public static void UnpackVoxelEdgeId(VolumeHeader hd, int packed, out Int3 a3, out Int3 b3) { int a = (packed % hd.TotalCount); int b = (packed / hd.TotalCount); a3 = hd.LinearToCubic(a); b3 = hd.LinearToCubic(b); }
public void SpreadValuesUp(int mip, Func <T, T, T> comb) { if (mip + 1 >= this.Mips.Length) { return; } var big = this.Mips [mip]; var sml = this.Mips [mip + 1]; var h2 = new VolumeHeader(new Int3(2, 2, 2)); foreach (var si in sml.AllIndices3()) { var res = big.Read(si.AsCubic()); for (int n = 1; n < h2.TotalCount; n++) { var ni = si.Add(h2.LinearToCubic(n)); var sec = big.Read(ni.AsCubic()); res = comb(res, sec); } sml.Write(si.AsCubic(), res); } }
public static Mesh GenerateSurfaceVolume <T>(VolumeBuffer <T> vol, Func <T, float> signTest, Vector3 relativeCameraPos, DynamicFieldModel optionalModel = null) { int tetCorners = 4; Dictionary <int, int> ndxToVertex = new Dictionary <int, int> (); List <int> triangles = new List <int> (); List <int> quads = new List <int> (); float[] signes = new float[tetCorners]; List <int> edgesInTetra = new List <int> (); VolumeHeader h2 = new VolumeHeader(new Int3(2, 2, 2)); foreach (var ndx in vol.AllIndices3()) { if ((ndx.X != 0) && (ndx.Y != 0) && (ndx.Z != 0)) { var start = ndx.Add(new Int3(-1, -1, -1)); foreach (var ts in TetrasInCube) { int countPos = 0, countNeg = 0; int signKey = 0; for (int cornerIndex = 0; cornerIndex < ts.Length; cornerIndex++) { var lndx = ts[cornerIndex]; var cur = AddInvertTileOffset3(start, (h2.LinearToCubic(lndx))); var sv = signTest(vol.Read(cur)); if (sv >= 0.0f) { countPos++; signKey |= (1 << cornerIndex); } else { countNeg++; } signes [cornerIndex] = sv; } if ((countPos > 0) && (countNeg > 0)) { edgesInTetra.Clear(); // we have something in this tetrahedra! for (int ei = 0; ei < VolumeTetrahedraSurfacer.EdgesInTetra.Length; ei += 2) { var ef = VolumeTetrahedraSurfacer.EdgesInTetra [ei + 0]; var et = VolumeTetrahedraSurfacer.EdgesInTetra [ei + 1]; if (((signes [ef]) * (signes [et])) < 0.0f) { // we have something on this edge! var tf = ts[ef]; var tt = ts[et]; var vf = AddInvertTileOffset3(start, h2.LinearToCubic(tf)); var vt = AddInvertTileOffset3(start, h2.LinearToCubic(tt)); int encoded = PackVoxelEdgeIdSorted(vol.Header, vf, vt); edgesInTetra.Add(encoded); } } int prevVid = -1, prevPrevVid = -1, pppv = -1; foreach (var ee in edgesInTetra) { int vid; if (ndxToVertex.ContainsKey(ee)) { vid = ndxToVertex [ee]; } else { vid = ndxToVertex.Count; ndxToVertex.Add(ee, vid); } if (edgesInTetra.Count == 3) { triangles.Add(vid); } else if (edgesInTetra.Count == 4) { quads.Add(vid); } else { Debug.Assert(false, "Really?? c=" + edgesInTetra.Count); } pppv = prevPrevVid; prevPrevVid = prevVid; prevVid = vid; } } } } } List <Vector3> vertices = new List <Vector3> (); List <Vector3> vertexSigns = new List <Vector3> (); List <Vector4> vertexTangents = null; if (optionalModel != null) { vertexTangents = new List <Vector4> (); } Vector3 invScale = new Vector3(1.0f / (vol.Size.X - 1), 1.0f / (vol.Size.Y - 1), 1.0f / (vol.Size.Z - 1)); foreach (var kv in ndxToVertex) { // setup vertices from edge data: var packed = kv.Key; var vid = kv.Value; while (vertices.Count <= vid) { vertices.Add(Vector3.zero); vertexSigns.Add(Vector3.zero);; if (optionalModel != null) { vertexTangents.Add(Vector4.zero); } } Int3 a3, b3; UnpackVoxelEdgeId(vol.Header, packed, out a3, out b3); var wa = signTest(vol.Read(a3)); var wb = signTest(vol.Read(b3)); var wab = Mathf.Abs(wa) / (Mathf.Abs(wa) + Mathf.Abs(wb)); var pos = Vector3.Lerp(a3.AsVector3(), b3.AsVector3(), wab); //0.5f); // TODO: weight value based on signed root var upos = new Vector3(pos.x * invScale.x, pos.y * invScale.y, pos.z * invScale.z) - (Vector3.one * 0.5f); vertices [vid] = upos; vertexSigns [vid] = (a3.AsVector3() - b3.AsVector3()) * Mathf.Sign(wa - wb); if (optionalModel != null) { var ta = CalcFlowTangent(optionalModel, optionalModel.FieldsCells.Read(a3)); var tb = CalcFlowTangent(optionalModel, optionalModel.FieldsCells.Read(b3)); vertexTangents [vid] = Vector4.Lerp(ta, tb, wab); // ((ta + tb) *0.5f); } } for (int qi = 0; qi < quads.Count; qi += 4) { // ensure quad covers whole space (a and b must be furthest from each other): var a = vertices[quads[qi + 0]]; var b = vertices[quads[qi + 1]]; var c = vertices[quads[qi + 2]]; var d = vertices[quads[qi + 3]]; // add triangle a-b-c: triangles.Add(quads[qi + 0]); triangles.Add(quads[qi + 1]); triangles.Add(quads[qi + 2]); triangles.Add(quads[qi + 1]); triangles.Add(quads[qi + 3]); triangles.Add(quads[qi + 2]); } var trisToSort = new List <SortTri> (); for (int i = 0; i < triangles.Count; i += 3) { // ensure triangle is oriented correctly: var a = vertices[triangles[i + 0]]; var b = vertices[triangles[i + 1]]; var c = vertices[triangles[i + 2]]; var n = Vector3.Cross(b - a, c - b); if (Vector3.Dot(vertexSigns [triangles [i + 0]], n) >= 0.0f) { SwapListValues(triangles, i + 1, i + 2); } // add triangle to list SortTri tri; tri.I0 = triangles [i + 0]; tri.I1 = triangles [i + 1]; tri.I2 = triangles [i + 2]; tri.DistFromCam = (relativeCameraPos - ((a + b + c) * (1.0f / 3.0f))).magnitude; trisToSort.Add(tri); } // sort the triangles: if (true) { trisToSort.Sort((a, b) => - (a.DistFromCam.CompareTo(b.DistFromCam))); triangles.Clear(); foreach (var t in trisToSort) { triangles.Add(t.I0); triangles.Add(t.I1); triangles.Add(t.I2); } } Mesh result = new Mesh(); //Debug.Log ("Meshing info: verts=" + vertices.Count + " tris=" + triangles.Count); result.SetVertices(vertices); if (optionalModel != null) { result.SetTangents(vertexTangents); } result.triangles = (triangles.ToArray()); result.RecalculateNormals(); return(result); }