private void Build() { var triangles = _bvhData.scene.triangles; var vetices = _bvhData.scene.vertices; var rootSpec = NodeSpec.New(); rootSpec.numRef = triangles.Count; // 遍历所有图元(引用),计算根节点的包围盒 for (int i = 0; i < rootSpec.numRef; i++) { var pRef = PrimitiveRef.New(); pRef.triangleIdx = i; // 计算单个图元的包围盒 for (int j = 0; j < 3; j++) { pRef.bounds.Union(vetices[triangles[i][j]]); } rootSpec.bounds.Union(pRef.bounds); _refStack.Add(pRef); } // 最小重叠面积,只有重叠面积大于这个值时才考虑进行spatial split _minOverlap = rootSpec.bounds.Area * SPLIT_ALPHA; // 递归创建BVH _bvhData.root = BuildNodeRecursively(rootSpec, 0); Debug.Log("Build Completely."); }
private void SplitReference(out PrimitiveRef leftRef, out PrimitiveRef rightRef, PrimitiveRef curRef, int dim, float pos) { leftRef = rightRef = PrimitiveRef.New(); leftRef.triangleIdx = rightRef.triangleIdx = curRef.triangleIdx; var triangle = _bvhData.scene.triangles[curRef.triangleIdx]; var vertices = _bvhData.scene.vertices; // 遍历三角形的三条边01,12,20,然后将顶点与分割平面组成包围盒 for (byte i = 0; i < 3; i++) { var v0 = vertices[triangle[i]]; var v1 = vertices[triangle[i + 1 == 3 ? 0 : i + 1]]; float v0p = v0[dim]; float v1p = v1[dim]; if (v0p <= pos) { leftRef.bounds.Union(v0); } if (v0p >= pos) { rightRef.bounds.Union(v0); } // 求得分割平面与三角形的交点,且算进左右两边的包围盒 if ((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) { Vector3 t = Vector3.Lerp(v0, v1, Mathf.Clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f)); leftRef.bounds.Union(t); rightRef.bounds.Union(t); } } leftRef.bounds.max[dim] = pos; rightRef.bounds.min[dim] = pos; // 上面得到的是图元(三角形)被分割后左右两边的包围盒,但我们希望得到的包围盒除此之外,还应该限制在分割平面左右两个bin中 leftRef.bounds.Intersect(curRef.bounds); rightRef.bounds.Intersect(curRef.bounds); }