Skip to content

Commit

Permalink
Inver Y-axis to match SpeedTree CAD. Export vertex colors, leaf cente…
Browse files Browse the repository at this point in the history
…rs, dimming, pivot and size.
  • Loading branch information
Vladislav Skachkov authored and Vladislav Skachkov committed Jun 1, 2020
1 parent 8e50de9 commit a85e8ac
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 62 deletions.
206 changes: 146 additions & 60 deletions SPT/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,38 @@ struct TreeStorage
int Lod;
};

inline FbxVector4 CPos(double x, double y, double z)
{
return FbxVector4(x, -y, z);
}

inline FbxVector4 CNorm(double x, double y, double z)
{
return FbxVector4(x, -y, z);
}

inline FbxVector4 CBiNorm(double x, double y, double z)
{
return FbxVector4(x, -y, z);
}

inline FbxVector4 CTang(double x, double y, double z)
{
return FbxVector4(x, -y, z);
}


bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)
{
// SIndexed geometry contains vertices for all LODs.
// We need to keep vertices of the current LOD only.
int totalVerticesCount = 0;
std::vector<int> uniqueBranchIndices;
std::vector<int> uniqueFrondIndices;
{
CSpeedTreeRT::SGeometry geometry;
tree->GetGeometry(geometry);


CSpeedTreeRT::SGeometry geometry;
tree->GetGeometry(geometry);
{
if (geometry.m_sBranches.m_nNumLods > o.Lod && geometry.m_sBranches.m_pNumStrips)
{
CSpeedTreeRT::SGeometry::SIndexed const *s = &geometry.m_sBranches;
Expand Down Expand Up @@ -102,9 +122,6 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)

// Begin to build the mesh

CSpeedTreeRT::SGeometry geometry;
tree->GetGeometry(geometry);

o.Mesh->InitControlPoints(totalVerticesCount);
FbxVector4 *controlPoints = o.Mesh->GetControlPoints();
int offset = 0;
Expand Down Expand Up @@ -135,52 +152,72 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)
int pos = 1;
while (pos)
{
const char mType = uData[pos];
const char mType = uData[pos]; pos++;
if (!mType || (mType != 'b' && mType != 'f' && mType != 'l'))
{
break;
}
pos++;
int length = uData[pos];
pos++;
char *nameRaw = (char *)malloc(length + 1);
memcpy(nameRaw, &uData[pos], length);
nameRaw[length] = '\0';
std::string name(nameRaw);
pos += length;
FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, name.c_str());
int length = uData[pos]; pos++;
char *name = (char *)malloc(length + 1);
memcpy(name, &uData[pos], length);
name[length] = '\0'; pos += length;
switch (mType)
{
case 'b':
branchMatIdx = o.MeshNode->GetMaterialCount();
{
std::string finalName = std::string(name) + "_branches";
FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, finalName.c_str());
branchMatIdx = o.MeshNode->AddMaterial(m);
break;
}
case 'f':
frondMatIdx = o.MeshNode->GetMaterialCount();
{
std::string finalName = std::string(name) + "_fronds";
FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, finalName.c_str());
frondMatIdx = o.MeshNode->AddMaterial(m);
break;
}
case 'l':
leafMatIdx = o.MeshNode->GetMaterialCount();
{
std::string finalName = std::string(name) + "_leafs";
FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, finalName.c_str());
leafMatIdx = o.MeshNode->AddMaterial(m);
break;
}
default:
break;
}
o.MeshNode->AddMaterial(m);
free(nameRaw);
free(name);
}
}

