/// <summary> /// Build the primitives to all selected objects to be used in the BVH /// </summary> public static void Build(ref List <ObjectData> allObjects, out List <BVHNode> nodes, out List <BVHTriangle> tris, out List <BVHTriangle> finalPrims) { // Current primitive id int pID = 0; // These buffers are disposed in the Main script from which this method is called nodes = new List <BVHNode>(); tris = new List <BVHTriangle>(); finalPrims = new List <BVHTriangle>(); // Iterate thourgh all objects and create primitives using object's triangles foreach (ObjectData o in allObjects) { if (!o.IsValid) { continue; } // Using the mesh verts and the tris from each submesh, // we can build the lumes separately for each submesh for (int i = 0; i < o.Indices.Length; i += 3) { int trID0 = o.Indices[i + 0]; int trID1 = o.Indices[i + 1]; int trID2 = o.Indices[i + 2]; Vector3 v0 = o.VerticeList[trID0]; Vector3 v1 = o.VerticeList[trID1]; Vector3 v2 = o.VerticeList[trID2]; Vector3 n0 = o.HasNormals ? o.NormalList[trID0] : Vector3.zero; Vector3 n1 = o.HasNormals ? o.NormalList[trID1] : Vector3.zero; Vector3 n2 = o.HasNormals ? o.NormalList[trID2] : Vector3.zero; // You have to add the check for excluding back face trinagles here // Backfacing triangles skip Vector3 n = Vector3.Cross((v1 - v0).normalized, (v2 - v0).normalized).normalized; // Backfacing check if (Vector3.Dot(Vector3.up, n) >= 0f) { tris.Add(new BVHTriangle(v0, v1, v2, n0, n1, n2, pID++, o.TerrainSourceID)); } } } // Creating (Building) the bvh Bvh = new BVHNode(tris, nodes, ref finalPrims); }
public int SplitAxis; // 4 byte public LBVHNODE(BVHNode node) { BMin = node.Min; BMax = node.Max; NodeID = node.NodeID; PrimitivesCount = node.PrimitivesCount; PrimitivesOffset = node.PrimitivesOffset; ParentID = node.ParentID; LChildID = node.LChildID; RChildID = node.RChildID; IsLeaf = node.IsLeaf; SplitAxis = node.SplitAxis; NearNodeID = -1; FarNodeID = -1; }
public ObjectData(MeshRenderer r, int terrainSourceID) { Renderer = r; Mesh = r.GetComponent <MeshFilter>().sharedMesh; IsValid = Mesh != null; SubMesheCount = 0; VerticeList = null; NormalList = null; Indices = null; HasNormals = false; Prims = null; Nodes = null; TerrainSourceID = terrainSourceID; BVH = new BVHNode(); if (IsValid) { SubMesheCount = Mesh.subMeshCount; VerticeList = new List <Vector3>(); Mesh.GetVertices(VerticeList); NormalList = new List <Vector3>(); Mesh.GetNormals(NormalList); Indices = new int[Mesh.triangles.Length]; Indices = Mesh.triangles; HasNormals = NormalList.Count > 0; Matrix4x4 mtrx = Renderer.localToWorldMatrix; for (int v = 0; v < VerticeList.Count; v++) { VerticeList[v] = mtrx.MultiplyPoint3x4(VerticeList[v]); NormalList[v] = mtrx.MultiplyVector(NormalList[v]); } } }
public static BVHNode CreateBVHNode() { BVHNode b = new BVHNode { NodeType = 0, IsLeaf = 0, Centroid = Vector3.zero, Min = Vector3.one * float.MaxValue, Max = Vector3.one * -float.MaxValue, PrimID = -1, PrimitivesCount = 0, PrimitivesOffset = 0, NodeID = 0, ParentID = -1, LChildID = 0, RChildID = 0, NearNodeID = 0, FarNodeID = 0, SplitAxis = 0, SplitMethod = 1 }; return(b); }
public void Build(int nodeID, List <BVHTriangle> tris, ref List <BVHNode> nodes, ref List <BVHTriangle> finalPrims) { BVHNode node = nodes[nodeID]; // Leaf if (tris.Count <= BVH.MaxPrimsCountPerNode) { // NOTE : the prims offset is calculated in the " Flattening BVH " method node.IsLeaf = 1; node.PrimitivesCount = 1; node.PrimitivesOffset = finalPrims.Count; finalPrims.Add(tris[0]); nodes[nodeID] = node; } else { List <BVHTriangle> lTris = new List <BVHTriangle>(); List <BVHTriangle> rTris = new List <BVHTriangle>(); switch (node.SplitMethod) { // -------------------- Equal count split ! -------------------- case 0: // (int)BVHSplitMethod.SPLIT_EQUAL_COUNTS: node.GetLongestAxisAndValue(); int splitAxis = node.SplitAxis; // Equal split if (lTris.Count == 0 || rTris.Count == 0) { // In this case the incomming tris list should be sorted switch (splitAxis) { case 0: tris.Sort(CompareX); break; case 1: tris.Sort(CompareY); break; case 2: tris.Sort(CompareZ); break; } int trisHalf = tris.Count / 2; lTris = tris.GetRange(0, trisHalf); rTris = tris.GetRange(trisHalf, tris.Count - trisHalf); } break; // -------------------- Median axis split ! -------------------- case 1: // (int)BVHSplitMethod.SPLIT_MIDDLE: node.GetLongestAxisAndValue(); float splitValue = node.SplitValue; splitAxis = node.SplitAxis; // Median split triangle buffer switch (splitAxis) { case 0: lTris = tris.FindAll(n => n.Centroid.x < splitValue); rTris = tris.FindAll(n => n.Centroid.x >= splitValue); break; case 1: lTris = tris.FindAll(n => n.Centroid.y < splitValue); rTris = tris.FindAll(n => n.Centroid.y >= splitValue); break; case 2: lTris = tris.FindAll(n => n.Centroid.z < splitValue); rTris = tris.FindAll(n => n.Centroid.z >= splitValue); break; } // If median split was not good enough // Switch to equal split if (lTris.Count == 0 || rTris.Count == 0) { // In this case the incomming tris list should be sorted switch (splitAxis) { case 0: tris.Sort(CompareX); break; case 1: tris.Sort(CompareY); break; case 2: tris.Sort(CompareZ); break; } int trisHalf = tris.Count / 2; lTris = tris.GetRange(0, trisHalf); rTris = tris.GetRange(trisHalf, tris.Count - trisHalf); } //Debug.Log("Sliptting primitives using median split"); break; // -------------------- Split using surface area heuristic ! -------------------- case 2: // BVHSplitMethod.SPLIT_SAH: break; } BVHNode lChild = CreateBVHNode(); BVHNode rChild = CreateBVHNode(); lChild.NodeID = nodes.Count + 0; rChild.NodeID = nodes.Count + 1; lChild.ParentID = node.NodeID; rChild.ParentID = node.NodeID; lChild.NodeType = 1; rChild.NodeType = 2; node.LChildID = lChild.NodeID; node.RChildID = rChild.NodeID; lChild.CalculateBBox(lTris); rChild.CalculateBBox(rTris); // ---------------------------------------------------------------------------- // Adding both children into the nodes list // ---------------------------------------------------------------------------- nodes.Add(lChild); nodes.Add(rChild); // ---------------------------------------------------------------------------- // Building the children nodes // ---------------------------------------------------------------------------- // Use only when dealing with structs nodes[nodeID] = node; Build(lChild.NodeID, lTris, ref nodes, ref finalPrims); Build(rChild.NodeID, rTris, ref nodes, ref finalPrims); } }