Пример #1
0
        public void intersect(Ray r, IntersectionState state)
        {
            float intervalMin = r.getMin();
            float intervalMax = r.getMax();
            float orgX = r.ox;
            float dirX = r.dx, invDirX = 1 / dirX;
            float t1, t2;
            t1 = (bounds.getMinimum().x - orgX) * invDirX;
            t2 = (bounds.getMaximum().x - orgX) * invDirX;
            if (invDirX > 0)
            {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            }
            else
            {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax)
                return;
            float orgY = r.oy;
            float dirY = r.dy, invDirY = 1 / dirY;
            t1 = (bounds.getMinimum().y - orgY) * invDirY;
            t2 = (bounds.getMaximum().y - orgY) * invDirY;
            if (invDirY > 0)
            {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            }
            else
            {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax)
                return;
            float orgZ = r.oz;
            float dirZ = r.dz, invDirZ = 1 / dirZ;
            t1 = (bounds.getMinimum().z - orgZ) * invDirZ;
            t2 = (bounds.getMaximum().z - orgZ) * invDirZ;
            if (invDirZ > 0)
            {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            }
            else
            {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax)
                return;

            // compute custom offsets from direction sign bit
            int offsetXFront = (int)((uint)(ByteUtil.floatToRawIntBits(dirX) & (1 << 31)) >> 30);//>>>
            int offsetYFront = (int)((uint)(ByteUtil.floatToRawIntBits(dirY) & (1 << 31)) >> 30);//>>>
            int offsetZFront = (int)((uint)(ByteUtil.floatToRawIntBits(dirZ) & (1 << 31)) >> 30);//>>>

            int offsetXBack = offsetXFront ^ 2;
            int offsetYBack = offsetYFront ^ 2;
            int offsetZBack = offsetZFront ^ 2;

            IntersectionState.StackNode[] stack = state.getStack();
            int stackTop = state.getStackTop();
            int stackPos = stackTop;
            int node = 0;

            while (true)
            {
                int tn = tree[node];
                int axis = tn & (3 << 30);
                int offset = tn & ~(3 << 30);
                switch (axis)
                {
                    case 0:
                        {
                            float d = (ByteUtil.intBitsToFloat(tree[node + 1]) - orgX) * invDirX;
                            int back = offset + offsetXBack;
                            node = back;
                            if (d < intervalMin)
                                continue;
                            node = offset + offsetXFront; // front
                            if (d > intervalMax)
                                continue;
                            // push back node
                            stack[stackPos].node = back;
                            stack[stackPos].near = (d >= intervalMin) ? d : intervalMin;
                            stack[stackPos].far = intervalMax;
                            stackPos++;
                            // update ray interval for front node
                            intervalMax = (d <= intervalMax) ? d : intervalMax;
                            continue;
                        }
                    case 1 << 30:
                        {
                            // y axis
                            float d = (ByteUtil.intBitsToFloat(tree[node + 1]) - orgY) * invDirY;
                            int back = offset + offsetYBack;
                            node = back;
                            if (d < intervalMin)
                                continue;
                            node = offset + offsetYFront; // front
                            if (d > intervalMax)
                                continue;
                            // push back node
                            stack[stackPos].node = back;
                            stack[stackPos].near = (d >= intervalMin) ? d : intervalMin;
                            stack[stackPos].far = intervalMax;
                            stackPos++;
                            // update ray interval for front node
                            intervalMax = (d <= intervalMax) ? d : intervalMax;
                            continue;
                        }
                    case 2 << 30:
                        {
                            // z axis
                            float d = (ByteUtil.intBitsToFloat(tree[node + 1]) - orgZ) * invDirZ;
                            int back = offset + offsetZBack;
                            node = back;
                            if (d < intervalMin)
                                continue;
                            node = offset + offsetZFront; // front
                            if (d > intervalMax)
                                continue;
                            // push back node
                            stack[stackPos].node = back;
                            stack[stackPos].near = (d >= intervalMin) ? d : intervalMin;
                            stack[stackPos].far = intervalMax;
                            stackPos++;
                            // update ray interval for front node
                            intervalMax = (d <= intervalMax) ? d : intervalMax;
                            continue;
                        }
                    default:
                        {
                            // leaf - test some objects
                            int n = tree[node + 1];
                            while (n > 0)
                            {
                                primitiveList.intersectPrimitive(r, primitives[offset], state);
                                n--;
                                offset++;
                            }
                            if (r.getMax() < intervalMax)
                                return;
                            do
                            {
                                // stack is empty?
                                if (stackPos == stackTop)
                                    return;
                                // move back up the stack
                                stackPos--;
                                intervalMin = stack[stackPos].near;
                                if (r.getMax() < intervalMin)
                                    continue;
                                node = stack[stackPos].node;
                                intervalMax = stack[stackPos].far;
                                break;
                            } while (true);
                            break;
                        }
                } // switch
            } // traversal loop
        }
        public void intersect(Ray r, IntersectionState state)
        {
            float intervalMin = r.getMin();
            float intervalMax = r.getMax();
            float orgX = r.ox;
            float dirX = r.dx, invDirX = 1 / dirX;
            float t1, t2;
            t1 = (bounds.getMinimum().x - orgX) * invDirX;
            t2 = (bounds.getMaximum().x - orgX) * invDirX;
            if (invDirX > 0)
            {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            }
            else
            {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax)
                return;
            float orgY = r.oy;
            float dirY = r.dy, invDirY = 1 / dirY;
            t1 = (bounds.getMinimum().y - orgY) * invDirY;
            t2 = (bounds.getMaximum().y - orgY) * invDirY;
            if (invDirY > 0)
            {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            }
            else
            {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax)
                return;
            float orgZ = r.oz;
            float dirZ = r.dz, invDirZ = 1 / dirZ;
            t1 = (bounds.getMinimum().z - orgZ) * invDirZ;
            t2 = (bounds.getMaximum().z - orgZ) * invDirZ;
            if (invDirZ > 0)
            {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            }
            else
            {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax)
                return;

            // compute custom offsets from direction sign bit

            int offsetXFront = (int)((uint)ByteUtil.floatToRawIntBits(dirX) >> 31);//>>>
            int offsetYFront = (int)((uint)ByteUtil.floatToRawIntBits(dirY) >> 31);//>>>
            int offsetZFront = (int)((uint)ByteUtil.floatToRawIntBits(dirZ) >> 31);//>>>

            int offsetXBack = offsetXFront ^ 1;
            int offsetYBack = offsetYFront ^ 1;
            int offsetZBack = offsetZFront ^ 1;

            int offsetXFront3 = offsetXFront * 3;
            int offsetYFront3 = offsetYFront * 3;
            int offsetZFront3 = offsetZFront * 3;

            int offsetXBack3 = offsetXBack * 3;
            int offsetYBack3 = offsetYBack * 3;
            int offsetZBack3 = offsetZBack * 3;

            // avoid always adding 1 during the inner loop
            offsetXFront++;
            offsetYFront++;
            offsetZFront++;
            offsetXBack++;
            offsetYBack++;
            offsetZBack++;

            IntersectionState.StackNode[] stack = state.getStack();
            int stackTop = state.getStackTop();
            int stackPos = stackTop;
            int node = 0;

            while (true)
            {
            pushloop:
                while (true)
                {
                    int tn = tree[node];
                    int axis = tn & (7 << 29);
                    int offset = tn & ~(7 << 29);
                    switch (axis)
                    {
                        case 0:
                            {
                                // x axis
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetXFront]) - orgX) * invDirX;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetXBack]) - orgX) * invDirX;
                                // ray passes between clip zones
                                if (tf < intervalMin && tb > intervalMax)
                                    goto pushloopend;
                                int back = offset + offsetXBack3;
                                node = back;
                                // ray passes through far node only
                                if (tf < intervalMin)
                                {
                                    intervalMin = (tb >= intervalMin) ? tb : intervalMin;
                                    continue;
                                }
                                node = offset + offsetXFront3; // front
                                // ray passes through near node only
                                if (tb > intervalMax)
                                {
                                    intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                    continue;
                                }
                                // ray passes through both nodes
                                // push back node
                                stack[stackPos].node = back;
                                stack[stackPos].near = (tb >= intervalMin) ? tb : intervalMin;
                                stack[stackPos].far = intervalMax;
                                stackPos++;
                                // update ray interval for front node
                                intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                continue;
                            }
                        case 1 << 30:
                            {
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetYFront]) - orgY) * invDirY;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetYBack]) - orgY) * invDirY;
                                // ray passes between clip zones
                                if (tf < intervalMin && tb > intervalMax)
                                    goto pushloopend;
                                int back = offset + offsetYBack3;
                                node = back;
                                // ray passes through far node only
                                if (tf < intervalMin)
                                {
                                    intervalMin = (tb >= intervalMin) ? tb : intervalMin;
                                    continue;
                                }
                                node = offset + offsetYFront3; // front
                                // ray passes through near node only
                                if (tb > intervalMax)
                                {
                                    intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                    continue;
                                }
                                // ray passes through both nodes
                                // push back node
                                stack[stackPos].node = back;
                                stack[stackPos].near = (tb >= intervalMin) ? tb : intervalMin;
                                stack[stackPos].far = intervalMax;
                                stackPos++;
                                // update ray interval for front node
                                intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                continue;
                            }
                        case 2 << 30:
                            {
                                // z axis
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetZFront]) - orgZ) * invDirZ;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetZBack]) - orgZ) * invDirZ;
                                // ray passes between clip zones
                                if (tf < intervalMin && tb > intervalMax)
                                    goto pushloopend;
                                int back = offset + offsetZBack3;
                                node = back;
                                // ray passes through far node only
                                if (tf < intervalMin)
                                {
                                    intervalMin = (tb >= intervalMin) ? tb : intervalMin;
                                    continue;
                                }
                                node = offset + offsetZFront3; // front
                                // ray passes through near node only
                                if (tb > intervalMax)
                                {
                                    intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                    continue;
                                }
                                // ray passes through both nodes
                                // push back node
                                stack[stackPos].node = back;
                                stack[stackPos].near = (tb >= intervalMin) ? tb : intervalMin;
                                stack[stackPos].far = intervalMax;
                                stackPos++;
                                // update ray interval for front node
                                intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                continue;
                            }
                        case 3 << 30:
                            {
                                // leaf - test some objects
                                int n = tree[node + 1];
                                while (n > 0)
                                {
                                    primitives.intersectPrimitive(r, objects[offset], state);
                                    n--;
                                    offset++;
                                }
                                goto pushloopend;
                            }
                        case 1 << 29:
                            {
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetXFront]) - orgX) * invDirX;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetXBack]) - orgX) * invDirX;
                                node = offset;
                                intervalMin = (tf >= intervalMin) ? tf : intervalMin;
                                intervalMax = (tb <= intervalMax) ? tb : intervalMax;
                                if (intervalMin > intervalMax)
                                    goto pushloopend;
                                continue;
                            }
                        case 3 << 29:
                            {
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetYFront]) - orgY) * invDirY;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetYBack]) - orgY) * invDirY;
                                node = offset;
                                intervalMin = (tf >= intervalMin) ? tf : intervalMin;
                                intervalMax = (tb <= intervalMax) ? tb : intervalMax;
                                if (intervalMin > intervalMax)
                                    goto pushloopend;
                                continue;
                            }
                        case 5 << 29:
                            {
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetZFront]) - orgZ) * invDirZ;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetZBack]) - orgZ) * invDirZ;
                                node = offset;
                                intervalMin = (tf >= intervalMin) ? tf : intervalMin;
                                intervalMax = (tb <= intervalMax) ? tb : intervalMax;
                                if (intervalMin > intervalMax)
                                    goto pushloopend;
                                continue;
                            }
                        default:
                            return; // should not happen
                    } // switch
                } // traversal loop
            pushloopend:
                do
                {
                    // stack is empty?
                    if (stackPos == stackTop)
                        return;
                    // move back up the stack
                    stackPos--;
                    intervalMin = stack[stackPos].near;
                    if (r.getMax() < intervalMin)
                        continue;
                    node = stack[stackPos].node;
                    intervalMax = stack[stackPos].far;
                    break;
                } while (true);
            }
        }