/// <summary> /// Internal method evaluates all collapse costs from this vertex and picks the lowest for a single buffer /// </summary> private float ComputeEdgeCostAtVertexForBuffer(PMWorkingData workingData, uint vertIndex) { // compute the edge collapse cost for all edges that start // from vertex v. Since we are only interested in reducing // the object by selecting the min cost edge at each step, we // only cache the cost of the least cost edge at this vertex // (in member variable collapse) as well as the value of the // cost (in member variable objdist). var v = workingData.vertList[(int)vertIndex]; if (v.neighbors.Count == 0) { // v doesn't have neighbors so nothing to collapse v.NotifyRemoved(); return(v.collapseCost); } // Init metrics v.collapseCost = float.MaxValue; v.collapseTo = null; // search all neighboring edges for "least cost" edge foreach (var neighbor in v.neighbors) { var cost = ComputeEdgeCollapseCost(v, neighbor); if ((v.collapseTo == null) || cost < v.collapseCost) { v.collapseTo = neighbor; // candidate for edge collapse v.collapseCost = cost; // cost of the collapse } } return(v.collapseCost); }
/// <summary> /// Internal method builds an new LOD based on the current state /// </summary> /// <param name="indexData">Index data which will have an index buffer created and initialized</param> void BakeNewLOD(IndexData indexData) { Debug.Assert(currNumIndexes > 0, "No triangles to bake!"); // Zip through the tri list of any working data copy and bake indexData.indexCount = (int)currNumIndexes; indexData.indexStart = 0; // Base size of indexes on original bool use32bitindexes = (this.indexData.indexBuffer.Type == IndexType.Size32); // Create index buffer, we don't need to read it back or modify it a lot indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer(this.indexData.indexBuffer.Type, indexData.indexCount, BufferUsage.StaticWriteOnly, false); IntPtr bufPtr = indexData.indexBuffer.Lock(BufferLocking.Discard); unsafe { ushort *pShort = null; uint * pInt = null; if (use32bitindexes) { pInt = (uint *)bufPtr.ToPointer(); } else { pShort = (ushort *)bufPtr.ToPointer(); } // Use the first working data buffer, they are all the same index-wise PMWorkingData work = this.workingDataList[0]; foreach (PMTriangle tri in work.triList) { if (!tri.removed) { if (use32bitindexes) { *pInt++ = tri.vertex[0].realIndex; *pInt++ = tri.vertex[1].realIndex; *pInt++ = tri.vertex[2].realIndex; } else { *pShort++ = (ushort)tri.vertex[0].realIndex; *pShort++ = (ushort)tri.vertex[1].realIndex; *pShort++ = (ushort)tri.vertex[2].realIndex; } } } } indexData.indexBuffer.Unlock(); }
/// <summary> /// Internal method for building PMWorkingData from geometry data /// </summary> private void AddWorkingData(VertexData vertexData, IndexData indexData) { // Insert blank working data, then fill var work = new PMWorkingData(); this.workingDataList.Add(work); // Build vertex list // Resize face list (this will always be this big) work.faceVertList = new PMFaceVertex[vertexData.vertexCount]; // Also resize common vert list to max, to avoid reallocations work.vertList = new PMVertex[vertexData.vertexCount]; // locate position element & the buffer to go with it var posElem = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); var vbuf = vertexData.vertexBufferBinding.GetBuffer(posElem.Source); // lock the buffer for reading var bufPtr = vbuf.Lock(BufferLocking.ReadOnly); uint numCommon = 0; #if !AXIOM_SAFE_ONLY unsafe #endif { var pVertex = bufPtr; Vector3 pos; // Map for identifying duplicate position vertices var commonVertexMap = new Dictionary <Vector3, uint>(); for (uint i = 0; i < vertexData.vertexCount; ++i, pVertex += vbuf.VertexSize) { var pFloat = (pVertex + posElem.Offset).ToFloatPointer(); pos.x = pFloat[0]; pos.y = pFloat[1]; pos.z = pFloat[2]; work.faceVertList[(int)i] = new PMFaceVertex(); // Try to find this position in the existing map if (!commonVertexMap.ContainsKey(pos)) { // Doesn't exist, so create it var commonVert = new PMVertex(); commonVert.SetDetails(pos, numCommon); commonVert.removed = false; commonVert.toBeRemoved = false; commonVert.seam = false; // Add it to our working set work.vertList[(int)numCommon] = commonVert; // Enter it in the map commonVertexMap.Add(pos, numCommon); // Increment common index ++numCommon; work.faceVertList[(int)i].commonVertex = commonVert; work.faceVertList[(int)i].realIndex = i; } else { // Exists already, reference it var existingVert = work.vertList[(int)commonVertexMap[pos]]; work.faceVertList[(int)i].commonVertex = existingVert; work.faceVertList[(int)i].realIndex = i; // Also tag original as a seam since duplicates at this location work.faceVertList[(int)i].commonVertex.seam = true; } } } vbuf.Unlock(); this.numCommonVertices = numCommon; // Build tri list var numTris = (uint)indexData.indexCount / 3; var ibuf = indexData.indexBuffer; var use32bitindexes = (ibuf.Type == IndexType.Size32); var indexBufferPtr = ibuf.Lock(BufferLocking.ReadOnly); #if !AXIOM_SAFE_ONLY unsafe #endif { var pInt = indexBufferPtr.ToUIntPointer(); var pShort = indexBufferPtr.ToUShortPointer(); var idx = 0; work.triList = new PMTriangle[(int)numTris]; // assumed tri list for (uint i = 0; i < numTris; ++i) { // use 32-bit index always since we're not storing var vindex = use32bitindexes ? pInt[idx++] : pShort[idx++]; var v0 = work.faceVertList[(int)vindex]; vindex = use32bitindexes ? pInt[idx++] : pShort[idx++]; var v1 = work.faceVertList[(int)vindex]; vindex = use32bitindexes ? pInt[idx++] : pShort[idx++]; var v2 = work.faceVertList[(int)vindex]; work.triList[(int)i] = new PMTriangle(); work.triList[(int)i].SetDetails(i, v0, v1, v2); work.triList[(int)i].removed = false; } } ibuf.Unlock(); }
/// <summary> /// Internal method evaluates all collapse costs from this vertex and picks the lowest for a single buffer /// </summary> float ComputeEdgeCostAtVertexForBuffer(PMWorkingData workingData, uint vertIndex) { // compute the edge collapse cost for all edges that start // from vertex v. Since we are only interested in reducing // the object by selecting the min cost edge at each step, we // only cache the cost of the least cost edge at this vertex // (in member variable collapse) as well as the value of the // cost (in member variable objdist). PMVertex v = workingData.vertList[(int)vertIndex]; if (v.neighbors.Count == 0) { // v doesn't have neighbors so nothing to collapse v.NotifyRemoved(); return v.collapseCost; } // Init metrics v.collapseCost = float.MaxValue; v.collapseTo = null; // search all neighboring edges for "least cost" edge foreach (PMVertex neighbor in v.neighbors) { float cost = ComputeEdgeCollapseCost(v, neighbor); if ((v.collapseTo == null) || cost < v.collapseCost) { v.collapseTo = neighbor; // candidate for edge collapse v.collapseCost = cost; // cost of the collapse } } return v.collapseCost; }
/// <summary> /// Internal method for building PMWorkingData from geometry data /// </summary> void AddWorkingData(VertexData vertexData, IndexData indexData) { // Insert blank working data, then fill PMWorkingData work = new PMWorkingData(); this.workingDataList.Add(work); // Build vertex list // Resize face list (this will always be this big) work.faceVertList = new PMFaceVertex[vertexData.vertexCount]; // Also resize common vert list to max, to avoid reallocations work.vertList = new PMVertex[vertexData.vertexCount]; // locate position element & the buffer to go with it VertexElement posElem = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer vbuf = vertexData.vertexBufferBinding.GetBuffer(posElem.Source); // lock the buffer for reading IntPtr bufPtr = vbuf.Lock(BufferLocking.ReadOnly); uint numCommon = 0; unsafe { byte *pVertex = (byte *)bufPtr.ToPointer(); float* pFloat; Vector3 pos; // Map for identifying duplicate position vertices Dictionary<Vector3, uint> commonVertexMap = new Dictionary<Vector3,uint>(); for (uint i = 0; i < vertexData.vertexCount; ++i, pVertex += vbuf.VertexSize) { pFloat = (float *)(pVertex + posElem.Offset); pos.x = *pFloat++; pos.y = *pFloat++; pos.z = *pFloat++; work.faceVertList[(int)i] = new PMFaceVertex(); // Try to find this position in the existing map if (!commonVertexMap.ContainsKey(pos)) { // Doesn't exist, so create it PMVertex commonVert = new PMVertex(); commonVert.SetDetails(pos, numCommon); commonVert.removed = false; commonVert.toBeRemoved = false; commonVert.seam = false; // Add it to our working set work.vertList[(int)numCommon] = commonVert; // Enter it in the map commonVertexMap.Add(pos, numCommon); // Increment common index ++numCommon; work.faceVertList[(int)i].commonVertex = commonVert; work.faceVertList[(int)i].realIndex = i; } else { // Exists already, reference it PMVertex existingVert = work.vertList[(int)commonVertexMap[pos]]; work.faceVertList[(int)i].commonVertex = existingVert; work.faceVertList[(int)i].realIndex = i; // Also tag original as a seam since duplicates at this location work.faceVertList[(int)i].commonVertex.seam = true; } } } vbuf.Unlock(); numCommonVertices = numCommon; // Build tri list uint numTris = (uint)indexData.indexCount / 3; HardwareIndexBuffer ibuf = indexData.indexBuffer; bool use32bitindexes = (ibuf.Type == IndexType.Size32); IntPtr indexBufferPtr = ibuf.Lock(BufferLocking.ReadOnly); unsafe { ushort* pShort = null; uint* pInt = null; if (use32bitindexes) { pInt = (uint *)indexBufferPtr.ToPointer(); } else { pShort = (ushort *)indexBufferPtr.ToPointer(); } work.triList = new PMTriangle[(int)numTris]; // assumed tri list for (uint i = 0; i < numTris; ++i) { // use 32-bit index always since we're not storing uint vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v0 = work.faceVertList[(int)vindex]; vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v1 = work.faceVertList[(int)vindex]; vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v2 = work.faceVertList[(int)vindex]; work.triList[(int)i] = new PMTriangle(); work.triList[(int)i].SetDetails(i, v0, v1, v2); work.triList[(int)i].removed = false; } } ibuf.Unlock(); }
/// <summary> /// Internal method for building PMWorkingData from geometry data /// </summary> private void AddWorkingData( VertexData vertexData, IndexData indexData ) { // Insert blank working data, then fill var work = new PMWorkingData(); this.workingDataList.Add( work ); // Build vertex list // Resize face list (this will always be this big) work.faceVertList = new PMFaceVertex[vertexData.vertexCount]; // Also resize common vert list to max, to avoid reallocations work.vertList = new PMVertex[vertexData.vertexCount]; // locate position element & the buffer to go with it var posElem = vertexData.vertexDeclaration.FindElementBySemantic( VertexElementSemantic.Position ); var vbuf = vertexData.vertexBufferBinding.GetBuffer( posElem.Source ); // lock the buffer for reading var bufPtr = vbuf.Lock( BufferLocking.ReadOnly ); uint numCommon = 0; #if !AXIOM_SAFE_ONLY unsafe #endif { var pVertex = bufPtr; Vector3 pos; // Map for identifying duplicate position vertices var commonVertexMap = new Dictionary<Vector3, uint>(); for ( uint i = 0; i < vertexData.vertexCount; ++i, pVertex += vbuf.VertexSize ) { var pFloat = ( pVertex + posElem.Offset ).ToFloatPointer(); pos.x = pFloat[ 0 ]; pos.y = pFloat[ 1 ]; pos.z = pFloat[ 2 ]; work.faceVertList[ (int)i ] = new PMFaceVertex(); // Try to find this position in the existing map if ( !commonVertexMap.ContainsKey( pos ) ) { // Doesn't exist, so create it var commonVert = new PMVertex(); commonVert.SetDetails( pos, numCommon ); commonVert.removed = false; commonVert.toBeRemoved = false; commonVert.seam = false; // Add it to our working set work.vertList[ (int)numCommon ] = commonVert; // Enter it in the map commonVertexMap.Add( pos, numCommon ); // Increment common index ++numCommon; work.faceVertList[ (int)i ].commonVertex = commonVert; work.faceVertList[ (int)i ].realIndex = i; } else { // Exists already, reference it var existingVert = work.vertList[ (int)commonVertexMap[ pos ] ]; work.faceVertList[ (int)i ].commonVertex = existingVert; work.faceVertList[ (int)i ].realIndex = i; // Also tag original as a seam since duplicates at this location work.faceVertList[ (int)i ].commonVertex.seam = true; } } } vbuf.Unlock(); this.numCommonVertices = numCommon; // Build tri list var numTris = (uint)indexData.indexCount/3; var ibuf = indexData.indexBuffer; var use32bitindexes = ( ibuf.Type == IndexType.Size32 ); var indexBufferPtr = ibuf.Lock( BufferLocking.ReadOnly ); #if !AXIOM_SAFE_ONLY unsafe #endif { var pInt = indexBufferPtr.ToUIntPointer(); var pShort = indexBufferPtr.ToUShortPointer(); var idx = 0; work.triList = new PMTriangle[(int)numTris]; // assumed tri list for ( uint i = 0; i < numTris; ++i ) { // use 32-bit index always since we're not storing var vindex = use32bitindexes ? pInt[ idx++ ] : pShort[ idx++ ]; var v0 = work.faceVertList[ (int)vindex ]; vindex = use32bitindexes ? pInt[ idx++ ] : pShort[ idx++ ]; var v1 = work.faceVertList[ (int)vindex ]; vindex = use32bitindexes ? pInt[ idx++ ] : pShort[ idx++ ]; var v2 = work.faceVertList[ (int)vindex ]; work.triList[ (int)i ] = new PMTriangle(); work.triList[ (int)i ].SetDetails( i, v0, v1, v2 ); work.triList[ (int)i ].removed = false; } } ibuf.Unlock(); }
/// <summary> /// Internal method for building PMWorkingData from geometry data /// </summary> void AddWorkingData(VertexData vertexData, IndexData indexData) { // Insert blank working data, then fill PMWorkingData work = new PMWorkingData(); this.workingDataList.Add(work); // Build vertex list // Resize face list (this will always be this big) work.faceVertList = new PMFaceVertex[vertexData.vertexCount]; // Also resize common vert list to max, to avoid reallocations work.vertList = new PMVertex[vertexData.vertexCount]; // locate position element & the buffer to go with it VertexElement posElem = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer vbuf = vertexData.vertexBufferBinding.GetBuffer(posElem.Source); // lock the buffer for reading IntPtr bufPtr = vbuf.Lock(BufferLocking.ReadOnly); uint numCommon = 0; unsafe { byte *pVertex = (byte *)bufPtr.ToPointer(); float * pFloat; Vector3 pos; // Map for identifying duplicate position vertices Dictionary <Vector3, uint> commonVertexMap = new Dictionary <Vector3, uint>(); for (uint i = 0; i < vertexData.vertexCount; ++i, pVertex += vbuf.VertexSize) { pFloat = (float *)(pVertex + posElem.Offset); pos.x = *pFloat++; pos.y = *pFloat++; pos.z = *pFloat++; work.faceVertList[(int)i] = new PMFaceVertex(); // Try to find this position in the existing map if (!commonVertexMap.ContainsKey(pos)) { // Doesn't exist, so create it PMVertex commonVert = new PMVertex(); commonVert.SetDetails(pos, numCommon); commonVert.removed = false; commonVert.toBeRemoved = false; commonVert.seam = false; // Add it to our working set work.vertList[(int)numCommon] = commonVert; // Enter it in the map commonVertexMap.Add(pos, numCommon); // Increment common index ++numCommon; work.faceVertList[(int)i].commonVertex = commonVert; work.faceVertList[(int)i].realIndex = i; } else { // Exists already, reference it PMVertex existingVert = work.vertList[(int)commonVertexMap[pos]]; work.faceVertList[(int)i].commonVertex = existingVert; work.faceVertList[(int)i].realIndex = i; // Also tag original as a seam since duplicates at this location work.faceVertList[(int)i].commonVertex.seam = true; } } } vbuf.Unlock(); numCommonVertices = numCommon; // Build tri list uint numTris = (uint)indexData.indexCount / 3; HardwareIndexBuffer ibuf = indexData.indexBuffer; bool use32bitindexes = (ibuf.Type == IndexType.Size32); IntPtr indexBufferPtr = ibuf.Lock(BufferLocking.ReadOnly); unsafe { ushort *pShort = null; uint * pInt = null; if (use32bitindexes) { pInt = (uint *)indexBufferPtr.ToPointer(); } else { pShort = (ushort *)indexBufferPtr.ToPointer(); } work.triList = new PMTriangle[(int)numTris]; // assumed tri list for (uint i = 0; i < numTris; ++i) { // use 32-bit index always since we're not storing uint vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v0 = work.faceVertList[(int)vindex]; vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v1 = work.faceVertList[(int)vindex]; vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v2 = work.faceVertList[(int)vindex]; work.triList[(int)i] = new PMTriangle(); work.triList[(int)i].SetDetails(i, v0, v1, v2); work.triList[(int)i].removed = false; } } ibuf.Unlock(); }