/* * child pointer | valid mask | nonleaf mask * 16 8 8 */ private void ExpandSVOAux(Node node, int nodeIndex, int level, List <int> svo, List <Node> svoNodes) { ChildDescriptor descriptor = new ChildDescriptor(svo[nodeIndex]); node.children = new Node[8]; int pointer = descriptor.childPointer; float half = node.size / 2f; if (svoNodes[nodeIndex] == null) { svoNodes[nodeIndex] = node; } for (int childNum = 0; childNum < 8; childNum++) { if (descriptor.Valid(childNum)) { bool leaf = descriptor.Leaf(childNum); Node child = new Node(node.position + Constants.vfoffsets[childNum] * (float)(half), half, level + 1, leaf); node.children[childNum] = child; if (!leaf) { ExpandSVOAux(node.children[childNum], pointer++, level + 1, svo, svoNodes); } } } }
private void RayStep(List <int> svo, Vector3 rayOrigin, Vector3 rayDirection, List <Node> intersectedNodes, List <Node> allSvoNodes) { //Debug.Log("Tracing svo hierarchy\n" + allSvoNodes[]) //string debugStr = ""; //debugStr += string.Join("\n", svo.ConvertAll(code => new ChildDescriptor(code))); //debugStr += "\nNeatly Printed Hierarchy:\n"; //debugStr += allSvoNodes[0].StringifyHierarchy(); //GUIUtility.systemCopyBuffer = debugStr; int s_max = 23; float epsilon = Mathf.Epsilon; StackData[] stack = new StackData[s_max + 1]; float tx_coef = 1.0f / -Mathf.Abs(rayDirection.x); float ty_coef = 1.0f / -Mathf.Abs(rayDirection.y); float tz_coef = 1.0f / -Mathf.Abs(rayDirection.z); float tx_bias = tx_coef * rayOrigin.x; float ty_bias = ty_coef * rayOrigin.y; float tz_bias = tz_coef * rayOrigin.z; int octant_mask = 7; if (rayDirection.x > 0.0f) { octant_mask ^= 1; tx_bias = 3.0f * tx_coef - tx_bias; } if (rayDirection.y > 0.0f) { octant_mask ^= 2; ty_bias = 3.0f * ty_coef - ty_bias; } if (rayDirection.z > 0.0f) { octant_mask ^= 4; tz_bias = 3.0f * tz_coef - tz_bias; } float t_min = Mathf.Max(2.0f * tx_coef - tx_bias, 2.0f * ty_coef - ty_bias, 2.0f * tz_coef - tz_bias); float t_max = Mathf.Min(tx_coef - tx_bias, ty_coef - ty_bias, tz_coef - tz_bias); float h = t_max; t_min = Mathf.Max(t_min, 0.0f); t_max = Mathf.Min(t_max, 1.0f); int parent = 0; // pointer to parent int child_descriptor = 0; // invalid until fetched int idx = 0; Vector3 pos = new Vector3(1.0f, 1.0f, 1.0f); // position of first child of root int scale = s_max - 1; // scale of "child" (22 at root) float scale_exp2 = 0.5f; // exp2f(scale - s_max) if (1.5f * tx_coef - tx_bias > t_min) { idx ^= 1; pos.x = 1.5f; } if (1.5f * ty_coef - ty_bias > t_min) { idx ^= 2; pos.y = 1.5f; } if (1.5f * tz_coef - tz_bias > t_min) { idx ^= 4; pos.z = 1.5f; } List <int> parentsVisited = new List <int>(); while (scale < s_max) { if (parent < allSvoNodes.Count) { //intersectedNodes.Add(allSvoNodes[parent]); Vector3 nodePos = pos; if ((octant_mask & 1) == 0) { nodePos.x = 3.0f - scale_exp2 - nodePos.x; } if ((octant_mask & 2) == 0) { nodePos.y = 3.0f - scale_exp2 - nodePos.y; } if ((octant_mask & 4) == 0) { nodePos.z = 3.0f - scale_exp2 - nodePos.z; } parentsVisited.Add(parent); //intersectedNodes.Add(new Node(nodePos, scale_exp2, 24 - scale, false)); } // Fetch child descriptor unless it is already valid. if (child_descriptor == 0) { child_descriptor = svo[parent]; } ChildDescriptor neatcd = new ChildDescriptor(child_descriptor); // Determine maximum t-value of the cube by evaluating // tx(), ty(), and tz() at its corner. float tx_corner = pos.x * tx_coef - tx_bias; float ty_corner = pos.y * ty_coef - ty_bias; float tz_corner = pos.z * tz_coef - tz_bias; float tc_max = Mathf.Min(tx_corner, ty_corner, tz_corner); int child_shift = idx ^ octant_mask; // permute child slots based on the mirroring int child_num = child_shift ^ 7; // Purely for seeing the index of the child in the debugger. Unused variable int child_masks = child_descriptor << child_shift; if ((child_masks & 0x8000) != 0 && t_min <= t_max) { // INTERSECT // Intersect active t-span with the cube and evaluate // tx(), ty(), and tz() at the center of the voxel. float tv_max = Mathf.Min(t_max, tc_max); float half = scale_exp2 * 0.5f; float tx_center = half * tx_coef + tx_corner; float ty_center = half * ty_coef + ty_corner; float tz_center = half * tz_coef + tz_corner; // Descend to the first child if the resulting t-span is non-empty. if (t_min <= tv_max) { // Terminate if the corresponding bit in the non-leaf mask is not set. if ((child_masks & 0x0080) == 0) { break; // at t_min (overridden with tv_min). } // PUSH // Write current parent to the stack. if (tc_max < h) { stack[scale] = new StackData(parent, t_max); } h = tc_max; // Find child descriptor corresponding to the current voxel. // child_descriptor format: first 16 bits is child pointer // next 8 is valid, next 8 is leaf int ofs = (child_descriptor >> 16); // child pointer ofs += popc8(child_masks & 0x7F); // finds (bits - 1) of shifted non-leaf mask parent = ofs; // Select child voxel that the ray enters first. idx = 0; scale--; scale_exp2 = half; if (tx_center > t_min) { idx ^= 1; pos.x += scale_exp2; } if (ty_center > t_min) { idx ^= 2; pos.y += scale_exp2; } if (tz_center > t_min) { idx ^= 4; pos.z += scale_exp2; } // Update active t-span and invalidate cached child descriptor. t_max = tv_max; child_descriptor = 0; continue; } } // ADVANCE // Step along the ray. int step_mask = 0; if (tx_corner <= tc_max) { step_mask ^= 1; pos.x -= scale_exp2; } if (ty_corner <= tc_max) { step_mask ^= 2; pos.y -= scale_exp2; } if (tz_corner <= tc_max) { step_mask ^= 4; pos.z -= scale_exp2; } // Update active t-span and flip bits of the child slot index. t_min = tc_max; idx ^= step_mask; // Proceed with pop if the bit flips disagree with the ray direction. if ((idx & step_mask) != 0) { // POP // Find the highest differing bit between the two positions. int differing_bits = 0; if ((step_mask & 1) != 0) { differing_bits |= __float_as_int(pos.x) ^ __float_as_int(pos.x + scale_exp2); } if ((step_mask & 2) != 0) { differing_bits |= __float_as_int(pos.y) ^ __float_as_int(pos.y + scale_exp2); } if ((step_mask & 4) != 0) { differing_bits |= __float_as_int(pos.z) ^ __float_as_int(pos.z + scale_exp2); } scale = (__float_as_int((float)differing_bits) >> 23) - 127; // position of the highest bit scale_exp2 = __int_as_float((scale - s_max + 127) << 23); // exp2f(scale - s_max) // Restore parent voxel from the stack. StackData stackEntry = stack[scale]; if (stackEntry != null) { parent = stackEntry.x; t_max = stackEntry.y; } // Round cube position and extract child slot index. int shx = __float_as_int(pos.x) >> scale; int shy = __float_as_int(pos.y) >> scale; int shz = __float_as_int(pos.z) >> scale; pos.x = __int_as_float(shx << scale); pos.y = __int_as_float(shy << scale); pos.z = __int_as_float(shz << scale); idx = (shx & 1) | ((shy & 1) << 1) | ((shz & 1) << 2); // Prevent same parent from being stored again and invalidate cached child descriptor. h = 0.0f; child_descriptor = 0; } } // Indicate miss if we are outside the octree. if (scale >= s_max) { t_min = 2.0f; } // Undo mirroring of the coordinate system. if ((octant_mask & 1) == 0) { pos.x = 3.0f - scale_exp2 - pos.x; } if ((octant_mask & 2) == 0) { pos.y = 3.0f - scale_exp2 - pos.y; } if ((octant_mask & 4) == 0) { pos.z = 3.0f - scale_exp2 - pos.z; } // Output results. /* hit_t = t_min; * hit_pos.x = fminf(fmaxf(p.x + t_min * d.x, pos.x + epsilon), pos.x + scale_exp2 - epsilon); * hit_pos.y = fminf(fmaxf(p.y + t_min * d.y, pos.y + epsilon), pos.y + scale_exp2 - epsilon); * hit_pos.z = fminf(fmaxf(p.z + t_min * d.z, pos.z + epsilon), pos.z + scale_exp2 - epsilon); * hit_parent = parent; * hit_idx = idx ˆ octant_mask ˆ 7; * hit_scale = scale;*/ //Vector3 hit_pos = new Vector3() if (scale >= s_max) { } else { Debug.Log("Hit_t: " + t_min); Debug.Log("Hit parents: " + string.Join(", ", parentsVisited)); Debug.Log("Hit idx: " + (idx ^ octant_mask ^ 7)); intersectedNodes.Add(allSvoNodes[parent].children[idx ^ octant_mask ^ 7]); } }