FbxLayerElementUV *uvDiffuseLayer = FbxLayerElementUV::Create(o.Mesh, "DiffuseUV");
FbxLayerElementUV *uvCustom1 = FbxLayerElementUV::Create(o.Mesh, "SizeXY");
FbxLayerElementUV *uvCustom2 = FbxLayerElementUV::Create(o.Mesh, "CenterXY");
FbxLayerElementUV *uvCustom3 = FbxLayerElementUV::Create(o.Mesh, "CenterZDimming");
FbxLayerElementUV *uvCustom4 = FbxLayerElementUV::Create(o.Mesh, "PivotXY");
FbxLayerElementNormal *layerElementNormal = FbxLayerElementNormal::Create(o.Mesh, "");
FbxLayerElementBinormal *layerElementBinormal = FbxLayerElementBinormal::Create(o.Mesh, "");
FbxLayerElementTangent *layerElementTangent = FbxLayerElementTangent::Create(o.Mesh, "");
FbxLayerElementVertexColor *layerElementColor = FbxLayerElementVertexColor::Create(o.Mesh, "");
uvDiffuseLayer->SetMappingMode(FbxLayerElement::eByControlPoint);
uvDiffuseLayer->SetReferenceMode(FbxLayerElement::eDirect);
uvCustom1->SetMappingMode(FbxLayerElement::eByControlPoint);
uvCustom1->SetReferenceMode(FbxLayerElement::eDirect);
uvCustom2->SetMappingMode(FbxLayerElement::eByControlPoint);
uvCustom2->SetReferenceMode(FbxLayerElement::eDirect);
uvCustom3->SetMappingMode(FbxLayerElement::eByControlPoint);
uvCustom3->SetReferenceMode(FbxLayerElement::eDirect);
uvCustom4->SetMappingMode(FbxLayerElement::eByControlPoint);
uvCustom4->SetReferenceMode(FbxLayerElement::eDirect);
layerElementNormal->SetMappingMode(FbxLayerElement::eByControlPoint);
layerElementNormal->SetReferenceMode(FbxLayerElement::eDirect);
layerElementBinormal->SetMappingMode(FbxLayerElement::eByControlPoint);
layerElementBinormal->SetReferenceMode(FbxLayerElement::eDirect);
layerElementTangent->SetMappingMode(FbxLayerElement::eByControlPoint);
layerElementTangent->SetReferenceMode(FbxLayerElement::eDirect);

layerElementColor->SetMappingMode(FbxLayerElement::eByControlPoint);
layerElementColor->SetReferenceMode(FbxLayerElement::eDirect);

// Building branches

Expand All @@ -196,31 +233,43 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)
const float *binorm = &s->m_pBinormals[idx * 3];
const float *tangent = &s->m_pTangents[idx * 3];
const float *uvs = &s->m_pTexCoords[CSpeedTreeRT::TL_DIFFUSE][idx * 2];
controlPoints[offset + i] = FbxVector4(pos[0], pos[1], pos[2]);
layerElementNormal->GetDirectArray().Add(FbxVector4(normal[0], normal[1], normal[2]));
layerElementBinormal->GetDirectArray().Add(FbxVector4(binorm[0], binorm[1], binorm[2]));
layerElementTangent->GetDirectArray().Add(FbxVector4(tangent[0], tangent[1], tangent[2]));
controlPoints[offset + i] = CPos(pos[0], pos[1], pos[2]);
layerElementNormal->GetDirectArray().Add(CNorm(normal[0], normal[1], normal[2]));
layerElementBinormal->GetDirectArray().Add(CBiNorm(binorm[0], binorm[1], binorm[2]));
layerElementTangent->GetDirectArray().Add(CTang(tangent[0], tangent[1], tangent[2]));
uvDiffuseLayer->GetDirectArray().Add(FbxVector2(uvs[0], uvs[1]));
uvCustom1->GetDirectArray().Add(FbxVector2(0, 0));
uvCustom2->GetDirectArray().Add(FbxVector2(0, 0));
uvCustom3->GetDirectArray().Add(FbxVector2(0, 0));
uvCustom4->GetDirectArray().Add(FbxVector2(0, 0));
if (s->m_pColors)
{
unsigned char *colors = (unsigned char *)&s->m_pColors[idx];
layerElementColor->GetDirectArray().Add(FbxColor((float)colors[0] / 255., (float)colors[1] / 255., (float)colors[2] / 255., (float)colors[3] / 255.));
}
else
{
layerElementColor->GetDirectArray().Add(FbxColor(0,0,0));
}
}

