/// <summary> /// Copy all mesh data - aligned to loops (thus no combination of like-vertices) /// </summary> internal void CopyMeshDataAlignedtoLoops( MVert[] verts, MLoop[] loops, MLoopTri[] loopTris, MLoopCol[] loopCols, List <MLoopUV[]> loopUVs ) { #if LEGACY Reallocate(loops.Length, loopTris.Length, loopUVs.Count, loopCols != null); // Normals need to be cast from short -> float from Blender var normalScale = 1f / 32767f; for (int i = 0; i < loops.Length; i++) { var co = verts[loops[i].v].co; var no = verts[loops[i].v].no; _vertices[i] = new InteropVector3(co[0], co[1], co[2]); _normals[i] = new InteropVector3( no[0] * normalScale, no[1] * normalScale, no[2] * normalScale ); // Copy UV layers - same length as loops for (int layer = 0; layer < loopUVs.Count; layer++) { _uvs[layer][i] = new InteropVector2( loopUVs[layer][i].uv ); } // Copy vertex colors - same length as loops if (loopCols != null) { var col = loopCols[i]; _colors[i] = new InteropColor32( col.r, col.g, col.b, col.a ); } } // Copy triangles for (uint t = 0; t < loopTris.Length; t++) { for (uint i = 0; i < 3; i++) { _triangles[(t * 3) + i] = loopTris[t].tri[i]; } } #endif }
/// <summary> /// Copy all mesh data from Blender in one go and optimize down as much as possible. /// </summary> /// <remarks> /// Reference: LuxCoreRender/LuxCore::Scene_DefineBlenderMesh /// for the logic dealing with split normals / UVs / etc. /// </remarks> /// <param name="verts"></param> /// <param name="loops"></param> /// <param name="loopTris"></param> /// <param name="loopUVs"></param> /// <param name="loopCols"></param> internal void CopyMeshData_V1( MVert[] verts, MLoop[] loops, MLoopTri[] loopTris, MLoopCol[] loopCols, List <MLoopUV[]> loopUVs ) { #if LEGACY // In the case of split vertices - this'll resize DOWN // and then resize UP again for split vertices. Reallocate(verts.Length, loopTris.Length, loopUVs.Count, loopCols != null); var normalScale = 1f / 32767f; // Copy in vertex coordinates and normals for (int i = 0; i < verts.Length; i++) { var co = verts[i].co; var no = verts[i].no; _vertices[i] = new InteropVector3(co[0], co[1], co[2]); // Normals need to be cast from short -> float from Blender _normals[i] = new InteropVector3( no[0] * normalScale, no[1] * normalScale, no[2] * normalScale ); } // Copy UV layers for (int layer = 0; layer < loopUVs.Count; layer++) { var uvLayer = _uvs[layer]; for (uint i = 0; i < loopUVs[layer].Length; i++) { var vertIndex = loops[i].v; // This will overwrite itself for shared vertices - that's fine. // We'll be handling split UVs when reading in triangle data. uvLayer[vertIndex] = new InteropVector2( loopUVs[layer][i].uv ); } } // Copy vertex colors if we got 'em if (loopCols != null) { for (uint i = 0; i < loopCols.Length; i++) { var vertIndex = loops[i].v; var col = loopCols[i]; _colors[vertIndex] = new InteropColor32( col.r, col.g, col.b, col.a ); } } // Track what triangle vertices need to be split. // This maps an index in `triangles` to an index in `loops` var splitTris = new Dictionary <uint, uint>(); // Generate triangle list while identifying any vertices that will need // to be split - due to having split UVs, normals, etc in the loop data. for (uint t = 0; t < loopTris.Length; t++) { for (uint i = 0; i < 3; i++) { var loopIndex = loopTris[t].tri[i]; var vertIndex = loops[loopIndex].v; var split = false; // Assumes .v is already < verts.Length // TODO: Test differing normals - not applicable // here as normals are only read in from MVert // Determine if we should make a new vertex for split UVs for (int layer = 0; layer < loopUVs.Count && !split; layer++) { var loopUV = loopUVs[layer][loopIndex].uv; var vertUV = _uvs[layer][vertIndex]; // TODO: Handle floating point errors? if (loopUV[0] != vertUV.x || loopUV[1] != vertUV.y) { split = true; } } // If we have vertex colors, check for split colors if (loopCols != null) { var col = loopCols[loopIndex]; var vertCol = _colors[vertIndex]; if (col.r != vertCol.r || col.g != vertCol.g || col.b != vertCol.b || col.a != vertCol.a ) { split = true; } } _triangles[(t * 3) + i] = vertIndex; // Track if we need to split the vertex in the triangle // to a new one once we've iterated through everything if (split) { splitTris.Add((t * 3) + i, loopIndex); } } } // 7958 + 32245 = 40203 // LOOPS are 31488 // 7958 * 3 = 23874 // 15744 loop triangles // 31488 vertex color indices // If we have triangle verts to split - apply all at once so there's // only a single re-allocation to our arrays. var totalNewVertices = splitTris.Count; if (totalNewVertices > 0) { InteropLogger.Debug($"Splitting {totalNewVertices} vertices"); var newVertIndex = (uint)verts.Length; // Reallocate everything to fit the new set of vertices Reallocate(verts.Length + totalNewVertices, loopTris.Length, loopUVs.Count, loopCols != null); // Generate new vertices with any split data (normals, UVs, colors, etc) foreach (var tri in splitTris.Keys) { var prevVertIndex = _triangles[tri]; // MVert index var loopIndex = splitTris[tri]; // MLoop index // Same coordinates as the original vertex _vertices[newVertIndex] = _vertices[prevVertIndex]; // TODO: If there were split normals, that'd be handled here. _normals[newVertIndex] = _normals[prevVertIndex]; // Read UVs from loops again to handle any split UVs for (int layer = 0; layer < loopUVs.Count; layer++) { var uv = loopUVs[layer][loopIndex].uv; _uvs[layer][newVertIndex] = new InteropVector2(uv); } // Same deal for vertex colors - copy from the loop if (loopCols != null) { var col = loopCols[loopIndex]; _colors[newVertIndex] = new InteropColor32( col.r, col.g, col.b, col.a ); } // And finally update the triangle to point to the new vertex _triangles[tri] = newVertIndex; newVertIndex++; } } #endif }