#include "Main.h" IsoSurface::IsoSurface() { _Function = NULL; _Epsilon = 0.0003f; } void IsoSurface::CalcGradient(const Vec3f &Pos, Vec3f &Normal) { float value = _Function(Pos); Normal.x = (_Function(Vec3f(Pos.x + _Epsilon, Pos.y, Pos.z)) - value); Normal.y = (_Function(Vec3f(Pos.x, Pos.y + _Epsilon, Pos.z)) - value); Normal.z = (_Function(Vec3f(Pos.x, Pos.y, Pos.z + _Epsilon)) - value); Normal = Vec3f::Normalize(Normal); } void IsoSurface::IsoApproximate(float BoxSize, float CellSize, BaseMesh &Result, float (*Function)(const Vec3f &Pos)) { Vec3f End(BoxSize, BoxSize, BoxSize); IsoApproximate(-End, End, CellSize, Result, Function); } void IsoSurface::IsoApproximate(const Vec3f &Start, const Vec3f &End, float CellSize, BaseMesh &Result, float (*Function)(const Vec3f &Pos)) { _Function = Function; _CellSize = CellSize; _Start = Start; _End = End; _Diff = _End - _Start; _XCount = int(_Diff.x / _CellSize); _YCount = int(_Diff.y / _CellSize); _ZCount = int(_Diff.z / _CellSize); float *TopGrid = new float[_XCount * _YCount]; float *BottomGrid = new float[_XCount * _YCount]; FillGrid(TopGrid, 0); for(UINT z = 1; z < _ZCount - 1; z++) { FillGrid(BottomGrid, z); PolygonizeGrids(TopGrid, BottomGrid, z); Utility::Swap(TopGrid, BottomGrid); } delete[] TopGrid; delete[] BottomGrid; MakeObject(Result); } void IsoSurface::FreeMemory() { } void IsoSurface::MakeObject(BaseMesh &Result) { Result.Allocate(_AllVertices.Length(), _AllFaces.Length()); MeshVertex *V = Result.Vertices(); DWORD *I = Result.Indices(); for(UINT VertexIndex = 0; VertexIndex < _AllVertices.Length(); VertexIndex++) { MeshVertex &CurVertex = V[VertexIndex]; CurVertex.Pos = _AllVertices[VertexIndex]; CalcGradient(CurVertex.Pos, CurVertex.Normal); } for(UINT FaceIndex = 0; FaceIndex < _AllFaces.Length(); FaceIndex++) { const TriMeshFace &CurFace = _AllFaces[FaceIndex]; I[FaceIndex * 3 + 0] = CurFace.I[0]; I[FaceIndex * 3 + 1] = CurFace.I[1]; I[FaceIndex * 3 + 2] = CurFace.I[2]; } Result.ColorNormals(); } bool IsoSurface::PushPolygons(GRIDCELL &g) { int NewVertexCount, IndexShift = _AllVertices.Length(); int NewFaceCount = Polygonise(g, _FaceStorage, NewVertexCount, _VertexStorage); if(NewFaceCount) { for(int FaceIndex = 0; FaceIndex < NewFaceCount; FaceIndex++) { _FaceStorage[FaceIndex].I[0] += IndexShift; _FaceStorage[FaceIndex].I[1] += IndexShift; _FaceStorage[FaceIndex].I[2] += IndexShift; _AllFaces.PushEnd(_FaceStorage[FaceIndex]); } for(int VertexIndex = 0; VertexIndex < NewVertexCount; VertexIndex++) { _AllVertices.PushEnd(_VertexStorage[VertexIndex]); } return true; } return false; } void IsoSurface::FillGrid(float *Grid, int z) { for(UINT x = 0; x < _XCount; x++) { for(UINT y = 0; y < _YCount; y++) { Vec3f Pos = Vec3f(_Start.x + _CellSize * x,_Start.y + _CellSize * y,_Start.z + _CellSize * (z + 1)); Grid[x * _YCount + y] = _Function(Pos); } } } void IsoSurface::PolygonizeGrids(float *TopVals, float *BottomVals, int z) { for(UINT x = 0; x < _XCount - 1; x++) { for(UINT y = 0; y < _YCount - 1; y++) { GRIDCELL g; g.p[0] = Vec3f(_Start.x + _CellSize * (x+0),_Start.y + _CellSize * (y+0),_Start.z + _CellSize * (z+0)); g.p[1] = Vec3f(_Start.x + _CellSize * (x+1),_Start.y + _CellSize * (y+0),_Start.z + _CellSize * (z+0)); g.p[2] = Vec3f(_Start.x + _CellSize * (x+1),_Start.y + _CellSize * (y+1),_Start.z + _CellSize * (z+0)); g.p[3] = Vec3f(_Start.x + _CellSize * (x+0),_Start.y + _CellSize * (y+1),_Start.z + _CellSize * (z+0)); g.val[0] = TopVals[x*_YCount+y]; g.val[1] = TopVals[(x+1)*_YCount+y]; g.val[2] = TopVals[(x+1)*_YCount+y+1]; g.val[3] = TopVals[x*_YCount+y+1]; g.p[4] = Vec3f(_Start.x + _CellSize * (x+0),_Start.y + _CellSize * (y+0),_Start.z + _CellSize * (z+1)); g.p[5] = Vec3f(_Start.x + _CellSize * (x+1),_Start.y + _CellSize * (y+0),_Start.z + _CellSize * (z+1)); g.p[6] = Vec3f(_Start.x + _CellSize * (x+1),_Start.y + _CellSize * (y+1),_Start.z + _CellSize * (z+1)); g.p[7] = Vec3f(_Start.x + _CellSize * (x+0),_Start.y + _CellSize * (y+1),_Start.z + _CellSize * (z+1)); g.val[4] = BottomVals[x*_YCount+y]; g.val[5] = BottomVals[(x+1)*_YCount+y]; g.val[6] = BottomVals[(x+1)*_YCount+y+1]; g.val[7] = BottomVals[x*_YCount+y+1]; bool Valid = true; for(UINT VertexIndex = 0; VertexIndex < 8 && Valid; VertexIndex++) { if(g.val[VertexIndex] == FLT_MAX) { Valid = false; } } if(Valid) { PushPolygons(g); } } } }