if (branchMatIdx == -1)
{
FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, "BranchMAT");
branchMatIdx = o.MeshNode->GetMaterialCount();
o.MeshNode->AddMaterial(m);
branchMatIdx = o.MeshNode->AddMaterial(m);
}

for(int strip = 0; strip < s->m_pNumStrips[o.Lod]; ++strip)
{
const int length = s->m_pStripLengths[o.Lod][strip];
const int *indices = s->m_pStrips[o.Lod][strip];

for(int i = 0; i < length - 2; ++i)
for(int i = 0; i < length - 3; ++i)
{
int polygon[3] = {indices[i], indices[i+1], indices[i+2]};
if(i % 2)
if (i % 2 == 0)
{
std::swap(polygon[2], polygon[1]);
std::swap(polygon[0], polygon[1]);
}

o.Mesh->BeginPolygon(branchMatIdx, -1, group);
Expand Down Expand Up @@ -248,18 +297,30 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)
const float *binorm = &s->m_pBinormals[idx * 3];
const float *tangent = &s->m_pTangents[idx * 3];
const float *uvs = &s->m_pTexCoords[CSpeedTreeRT::TL_DIFFUSE][idx * 2];
controlPoints[offset + i] = FbxVector4(pos[0], pos[1], pos[2]);
layerElementNormal->GetDirectArray().Add(FbxVector4(normal[0], normal[1], normal[2]));
layerElementBinormal->GetDirectArray().Add(FbxVector4(binorm[0], binorm[1], binorm[2]));
layerElementTangent->GetDirectArray().Add(FbxVector4(tangent[0], tangent[1], tangent[2]));
controlPoints[offset + i] = CPos(pos[0], pos[1], pos[2]);
layerElementNormal->GetDirectArray().Add(CNorm(normal[0], normal[1], normal[2]));
layerElementBinormal->GetDirectArray().Add(CBiNorm(binorm[0], binorm[1], binorm[2]));
layerElementTangent->GetDirectArray().Add(CTang(tangent[0], tangent[1], tangent[2]));
uvDiffuseLayer->GetDirectArray().Add(FbxVector2(uvs[0], uvs[1]));
uvCustom1->GetDirectArray().Add(FbxVector2(0, 0));
uvCustom2->GetDirectArray().Add(FbxVector2(0, 0));
uvCustom3->GetDirectArray().Add(FbxVector2(0, 0));
uvCustom4->GetDirectArray().Add(FbxVector2(0, 0));
if (s->m_pColors)
{
unsigned char *colors = (unsigned char *)&s->m_pColors[idx];
layerElementColor->GetDirectArray().Add(FbxColor((float)colors[0] / 255., (float)colors[1] / 255., (float)colors[2] / 255., (float)colors[3] / 255.));
}
else
{
layerElementColor->GetDirectArray().Add(FbxColor(0,0,0));
}
}

if (frondMatIdx == -1)
{
FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, "FrondMAT");
frondMatIdx = o.MeshNode->GetMaterialCount();
o.MeshNode->AddMaterial(m);
frondMatIdx = o.MeshNode->AddMaterial(m);
}

