//Calcola la normale del punto passato public Vector3 CalculateSurfaceNormal(Vector3 p) { float H = 0.001f; float dx = Density.DensityFunc(p + new Vector3(H, 0, 0)) - Density.DensityFunc(p - new Vector3(H, 0, 0)); float dy = Density.DensityFunc(p + new Vector3(0, H, 0)) - Density.DensityFunc(p - new Vector3(0, H, 0)); float dz = Density.DensityFunc(p + new Vector3(0, 0, H)) - Density.DensityFunc(p - new Vector3(0, 0, H)); Vector3 res = new Vector3(dx, dy, dz); return(res.normalized); }
//approssima il punto di incontro dei vettori public Vector3 ApproximateZeroCrossingPosition(Vector3 p1, Vector3 p2, int steps) { float minVal = float.MaxValue; float t = 0, curT = 0; float increment = 1.0f / (float)steps; while (curT <= 1.0f) { Vector3 p = p1 + ((p2 - p1) * curT); float density = Mathf.Abs(Density.DensityFunc(p)); if (density < minVal) { minVal = density; t = curT; } curT += increment; } return(p1 + ((p2 - p1) * t)); }
//costruisce il nodo terminale (foglia) calcolando le NodeInfo per la generazione della mesh public OctreeNode BuildLeaf(OctreeNode leaf, int size) { if (leaf == null || leaf.size != size) { return(null); } int corners = 0; for (int i = 0; i < 8; i++) { Vector3 cornerPos = leaf.min + (CHILD_MIN_OFFSETS[i] * size); float density = Density.DensityFunc(cornerPos); int material = density < 0.0f ? SOLID : AIR; corners |= (material << i); } if (corners == 0 || corners == 255) { leaf = null; return(null); } int edgeCount = 0; Vector3 averageNormal = new Vector3(); QefSolver qef = new QefSolver(); for (int i = 0; i < 12 && edgeCount < MAX_CROSSINGS; i++) { int c1 = edgevmap[i][0]; int c2 = edgevmap[i][1]; int m1 = (corners >> c1) & 1; int m2 = (corners >> c2) & 1; if ((m1 == AIR && m2 == AIR) || (m1 == SOLID && m2 == SOLID)) { continue; } Vector3 p1 = leaf.min + (CHILD_MIN_OFFSETS[c1] * size); Vector3 p2 = leaf.min + (CHILD_MIN_OFFSETS[c2] * size); Vector3 p = ApproximateZeroCrossingPosition(p1, p2, 8); Vector3 n = CalculateSurfaceNormal(p); qef.Add(p.x, p.y, p.z, n.x, n.y, n.z); averageNormal += n; edgeCount++; } Vector3 qefPosition = new Vector3(); qef.Solve(qefPosition, QEF_ERROR, QEF_SWEEPS, QEF_ERROR); NodeInfo info = new NodeInfo(); info.index = -1; info.corners = 0; info.position = qefPosition; info.qef = qef.GetData(); Vector3 min = leaf.min; Vector3 max = new Vector3(leaf.min.x + leaf.size, leaf.min.y + leaf.size, leaf.min.z + leaf.size); if (info.position.x < min.x || info.position.x > max.x || info.position.y < min.y || info.position.y > max.y || info.position.z < min.z || info.position.z > max.z) { info.position = qef.GetMassPoint(); } info.avgNormal = (averageNormal / (float)edgeCount).normalized; info.corners = corners; leaf.type = NodeType.LEAF; leaf.nodeInfo = info; return(leaf); }