public static unsafe int[] GenerateIndexBufferAEN(IndexBufferBinding indexBuffer, VertexBufferBinding vertexBuffer, CommandList commandList = null) { // More info at http://developer.download.nvidia.com/whitepapers/2010/PN-AEN-Triangles-Whitepaper.pdf // This implementation might need some performance improvements var triangleCount = indexBuffer.Count / 3; var newIndices = new int[triangleCount * 12]; var positionMapping = GenerateIndexMapping(vertexBuffer, commandList, "POSITION"); var dominantEdges = new Dictionary <EdgeKeyAEN, EdgeAEN>(); var dominantVertices = new Dictionary <int, int>(); var indexSize = indexBuffer.Is32Bit? 4: 2; fixed(byte *indexBufferStart = &indexBuffer.Buffer.GetDataSafe(commandList)[indexBuffer.Offset]) { var triangleIndices = stackalloc int[3]; var positionIndices = stackalloc int[3]; // Step 2: prepare initial data for (int i = 0; i < triangleCount; ++i) { var oldIndices = indexBufferStart + i * 3 * indexSize; if (indexSize == 2) { var oldIndicesShort = (short *)oldIndices; triangleIndices[0] = oldIndicesShort[0]; triangleIndices[1] = oldIndicesShort[1]; triangleIndices[2] = oldIndicesShort[2]; } else { var oldIndicesShort = (int *)oldIndices; triangleIndices[0] = oldIndicesShort[0]; triangleIndices[1] = oldIndicesShort[1]; triangleIndices[2] = oldIndicesShort[2]; } positionIndices[0] = positionMapping.Indices[triangleIndices[0]]; positionIndices[1] = positionMapping.Indices[triangleIndices[1]]; positionIndices[2] = positionMapping.Indices[triangleIndices[2]]; newIndices[i * 12 + 0] = triangleIndices[0]; newIndices[i * 12 + 1] = triangleIndices[1]; newIndices[i * 12 + 2] = triangleIndices[2]; newIndices[i * 12 + 3] = triangleIndices[0]; newIndices[i * 12 + 4] = triangleIndices[1]; newIndices[i * 12 + 5] = triangleIndices[1]; newIndices[i * 12 + 6] = triangleIndices[2]; newIndices[i * 12 + 7] = triangleIndices[2]; newIndices[i * 12 + 8] = triangleIndices[0]; newIndices[i * 12 + 9] = triangleIndices[0]; newIndices[i * 12 + 10] = triangleIndices[1]; newIndices[i * 12 + 11] = triangleIndices[2]; // Step 2b/2c: Build dominant vertex/edge list for (int j = 0; j < 3; ++j) { dominantVertices[positionIndices[j]] = triangleIndices[j]; var edge = new EdgeAEN( triangleIndices[((j + 0) % 3)], triangleIndices[((j + 1) % 3)], positionIndices[((j + 0) % 3)], positionIndices[((j + 1) % 3)]); dominantEdges[new EdgeKeyAEN(edge)] = edge; edge = edge.Reverse(); dominantEdges[new EdgeKeyAEN(edge)] = edge; } } // Step3: Find dominant vertex/edge for (int i = 0; i < triangleCount; ++i) { var oldIndices = indexBufferStart + i * 3 * indexSize; if (indexSize == 2) { var oldIndicesShort = (short *)oldIndices; triangleIndices[0] = oldIndicesShort[0]; triangleIndices[1] = oldIndicesShort[1]; triangleIndices[2] = oldIndicesShort[2]; } else { var oldIndicesShort = (int *)oldIndices; triangleIndices[0] = oldIndicesShort[0]; triangleIndices[1] = oldIndicesShort[1]; triangleIndices[2] = oldIndicesShort[2]; } positionIndices[0] = positionMapping.Indices[triangleIndices[0]]; positionIndices[1] = positionMapping.Indices[triangleIndices[1]]; positionIndices[2] = positionMapping.Indices[triangleIndices[2]]; for (int j = 0; j < 3; ++j) { // Dominant edge int vertexKey; if (dominantVertices.TryGetValue(positionIndices[j], out vertexKey)) { newIndices[i * 12 + 9 + j] = vertexKey; } // Dominant vertex EdgeAEN edge; var edgeKey = new EdgeKeyAEN(positionIndices[((j + 0) % 3)], positionIndices[((j + 1) % 3)]); if (dominantEdges.TryGetValue(edgeKey, out edge)) { newIndices[i * 12 + 3 + j * 2 + 0] = edge.Index0; newIndices[i * 12 + 3 + j * 2 + 1] = edge.Index1; } } } } return(newIndices); }
/// <summary> /// Generates the index buffer with dominant edge and vertex informations. /// Each triangle gets its indices expanded to 12 control points, with 0 to 2 being original triangle, /// 3 to 8 being dominant edges and 9 to 11 being dominant vertices. /// </summary> /// <param name="meshData">The mesh data.</param> public static unsafe void GenerateIndexBufferAEN(this MeshDrawData meshData) { // For now, require a MeshData with only one vertex buffer and one index buffer if (meshData.VertexBuffers.Length != 1 || meshData.IndexBuffer == null) { throw new NotImplementedException(); } // More info at http://developer.download.nvidia.com/whitepapers/2010/PN-AEN-Triangles-Whitepaper.pdf // This implementation might need some performance improvements var indexBuffer = meshData.IndexBuffer; var triangleCount = indexBuffer.Count / 3; var newIndices = new int[triangleCount * 12]; var positionMapping = GenerateIndexMapping(meshData.VertexBuffers[0], "POSITION"); var dominantEdges = new Dictionary <EdgeKeyAEN, EdgeAEN>(); var dominantVertices = new Dictionary <int, int>(); fixed(byte *indexBufferStart = &indexBuffer.Buffer.Value.Content[indexBuffer.Offset]) { var oldIndices = (int *)indexBufferStart; var triangleIndices = stackalloc int[3]; var positionIndices = stackalloc int[3]; // Step 2: prepare initial data for (int i = 0; i < triangleCount; ++i) { triangleIndices[0] = oldIndices[i * 3 + 0]; triangleIndices[1] = oldIndices[i * 3 + 1]; triangleIndices[2] = oldIndices[i * 3 + 2]; positionIndices[0] = positionMapping.Indices[triangleIndices[0]]; positionIndices[1] = positionMapping.Indices[triangleIndices[1]]; positionIndices[2] = positionMapping.Indices[triangleIndices[2]]; newIndices[i * 12 + 0] = triangleIndices[0]; newIndices[i * 12 + 1] = triangleIndices[1]; newIndices[i * 12 + 2] = triangleIndices[2]; newIndices[i * 12 + 3] = triangleIndices[0]; newIndices[i * 12 + 4] = triangleIndices[1]; newIndices[i * 12 + 5] = triangleIndices[1]; newIndices[i * 12 + 6] = triangleIndices[2]; newIndices[i * 12 + 7] = triangleIndices[2]; newIndices[i * 12 + 8] = triangleIndices[0]; newIndices[i * 12 + 9] = triangleIndices[0]; newIndices[i * 12 + 10] = triangleIndices[1]; newIndices[i * 12 + 11] = triangleIndices[2]; // Step 2b/2c: Build dominant vertex/edge list for (int j = 0; j < 3; ++j) { dominantVertices[positionIndices[j]] = triangleIndices[j]; var edge = new EdgeAEN( triangleIndices[((j + 0) % 3)], triangleIndices[((j + 1) % 3)], positionIndices[((j + 0) % 3)], positionIndices[((j + 1) % 3)]); dominantEdges[new EdgeKeyAEN(edge)] = edge; edge = edge.Reverse(); dominantEdges[new EdgeKeyAEN(edge)] = edge; } } // Step3: Find dominant vertex/edge for (int i = 0; i < triangleCount; ++i) { triangleIndices[0] = oldIndices[i * 3 + 0]; triangleIndices[1] = oldIndices[i * 3 + 1]; triangleIndices[2] = oldIndices[i * 3 + 2]; positionIndices[0] = positionMapping.Indices[triangleIndices[0]]; positionIndices[1] = positionMapping.Indices[triangleIndices[1]]; positionIndices[2] = positionMapping.Indices[triangleIndices[2]]; for (int j = 0; j < 3; ++j) { // Dominant edge int vertexKey; if (dominantVertices.TryGetValue(positionIndices[j], out vertexKey)) { newIndices[i * 12 + 9 + j] = vertexKey; } // Dominant vertex EdgeAEN edge; var edgeKey = new EdgeKeyAEN(positionIndices[((j + 0) % 3)], positionIndices[((j + 1) % 3)]); if (dominantEdges.TryGetValue(edgeKey, out edge)) { newIndices[i * 12 + 3 + j * 2 + 0] = edge.Index0; newIndices[i * 12 + 3 + j * 2 + 1] = edge.Index1; } } } } // Generate index buffer var indexBufferData = new byte[triangleCount * 12 * Utilities.SizeOf <int>()]; fixed(int *indexDataStart = &newIndices[0]) fixed(byte *indexBufferDataStart = &indexBufferData[0]) { Utilities.CopyMemory((IntPtr)indexBufferDataStart, (IntPtr)indexDataStart, indexBufferData.Length); meshData.IndexBuffer = new IndexBufferBindingData(new BufferData(BufferFlags.IndexBuffer, indexBufferData), true, triangleCount * 12); } meshData.DrawCount = triangleCount * 12; meshData.PrimitiveType = PrimitiveType.PatchList.ControlPointCount(12); }