for(int strip = 0; strip < s->m_pNumStrips[o.Lod]; ++strip)
Expand All @@ -270,11 +331,10 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)
for(int i = 0; i < length - 2; ++i)
{
int polygon[3] = {indices[i], indices[i+1], indices[i+2]};
if(i % 2)
if (i % 2 == 0)
{
std::swap(polygon[2], polygon[1]);
std::swap(polygon[0], polygon[1]);
}

o.Mesh->BeginPolygon(frondMatIdx, -1, group);
for (int j = 0; j < 3; ++j)
{
Expand All @@ -289,7 +349,6 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)

// Building leaf cards

bool usesCardLeafs = false;
if (tree->GetNumLeafLodLevels() > o.Lod)
{
bool secondaryIndexForMesh = false;
Expand All @@ -299,17 +358,18 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)
if (leafCount && leafMatIdx == -1)
{
FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, "LeafMAT");
leafMatIdx = o.MeshNode->GetMaterialCount();
o.MeshNode->AddMaterial(m);
leafMatIdx = o.MeshNode->AddMaterial(m);
}
int processedLeafs = 0;
for (int leaf = 0; leaf < leafCount; ++leaf)
{
const CSpeedTreeRT::SGeometry::SLeaf::SCard *card = &s->m_pCards[s->m_pLeafCardIndices[leaf]];
const float *center = &s->m_pCenterCoords[leaf * 3];
float pivot[2];
pivot[0] = (card->m_pTexCoords[0 * 2] + card->m_pTexCoords[2 * 2]) / 2.;
pivot[1] = (card->m_pTexCoords[0 * 2 + 1] + card->m_pTexCoords[2 * 2 + 1]) / 2.;
if (!card->m_pMesh)
{
usesCardLeafs = true;
int cornerIndicies[] = {0,0,0,0};
for (int corner = 0; corner < 4; ++corner)
{
Expand All @@ -318,11 +378,26 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)
const float *binorm = &s->m_pBinormals[12 * leaf + (corner * 3)];
const float *tangent = &s->m_pTangents[12 * leaf + (corner * 3)];
const float *uvs = &card->m_pTexCoords[corner * 2];
controlPoints[offset + (processedLeafs * 4 + corner)] = FbxVector4(pos[0] + center[0], pos[1] + center[1], pos[2] + center[2]);
layerElementNormal->GetDirectArray().Add(FbxVector4(normal[0], normal[1], normal[2]));
layerElementBinormal->GetDirectArray().Add(FbxVector4(binorm[0], binorm[1], binorm[2]));
layerElementTangent->GetDirectArray().Add(FbxVector4(tangent[0], tangent[1], tangent[2]));
controlPoints[offset + (processedLeafs * 4 + corner)] = CPos(pos[0] + center[0], pos[1] + center[1], pos[2] + center[2]);
layerElementNormal->GetDirectArray().Add(CNorm(normal[0], normal[1], normal[2]));
layerElementBinormal->GetDirectArray().Add(CBiNorm(binorm[0], binorm[1], binorm[2]));
layerElementTangent->GetDirectArray().Add(CTang(tangent[0], tangent[1], tangent[2]));
uvDiffuseLayer->GetDirectArray().Add(FbxVector2(uvs[0], uvs[1]));
uvCustom1->GetDirectArray().Add(FbxVector2(card->m_fWidth, card->m_fHeight));
uvCustom2->GetDirectArray().Add(FbxVector2(center[0], -center[1]));
uvCustom3->GetDirectArray().Add(FbxVector2(center[2], s->m_pDimming[leaf]));
uvCustom4->GetDirectArray().Add(FbxVector2(pivot[0], pivot[1]));

if (s->m_pColors)
{
unsigned char *colors = (unsigned char *)&s->m_pColors[leaf * 4 + corner];
layerElementColor->GetDirectArray().Add(FbxColor((float)colors[0] / 255., (float)colors[1] / 255., (float)colors[2] / 255., (float)colors[3] / 255.));
}
else
{
layerElementColor->GetDirectArray().Add(FbxColor(0,0,0));
}

cornerIndicies[corner] = offset + (processedLeafs * 4 + corner);
}

Expand Down Expand Up @@ -353,27 +428,26 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)
if (leafCount && leafMatIdx == -1)
{
FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, "LeafMAT");
leafMatIdx = o.MeshNode->GetMaterialCount();
o.MeshNode->AddMaterial(m);
leafMatIdx = o.MeshNode->AddMaterial(m);
}

