Add support for 8 bone influences per vertex. This generalizes FbxSkinningAccess to be agnostic to vertex types and support any number of bone influences. RawModel and Raw2Gltf still operates on (multiple) Vec4f Vec4i types for per vertex weights and bone ids. A good second step would be to generalize RawModel as well, though AddAttributeToPrimitive, GetAttributeArray and the attribute pointer in AttributeDefinition complicates this.
This commit is contained in:
parent
395e376252
commit
a7b9f80e32
|
@ -144,7 +144,7 @@ int main(int argc, char* argv[]) {
|
|||
"-k,--keep-attribute",
|
||||
[&](std::vector<std::string> attributes) -> bool {
|
||||
gltfOptions.keepAttribs =
|
||||
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
|
||||
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0 | RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1;
|
||||
for (std::string attribute : attributes) {
|
||||
if (attribute == "position") {
|
||||
gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
||||
|
|
|
@ -69,6 +69,27 @@ static RawMaterialType GetMaterialType(
|
|||
return skinned ? RAW_MATERIAL_TYPE_SKINNED_OPAQUE : RAW_MATERIAL_TYPE_OPAQUE;
|
||||
}
|
||||
|
||||
static void calcMinMax(RawSurface& rawSurface, const FbxSkinningAccess& skinning, const FbxVector4& globalPosition, const Vec4i& indices, const Vec4f& weights) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (weights[i] > 0.0f) {
|
||||
const FbxVector4 localPosition =
|
||||
skinning.GetJointInverseGlobalTransforms(indices[i]).MultNormalize(globalPosition);
|
||||
|
||||
Vec3f& mins = rawSurface.jointGeometryMins[indices[i]];
|
||||
mins[0] = std::min(mins[0], (float)localPosition[0]);
|
||||
mins[1] = std::min(mins[1], (float)localPosition[1]);
|
||||
mins[2] = std::min(mins[2], (float)localPosition[2]);
|
||||
|
||||
Vec3f& maxs = rawSurface.jointGeometryMaxs[indices[i]];
|
||||
maxs[0] = std::max(maxs[0], (float)localPosition[0]);
|
||||
maxs[1] = std::max(maxs[1], (float)localPosition[1]);
|
||||
maxs[2] = std::max(maxs[2], (float)localPosition[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ReadMesh(
|
||||
RawModel& raw,
|
||||
FbxScene* pScene,
|
||||
|
@ -159,8 +180,15 @@ static void ReadMesh(
|
|||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_UV1);
|
||||
}
|
||||
if (skinning.IsSkinned()) {
|
||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS);
|
||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_INDICES);
|
||||
FBX_ASSERT(skinning.MaxWeights() <= 8); // output only supports up to 8
|
||||
|
||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0);
|
||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0);
|
||||
if (skinning.MaxWeights() > 4) {
|
||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1);
|
||||
raw.AddVertexAttribute(RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RawSurface& rawSurface = raw.GetSurface(rawSurfaceIndex);
|
||||
|
@ -342,8 +370,10 @@ static void ReadMesh(
|
|||
vertex.uv0[1] = (float)fbxUV0[1];
|
||||
vertex.uv1[0] = (float)fbxUV1[0];
|
||||
vertex.uv1[1] = (float)fbxUV1[1];
|
||||
vertex.jointIndices = skinning.GetVertexIndices(controlPointIndex);
|
||||
vertex.jointWeights = skinning.GetVertexWeights(controlPointIndex);
|
||||
vertex.jointIndices0 = skinning.GetVertexIndices(controlPointIndex, 0);
|
||||
vertex.jointWeights0 = skinning.GetVertexWeights(controlPointIndex, 0);
|
||||
vertex.jointIndices1 = skinning.GetVertexIndices(controlPointIndex, 1);
|
||||
vertex.jointWeights1 = skinning.GetVertexWeights(controlPointIndex, 1);
|
||||
vertex.polarityUv0 = false;
|
||||
|
||||
// flag this triangle as transparent if any of its corner vertices substantially deviates from
|
||||
|
@ -387,38 +417,15 @@ static void ReadMesh(
|
|||
}
|
||||
|
||||
if (skinning.IsSkinned()) {
|
||||
const int jointIndices[FbxSkinningAccess::MAX_WEIGHTS] = {vertex.jointIndices[0],
|
||||
vertex.jointIndices[1],
|
||||
vertex.jointIndices[2],
|
||||
vertex.jointIndices[3]};
|
||||
const float jointWeights[FbxSkinningAccess::MAX_WEIGHTS] = {vertex.jointWeights[0],
|
||||
vertex.jointWeights[1],
|
||||
vertex.jointWeights[2],
|
||||
vertex.jointWeights[3]};
|
||||
const FbxMatrix skinningMatrix =
|
||||
skinning.GetJointSkinningTransform(jointIndices[0]) * jointWeights[0] +
|
||||
skinning.GetJointSkinningTransform(jointIndices[1]) * jointWeights[1] +
|
||||
skinning.GetJointSkinningTransform(jointIndices[2]) * jointWeights[2] +
|
||||
skinning.GetJointSkinningTransform(jointIndices[3]) * jointWeights[3];
|
||||
|
||||
const FbxVector4 globalPosition = skinningMatrix.MultNormalize(fbxPosition);
|
||||
for (int i = 0; i < FbxSkinningAccess::MAX_WEIGHTS; i++) {
|
||||
if (jointWeights[i] > 0.0f) {
|
||||
const FbxVector4 localPosition =
|
||||
skinning.GetJointInverseGlobalTransforms(jointIndices[i])
|
||||
.MultNormalize(globalPosition);
|
||||
|
||||
Vec3f& mins = rawSurface.jointGeometryMins[jointIndices[i]];
|
||||
mins[0] = std::min(mins[0], (float)localPosition[0]);
|
||||
mins[1] = std::min(mins[1], (float)localPosition[1]);
|
||||
mins[2] = std::min(mins[2], (float)localPosition[2]);
|
||||
|
||||
Vec3f& maxs = rawSurface.jointGeometryMaxs[jointIndices[i]];
|
||||
maxs[0] = std::max(maxs[0], (float)localPosition[0]);
|
||||
maxs[1] = std::max(maxs[1], (float)localPosition[1]);
|
||||
maxs[2] = std::max(maxs[2], (float)localPosition[2]);
|
||||
}
|
||||
}
|
||||
FbxMatrix skinningMatrix = FbxMatrix() * 0.0;
|
||||
for (int j = 0; j < 4; j++)
|
||||
skinningMatrix += skinning.GetJointSkinningTransform(vertex.jointIndices0[j]) * vertex.jointWeights0[j];
|
||||
for (int j = 0; j < 4; j++)
|
||||
skinningMatrix += skinning.GetJointSkinningTransform(vertex.jointIndices1[j]) * vertex.jointWeights1[j];
|
||||
|
||||
const FbxVector4 globalPosition = skinningMatrix.MultNormalize(fbxPosition);
|
||||
calcMinMax(rawSurface, skinning, globalPosition, vertex.jointIndices0, vertex.jointWeights0);
|
||||
calcMinMax(rawSurface, skinning, globalPosition, vertex.jointIndices1, vertex.jointWeights1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, Fbx
|
|||
continue;
|
||||
}
|
||||
int controlPointCount = pMesh->GetControlPointsCount();
|
||||
vertexJointIndices.resize(controlPointCount, Vec4i(0, 0, 0, 0));
|
||||
vertexJointWeights.resize(controlPointCount, Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
vertexJointIndices.resize(controlPointCount);
|
||||
vertexJointWeights.resize(controlPointCount);
|
||||
|
||||
for (int clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) {
|
||||
FbxCluster* cluster = skin->GetCluster(clusterIndex);
|
||||
|
@ -55,12 +55,12 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, Fbx
|
|||
if (clusterIndices[i] < 0 || clusterIndices[i] >= controlPointCount) {
|
||||
continue;
|
||||
}
|
||||
if (clusterWeights[i] <= vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1]) {
|
||||
if (clusterWeights[i] <= 0.0 || vertexJointWeights[clusterIndices[i]].size() >= MAX_WEIGHTS) {
|
||||
continue;
|
||||
}
|
||||
vertexJointIndices[clusterIndices[i]][MAX_WEIGHTS - 1] = clusterIndex;
|
||||
vertexJointWeights[clusterIndices[i]][MAX_WEIGHTS - 1] = (float)clusterWeights[i];
|
||||
for (int j = MAX_WEIGHTS - 1; j > 0; j--) {
|
||||
vertexJointIndices[clusterIndices[i]].push_back(clusterIndex);
|
||||
vertexJointWeights[clusterIndices[i]].push_back((float)clusterWeights[i]);
|
||||
for (int j = vertexJointWeights[clusterIndices[i]].size() - 1; j > 0; j--) {
|
||||
if (vertexJointWeights[clusterIndices[i]][j - 1] >=
|
||||
vertexJointWeights[clusterIndices[i]][j]) {
|
||||
break;
|
||||
|
@ -75,8 +75,12 @@ FbxSkinningAccess::FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, Fbx
|
|||
}
|
||||
}
|
||||
for (int i = 0; i < controlPointCount; i++) {
|
||||
const float weightSumRcp = 1.0 / (vertexJointWeights[i][0] + vertexJointWeights[i][1] + vertexJointWeights[i][2] + vertexJointWeights[i][3]);
|
||||
vertexJointWeights[i] *= weightSumRcp;
|
||||
float weightSum = 0.0;
|
||||
for (int w = 0; w < vertexJointWeights[i].size(); ++w)
|
||||
weightSum += vertexJointWeights[i][w];
|
||||
float weightSumRcp = 1.0 / weightSum;
|
||||
for (int w = 0; w < vertexJointWeights[i].size(); ++w)
|
||||
vertexJointWeights[i][w] *= weightSumRcp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
class FbxSkinningAccess {
|
||||
public:
|
||||
static const int MAX_WEIGHTS = 4;
|
||||
static const int MAX_WEIGHTS = 8;
|
||||
|
||||
FbxSkinningAccess(const FbxMesh* pMesh, FbxScene* pScene, FbxNode* pNode);
|
||||
|
||||
|
@ -29,6 +29,10 @@ class FbxSkinningAccess {
|
|||
return (vertexJointWeights.size() > 0);
|
||||
}
|
||||
|
||||
int MaxWeights() const {
|
||||
return MAX_WEIGHTS;
|
||||
}
|
||||
|
||||
int GetNodeCount() const {
|
||||
return (int)jointNodes.size();
|
||||
}
|
||||
|
@ -58,15 +62,23 @@ class FbxSkinningAccess {
|
|||
return inverseBindMatrices[jointIndex];
|
||||
}
|
||||
|
||||
const Vec4i GetVertexIndices(const int controlPointIndex) const {
|
||||
return (!vertexJointIndices.empty()) ? vertexJointIndices[controlPointIndex]
|
||||
: Vec4i(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
const Vec4f GetVertexWeights(const int controlPointIndex) const {
|
||||
return (!vertexJointWeights.empty()) ? vertexJointWeights[controlPointIndex]
|
||||
: Vec4f(0, 0, 0, 0);
|
||||
}
|
||||
const Vec4i GetVertexIndices(const int controlPointIndex, const int subset) const {
|
||||
if (vertexJointIndices.empty())
|
||||
return Vec4i(0, 0, 0, 0);
|
||||
Vec4i indices(0, 0, 0, 0);
|
||||
for (int k = subset * 4; k < subset * 4 + 4 && k < vertexJointIndices[controlPointIndex].size(); k++)
|
||||
indices[k - subset * 4] = vertexJointIndices[controlPointIndex][k];
|
||||
return indices;
|
||||
}
|
||||
|
||||
const Vec4f GetVertexWeights(const int controlPointIndex, const int subset) const {
|
||||
if (vertexJointWeights.empty())
|
||||
return Vec4f(0.0f);
|
||||
Vec4f weights(0.0f);
|
||||
for (int k = subset * 4; k < subset * 4 + 4 && k < vertexJointWeights[controlPointIndex].size(); k++)
|
||||
weights[k - subset * 4] = vertexJointWeights[controlPointIndex][k];
|
||||
return weights;
|
||||
}
|
||||
|
||||
private:
|
||||
int rootIndex;
|
||||
|
@ -75,6 +87,6 @@ class FbxSkinningAccess {
|
|||
std::vector<FbxMatrix> jointSkinningTransforms;
|
||||
std::vector<FbxMatrix> jointInverseGlobalTransforms;
|
||||
std::vector<FbxAMatrix> inverseBindMatrices;
|
||||
std::vector<Vec4i> vertexJointIndices;
|
||||
std::vector<Vec4f> vertexJointWeights;
|
||||
std::vector<std::vector<uint16_t>> vertexJointIndices;
|
||||
std::vector<std::vector<float>> vertexJointWeights;
|
||||
};
|
||||
|
|
|
@ -532,24 +532,42 @@ ModelData* Raw2Gltf(
|
|||
draco::DT_FLOAT32);
|
||||
gltf->AddAttributeToPrimitive<Vec2f>(buffer, surfaceModel, *primitive, ATTR_TEXCOORD_1);
|
||||
}
|
||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) != 0) {
|
||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0) != 0) {
|
||||
const AttributeDefinition<Vec4i> ATTR_JOINTS(
|
||||
"JOINTS_0",
|
||||
&RawVertex::jointIndices,
|
||||
&RawVertex::jointIndices0,
|
||||
GLT_VEC4I,
|
||||
draco::GeometryAttribute::GENERIC,
|
||||
draco::DT_UINT16);
|
||||
gltf->AddAttributeToPrimitive<Vec4i>(buffer, surfaceModel, *primitive, ATTR_JOINTS);
|
||||
}
|
||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS) != 0) {
|
||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0) != 0) {
|
||||
const AttributeDefinition<Vec4f> ATTR_WEIGHTS(
|
||||
"WEIGHTS_0",
|
||||
&RawVertex::jointWeights,
|
||||
&RawVertex::jointWeights0,
|
||||
GLT_VEC4F,
|
||||
draco::GeometryAttribute::GENERIC,
|
||||
draco::DT_FLOAT32);
|
||||
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
|
||||
}
|
||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1) != 0) {
|
||||
const AttributeDefinition<Vec4i> ATTR_JOINTS(
|
||||
"JOINTS_1",
|
||||
&RawVertex::jointIndices1,
|
||||
GLT_VEC4I,
|
||||
draco::GeometryAttribute::GENERIC,
|
||||
draco::DT_UINT16);
|
||||
gltf->AddAttributeToPrimitive<Vec4i>(buffer, surfaceModel, *primitive, ATTR_JOINTS);
|
||||
}
|
||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1) != 0) {
|
||||
const AttributeDefinition<Vec4f> ATTR_WEIGHTS(
|
||||
"WEIGHTS_1",
|
||||
&RawVertex::jointWeights1,
|
||||
GLT_VEC4F,
|
||||
draco::GeometryAttribute::GENERIC,
|
||||
draco::DT_FLOAT32);
|
||||
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_WEIGHTS);
|
||||
}
|
||||
|
||||
// each channel present in the mesh always ends up a target in the primitive
|
||||
for (int channelIx = 0; channelIx < rawSurface.blendChannels.size(); channelIx++) {
|
||||
|
|
|
@ -26,8 +26,9 @@
|
|||
bool RawVertex::operator==(const RawVertex& other) const {
|
||||
return (position == other.position) && (normal == other.normal) && (tangent == other.tangent) &&
|
||||
(binormal == other.binormal) && (color == other.color) && (uv0 == other.uv0) &&
|
||||
(uv1 == other.uv1) && (jointIndices == other.jointIndices) &&
|
||||
(jointWeights == other.jointWeights) && (polarityUv0 == other.polarityUv0) &&
|
||||
(uv1 == other.uv1) && (jointIndices0 == other.jointIndices0) &&
|
||||
(jointWeights0 == other.jointWeights0) && (jointIndices1 == other.jointIndices1) &&
|
||||
(jointWeights1 == other.jointWeights1) && (polarityUv0 == other.polarityUv0) &&
|
||||
(blendSurfaceIx == other.blendSurfaceIx) && (blends == other.blends);
|
||||
}
|
||||
|
||||
|
@ -55,11 +56,17 @@ size_t RawVertex::Difference(const RawVertex& other) const {
|
|||
attributes |= RAW_VERTEX_ATTRIBUTE_UV1;
|
||||
}
|
||||
// Always need both or neither.
|
||||
if (jointIndices != other.jointIndices) {
|
||||
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
|
||||
}
|
||||
if (jointWeights != other.jointWeights) {
|
||||
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
|
||||
if (jointIndices0 != other.jointIndices0) {
|
||||
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0;
|
||||
}
|
||||
if (jointWeights0 != other.jointWeights0) {
|
||||
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0;
|
||||
}
|
||||
if (jointIndices1 != other.jointIndices1) {
|
||||
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1;
|
||||
}
|
||||
if (jointWeights1 != other.jointWeights1) {
|
||||
attributes |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1;
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
@ -573,7 +580,7 @@ void RawModel::CreateMaterialModels(
|
|||
if (keepAttribs != -1) {
|
||||
int keep = keepAttribs;
|
||||
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) {
|
||||
keep |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
|
||||
keep |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0 | RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1;
|
||||
}
|
||||
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_AUTO) != 0) {
|
||||
keep |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
||||
|
@ -614,11 +621,17 @@ void RawModel::CreateMaterialModels(
|
|||
if ((keep & RAW_VERTEX_ATTRIBUTE_UV1) == 0) {
|
||||
vertex.uv1 = defaultVertex.uv1;
|
||||
}
|
||||
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES) == 0) {
|
||||
vertex.jointIndices = defaultVertex.jointIndices;
|
||||
}
|
||||
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS) == 0) {
|
||||
vertex.jointWeights = defaultVertex.jointWeights;
|
||||
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0) == 0) {
|
||||
vertex.jointIndices0 = defaultVertex.jointIndices0;
|
||||
}
|
||||
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0) == 0) {
|
||||
vertex.jointWeights0 = defaultVertex.jointWeights0;
|
||||
}
|
||||
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1) == 0) {
|
||||
vertex.jointIndices1 = defaultVertex.jointIndices1;
|
||||
}
|
||||
if ((keep & RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1) == 0) {
|
||||
vertex.jointWeights1 = defaultVertex.jointWeights1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,10 @@ enum RawVertexAttribute {
|
|||
RAW_VERTEX_ATTRIBUTE_COLOR = 1 << 4,
|
||||
RAW_VERTEX_ATTRIBUTE_UV0 = 1 << 5,
|
||||
RAW_VERTEX_ATTRIBUTE_UV1 = 1 << 6,
|
||||
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES = 1 << 7,
|
||||
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS = 1 << 8,
|
||||
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES0 = 1 << 7,
|
||||
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS0 = 1 << 8,
|
||||
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES1 = 1 << 9,
|
||||
RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS1 = 1 << 10,
|
||||
|
||||
RAW_VERTEX_ATTRIBUTE_AUTO = 1 << 31
|
||||
};
|
||||
|
@ -49,8 +51,10 @@ struct RawVertex {
|
|||
Vec4f color{0.0f};
|
||||
Vec2f uv0{0.0f};
|
||||
Vec2f uv1{0.0f};
|
||||
Vec4i jointIndices{0, 0, 0, 0};
|
||||
Vec4f jointWeights{0.0f};
|
||||
Vec4i jointIndices0{0,0,0,0};
|
||||
Vec4i jointIndices1{0,0,0,0};
|
||||
Vec4f jointWeights0{0.0f};
|
||||
Vec4f jointWeights1{0.0f};
|
||||
// end of members that directly correspond to vertex attributes
|
||||
|
||||
// if this vertex participates in a blend shape setup, the surfaceIx of its dedicated mesh;
|
||||
|
|
Loading…
Reference in New Issue