/// <summary> /// 2つのVertexを内分するVertexを求める /// </summary> /// <param name="v1">1つ目のVertex</param> /// <param name="v2">2つ目のVertex</param> /// <param name="isoValue">等値曲面の値</param> /// <returns>内分されたVertex</returns> public static Vertex Interpolate(Vertex v1, Vertex v2, float isoValue) { if (Math.Abs(isoValue - v1.Value) < 0.00001f) { return v1; } if (Math.Abs(isoValue - v2.Value) < 0.00001f) { return v2; } if (Math.Abs(v1.Value - v2.Value) < 0.00001f) { return v1; } var diff = (isoValue - v1.Value) / (v2.Value - v1.Value); Vertex v; v.Point = new Vec3( v1.Point.X + (v2.Point.X - v1.Point.X) * diff, v1.Point.Y + (v2.Point.Y - v1.Point.Y) * diff, v1.Point.Z + (v2.Point.Z - v1.Point.Z) * diff ); v.Value = (v1.Value + v2.Value) * 0.5f; v.IsInside = false; return v; }
/// <summary> /// 等値曲面を計算する /// </summary> /// <returns>等値曲面を構成する三角形の配列</returns> public unsafe List<Triangle> CalculateIsosurface() { // 等値曲面を構成するポリゴンの動的配列 var triangles = new List<Triangle>(); // ポリゴンを構成する座標の配列 var vertexList = new Vertex[12]; var vertices = (Vertex*)_verticesBuffer.ToPointer(); for (var z = 0; z < _sizeZ - 1; z++) { for (var y = 0; y < _sizeY - 1; y++) { for (var x = 0; x < _sizeX - 1; x++) { var lookup = 0; var index = x + y * _sizeX + z * _sizeX * _sizeY; // 等値曲面の内側に存在する頂点を検索する if (vertices[index + _sizeX + _sizeXY].IsInside) lookup |= 1; if (vertices[index + 1 + _sizeX + _sizeXY].IsInside) lookup |= 2; if (vertices[index + 1 + _sizeX].IsInside) lookup |= 4; if (vertices[index + _sizeX].IsInside) lookup |= 8; if (vertices[index + _sizeXY].IsInside) lookup |= 16; if (vertices[index + 1 + _sizeXY].IsInside) lookup |= 32; if (vertices[index + 1].IsInside) lookup |= 64; if (vertices[index].IsInside) lookup |= 128; // 全ての頂点が等値曲面の内側・外側に存在しないときのみ if ((lookup != 0) && (lookup != 255)) { if ((EDGE_TABLE[lookup] & 1) != 0) vertexList[0]= Vertex.Interpolate(vertices[index + _sizeX + _sizeXY], vertices[index + 1 + _sizeY + _sizeXY], _isoValue); if ((EDGE_TABLE[lookup] & 2) != 0) vertexList[1] = Vertex.Interpolate(vertices[index + 1 + _sizeX + _sizeXY], vertices[index + 1 + _sizeX], _isoValue); if ((EDGE_TABLE[lookup] & 4) != 0) vertexList[2] = Vertex.Interpolate(vertices[index + 1 + _sizeX], vertices[index + _sizeX], _isoValue); if ((EDGE_TABLE[lookup] & 8) != 0) vertexList[3] = Vertex.Interpolate(vertices[index + _sizeX], vertices[index + _sizeX + _sizeXY], _isoValue); if ((EDGE_TABLE[lookup] & 16) != 0) vertexList[4] = Vertex.Interpolate(vertices[index + _sizeXY], vertices[index + 1 + _sizeXY], _isoValue); if ((EDGE_TABLE[lookup] & 32) != 0) vertexList[5] = Vertex.Interpolate(vertices[index + 1 + _sizeXY], vertices[index + 1], _isoValue); if ((EDGE_TABLE[lookup] & 64) != 0) vertexList[6] = Vertex.Interpolate(vertices[index + 1], vertices[index], _isoValue); if ((EDGE_TABLE[lookup] & 128) != 0) vertexList[7] = Vertex.Interpolate(vertices[index], vertices[index + _sizeXY], _isoValue); if ((EDGE_TABLE[lookup] & 256) != 0) vertexList[8] = Vertex.Interpolate(vertices[index + _sizeX + _sizeXY], vertices[index + _sizeXY], _isoValue); if ((EDGE_TABLE[lookup] & 512) != 0) vertexList[9] = Vertex.Interpolate(vertices[index + 1 + _sizeX + _sizeXY], vertices[index + 1 + _sizeXY], _isoValue); if ((EDGE_TABLE[lookup] & 1024) != 0) vertexList[10] = Vertex.Interpolate(vertices[index + 1 + _sizeX], vertices[index + 1], _isoValue); if ((EDGE_TABLE[lookup] & 2048) != 0) vertexList[11] = Vertex.Interpolate(vertices[index + _sizeX], vertices[index], _isoValue); // 三角形ポリゴンを生成していく for (var i = 0; i < TRI_TABLE[lookup].Length; i += 3) { triangles.Add(new Triangle( vertexList[TRI_TABLE[lookup][i]].Point, vertexList[TRI_TABLE[lookup][i + 1]].Point, vertexList[TRI_TABLE[lookup][i + 2]].Point )); } } } } } return triangles; }