for (int leaf = 0; leaf < leafCount; ++leaf)
{
const CSpeedTreeRT::SGeometry::SLeaf::SCard *card = &s->m_pCards[s->m_pLeafCardIndices[leaf]];
const float *center = &s->m_pCenterCoords[leaf * 3];
const float *pivot = card->m_afPivotPoint;
if (card->m_pMesh)
{
if (usesCardLeafs && leafMatIdx2 == -1)
if (leafMatIdx2 == -1)
{
const char *leafMatName = o.MeshNode->GetMaterial(leafMatIdx)->GetName();
std::string newMatName("LeafMeshMAT");
if (leafMatName && leafMatName != "LeafMAT")
{
newMatName = std::string(leafMatName) + "_lMesh";
newMatName = std::string(leafMatName) + "mesh";
}
FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, newMatName.c_str());
leafMatIdx2 = o.MeshNode->GetMaterialCount();
o.MeshNode->AddMaterial(m);
leafMatIdx2 = o.MeshNode->AddMaterial(m);
}
else if (leafMatIdx2 == -1)
{
Expand All @@ -387,18 +461,24 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)
const float *binorm = &mesh->m_pBinormals[vert * 3];
const float *tangent = &mesh->m_pTangents[vert * 3];
const float *uvs = &mesh->m_pTexCoords[vert * 2];
controlPoints[offset + vert] = FbxVector4(pos[0] + center[0], pos[1] + center[1], pos[2] + center[2]);
layerElementNormal->GetDirectArray().Add(FbxVector4(normal[0], normal[1], normal[2]));
layerElementBinormal->GetDirectArray().Add(FbxVector4(binorm[0], binorm[1], binorm[2]));
layerElementTangent->GetDirectArray().Add(FbxVector4(tangent[0], tangent[1], tangent[2]));
controlPoints[offset + vert] = CPos(pos[0] + center[0], pos[1] + center[1], pos[2] + center[2]);
layerElementNormal->GetDirectArray().Add(CNorm(normal[0], normal[1], normal[2]));
layerElementBinormal->GetDirectArray().Add(CBiNorm(binorm[0], binorm[1], binorm[2]));
layerElementTangent->GetDirectArray().Add(CTang(tangent[0], tangent[1], tangent[2]));
layerElementColor->GetDirectArray().Add(FbxColor(0,0,0));
uvDiffuseLayer->GetDirectArray().Add(FbxVector2(uvs[0], uvs[1]));
uvCustom1->GetDirectArray().Add(FbxVector2(card->m_fWidth, card->m_fHeight));
uvCustom2->GetDirectArray().Add(FbxVector2(center[0], center[1]));
uvCustom3->GetDirectArray().Add(FbxVector2(center[2], s->m_pDimming[leaf]));
uvCustom4->GetDirectArray().Add(FbxVector2(pivot[0], pivot[1]));
}
for (int i = 0; i < mesh->m_nNumIndices - 2; i+=3)
{
int polygon[3] = {mesh->m_pIndices[i+1], mesh->m_pIndices[i], mesh->m_pIndices[i+2]};
o.Mesh->BeginPolygon(leafMatIdx2, -1, group);
for (int j = 0; j < 3; ++j)
{
o.Mesh->AddPolygon(offset + mesh->m_pIndices[i + j]);
o.Mesh->AddPolygon(offset + polygon[j]);
}
o.Mesh->EndPolygon();
}
Expand All @@ -411,7 +491,13 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o)
layer->SetNormals(layerElementNormal);
layer->SetBinormals(layerElementBinormal);
layer->SetTangents(layerElementTangent);
layer->SetVertexColors(layerElementColor);
layer->SetUVs(uvDiffuseLayer, FbxLayerElement::eTextureDiffuse);
layer->SetUVs(uvCustom1, FbxLayerElement::eTextureEmissive); // cardWidth, cardHeight
layer->SetUVs(uvCustom2, FbxLayerElement::eTextureAmbient); // leafPositionX, leafPositionY
layer->SetUVs(uvCustom3, FbxLayerElement::eTextureSpecular); // leafPositionZ, leafDimming
layer->SetUVs(uvCustom4, FbxLayerElement::eTextureNormalMap); // cardPivotU, cardPivotV

return true;
}

Expand Down
Loading

0 comments on commit a85e8ac

Please sign in to comment.