in src/raw/RawModel.cpp [476:641]
void RawModel::CreateMaterialModels(
std::vector<RawModel>& materialModels,
bool shortIndices,
const int keepAttribs,
const bool forceDiscrete) const {
// Sort all triangles based on material first, then surface, then first vertex index.
std::vector<RawTriangle> sortedTriangles;
bool invertedTransparencySort = true;
if (invertedTransparencySort) {
// Split the triangles into opaque and transparent triangles.
std::vector<RawTriangle> opaqueTriangles;
std::vector<RawTriangle> transparentTriangles;
for (const auto& triangle : triangles) {
const int materialIndex = triangle.materialIndex;
if (materialIndex < 0) {
opaqueTriangles.push_back(triangle);
continue;
}
const int textureIndex = materials[materialIndex].textures[RAW_TEXTURE_USAGE_DIFFUSE];
if (textureIndex < 0) {
if (vertices[triangle.verts[0]].color.w < 1.0f ||
vertices[triangle.verts[1]].color.w < 1.0f ||
vertices[triangle.verts[2]].color.w < 1.0f) {
transparentTriangles.push_back(triangle);
continue;
}
opaqueTriangles.push_back(triangle);
continue;
}
if (textures[textureIndex].occlusion == RAW_TEXTURE_OCCLUSION_TRANSPARENT) {
transparentTriangles.push_back(triangle);
} else {
opaqueTriangles.push_back(triangle);
}
}
// Sort the opaque triangles.
std::sort(opaqueTriangles.begin(), opaqueTriangles.end(), TriangleModelSortPos::Compare);
// Sort the transparent triangles in the reverse direction.
std::sort(
transparentTriangles.begin(), transparentTriangles.end(), TriangleModelSortNeg::Compare);
// Add the triangles to the sorted list.
for (const auto& opaqueTriangle : opaqueTriangles) {
sortedTriangles.push_back(opaqueTriangle);
}
for (const auto& transparentTriangle : transparentTriangles) {
sortedTriangles.push_back(transparentTriangle);
}
} else {
sortedTriangles = triangles;
std::sort(sortedTriangles.begin(), sortedTriangles.end(), TriangleModelSortPos::Compare);
}
// Overestimate the number of models that will be created to avoid massive reallocation.
int discreteCount = 0;
for (const auto& surface : surfaces) {
discreteCount += surface.discrete ? 1 : 0;
}
materialModels.clear();
materialModels.reserve(materials.size() + discreteCount);
const RawVertex defaultVertex;
// Create a separate model for each material.
RawModel* model;
for (size_t i = 0; i < sortedTriangles.size(); i++) {
if (sortedTriangles[i].materialIndex < 0 || sortedTriangles[i].surfaceIndex < 0) {
continue;
}
if (i == 0 || (shortIndices && model->GetVertexCount() >= 0xFFFE) ||
sortedTriangles[i].materialIndex != sortedTriangles[i - 1].materialIndex ||
(sortedTriangles[i].surfaceIndex != sortedTriangles[i - 1].surfaceIndex &&
(forceDiscrete || surfaces[sortedTriangles[i].surfaceIndex].discrete ||
surfaces[sortedTriangles[i - 1].surfaceIndex].discrete))) {
materialModels.resize(materialModels.size() + 1);
model = &materialModels[materialModels.size() - 1];
}
// FIXME: will have to unlink from the nodes, transform both surfaces into a
// common space, and reparent to a new node with appropriate transform.
const int prevSurfaceCount = model->GetSurfaceCount();
const int materialIndex = model->AddMaterial(materials[sortedTriangles[i].materialIndex]);
const int surfaceIndex = model->AddSurface(surfaces[sortedTriangles[i].surfaceIndex]);
RawSurface& rawSurface = model->GetSurface(surfaceIndex);
if (model->GetSurfaceCount() > prevSurfaceCount) {
const std::vector<long>& jointIds = surfaces[sortedTriangles[i].surfaceIndex].jointIds;
for (const auto& jointId : jointIds) {
const int nodeIndex = GetNodeById(jointId);
assert(nodeIndex != -1);
model->AddNode(GetNode(nodeIndex));
}
rawSurface.bounds.Clear();
}
int verts[3];
for (int j = 0; j < 3; j++) {
RawVertex vertex = vertices[sortedTriangles[i].verts[j]];
if (keepAttribs != -1) {
int keep = keepAttribs;
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) {
keep |= RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
}
if ((keepAttribs & RAW_VERTEX_ATTRIBUTE_AUTO) != 0) {
keep |= RAW_VERTEX_ATTRIBUTE_POSITION;
const RawMaterial& mat = model->GetMaterial(materialIndex);
if (mat.textures[RAW_TEXTURE_USAGE_DIFFUSE] != -1) {
keep |= RAW_VERTEX_ATTRIBUTE_UV0;
}
if (mat.textures[RAW_TEXTURE_USAGE_NORMAL] != -1) {
keep |= RAW_VERTEX_ATTRIBUTE_NORMAL | RAW_VERTEX_ATTRIBUTE_TANGENT |
RAW_VERTEX_ATTRIBUTE_BINORMAL | RAW_VERTEX_ATTRIBUTE_UV0;
}
if (mat.textures[RAW_TEXTURE_USAGE_SPECULAR] != -1) {
keep |= RAW_VERTEX_ATTRIBUTE_NORMAL | RAW_VERTEX_ATTRIBUTE_UV0;
}
if (mat.textures[RAW_TEXTURE_USAGE_EMISSIVE] != -1) {
keep |= RAW_VERTEX_ATTRIBUTE_UV1;
}
}
if ((keep & RAW_VERTEX_ATTRIBUTE_POSITION) == 0) {
vertex.position = defaultVertex.position;
}
if ((keep & RAW_VERTEX_ATTRIBUTE_NORMAL) == 0) {
vertex.normal = defaultVertex.normal;
}
if ((keep & RAW_VERTEX_ATTRIBUTE_TANGENT) == 0) {
vertex.tangent = defaultVertex.tangent;
}
if ((keep & RAW_VERTEX_ATTRIBUTE_BINORMAL) == 0) {
vertex.binormal = defaultVertex.binormal;
}
if ((keep & RAW_VERTEX_ATTRIBUTE_COLOR) == 0) {
vertex.color = defaultVertex.color;
}
if ((keep & RAW_VERTEX_ATTRIBUTE_UV0) == 0) {
vertex.uv0 = defaultVertex.uv0;
}
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;
}
}
verts[j] = model->AddVertex(vertex);
model->vertexAttributes |= vertex.Difference(defaultVertex);
rawSurface.bounds.AddPoint(vertex.position);
}
model->AddTriangle(verts[0], verts[1], verts[2], materialIndex, surfaceIndex);
}
}