Beispiel #1
0
        public override bool FindIntersection(Ray ray, out Intersection intersect)
        {
            intersect = new Intersection();
            Vector3D v      = ray.Origin - this.center;
            float    pdotuA = v * this.axisA;
            float    pdotuB = v * this.axisB;
            float    pdotuC = v * this.axisC;
            float    udotuA = ray.Direction * this.axisA;
            float    udotuB = ray.Direction * this.axisB;
            float    udotuC = ray.Direction * this.axisC;
            float    C      = (pdotuA * pdotuA) + (pdotuB * pdotuB) + (pdotuC * pdotuC) - 1.0f;
            float    B      = (pdotuA * udotuA + pdotuB * udotuB + pdotuC * udotuC);

            if (C > 0.0f && B >= 0.0f)
            {
                return(false); // Pointing away from the ellipsoid
            }
            B += B;            // Double B to get final factor of 2.
            float A = (udotuA * udotuA) + (udotuB * udotuB) + (udotuC * udotuC);
            float alpha1, alpha2;
            int   numRoots = EquationSolver.SolveQuadric(A, B, C, out alpha1, out alpha2);

            if (numRoots == 0)
            {
                return(false);
            }
            if (alpha1 > 0.01f)
            {
                // Found an intersection from outside.
                intersect.TMin          = alpha1;
                intersect.TMax          = alpha2;
                intersect.HitFromInSide = false;
            }
            else if (numRoots == 2 && alpha2 > 0.01f)
            {
                // Found an intersection from inside.
                intersect.TMin          = alpha2;
                intersect.TMax          = alpha1;
                intersect.HitFromInSide = true;
            }
            else
            {
                return(false); // Both intersections behind us (should never get here)
            }
            // Calculate intersection position
            intersect.HitPoint = ray.Origin + intersect.TMin * ray.Direction;
            intersect.Normal   = intersect.HitPoint - this.center; // Now v is the relative position
            float vdotuA = intersect.Normal * this.axisA;
            float vdotuB = intersect.Normal * this.axisB;
            float vdotuC = intersect.Normal * this.axisC;

            intersect.Normal = vdotuA * this.axisA + vdotuB * this.axisB + vdotuC * this.axisC;
            intersect.Normal.Normalize();
            intersect.HitPrimitive = this;
            if (this.material != null && this.material.IsTexturized)
            {
                double uCoord = Math.Atan2(-vdotuB, vdotuA) * (1.0 / (Math.PI + Math.PI));
                double vCoord = 1.0 - Math.Cos(-vdotuC) * (1.0 / Math.PI);
                if (uCoord < 0.0)
                {
                    uCoord++;
                }
                //int widthTex = this.material.Texture.Width - 1;
                //int heightTex = this.material.Texture.Height - 1;
                //this.material.Color = this.material.Texture.GetPixel((int)(uCoord * widthTex), (int)(vCoord * heightTex));
                intersect.CurrentTextureCoordinate.U = (float)uCoord;
                intersect.CurrentTextureCoordinate.V = (float)vCoord;
            }
            return(true);
        }
Beispiel #2
0
        public override bool FindIntersection(Ray ray, out Intersection intersect)
        {
            intersect = new Intersection();
            Vector3D rayDir   = ray.Direction;
            Point3D  rayPoint = ray.Origin;
            //this->boundingBox->intersect(line, point, normal, u, v);
            //if(!(*point))
            //{
            //    *point = 0;
            //    *normal = 0;
            //    return;
            //}
            //@see: http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter4.htm
            float Aq_1 = this.a * (rayDir.X * rayDir.X);
            float Aq_2 = this.b * (rayDir.Y * rayDir.Y);
            float Aq_3 = this.c * (rayDir.Z * rayDir.Z);
            float Aq_4 = this.d * rayDir.X * rayDir.Y;
            float Aq_5 = this.e * rayDir.X * rayDir.Z;
            float Aq_6 = this.f * rayDir.Y * rayDir.Z;
            float Bq_1 = 2 * this.a * rayPoint.X * rayDir.X;
            float Bq_2 = 2 * this.b * rayPoint.Y * rayDir.Y;
            float Bq_3 = 2 * this.c * rayPoint.Z * rayDir.Z;
            float Bq_4 = this.d * ((rayPoint.X * rayDir.Y) + (rayPoint.Y * rayDir.X));
            float Bq_5 = this.e * rayPoint.X * rayDir.Z;
            float Bq_6 = this.f * ((rayPoint.Y * rayDir.Z) + (rayDir.Y * rayPoint.Z));
            float Bq_7 = this.g * rayDir.X;
            float Bq_8 = this.h * rayDir.Y;
            float Bq_9 = this.i * rayDir.Z;
            float Cq_1 = this.a * (rayPoint.X * rayPoint.X);
            float Cq_2 = this.b * (rayPoint.Y * rayPoint.Y);
            float Cq_3 = this.c * (rayPoint.Z * rayPoint.Z);
            float Cq_4 = this.d * rayPoint.X * rayPoint.Y;
            float Cq_5 = this.e * rayPoint.X * rayPoint.Z;
            float Cq_6 = this.f * rayPoint.Y * rayPoint.Z;
            float Cq_7 = this.g * rayPoint.X;
            float Cq_8 = this.h * rayPoint.Y;
            float Cq_9 = this.i * rayPoint.Z;
            float Aq   = Aq_1 + Aq_2 + Aq_3 + Aq_4 + Aq_5 + Aq_6;
            float Bq   = Bq_1 + Bq_2 + Bq_3 + Bq_4 + Bq_5 + Bq_6 + Bq_7 + Bq_8 + Bq_9;
            float Cq   = Cq_1 + Cq_2 + Cq_3 + Cq_4 + Cq_5 + Cq_6 + Cq_7 + Cq_8 + Cq_9 + this.j;
            //quadratic equation:   Aqt² + Bqt + Cq = 0
            float t, t0, t1, tMin, tMax;

            if (EquationSolver.SolveQuadric(Aq, Bq, Cq, out t0, out t1) == 0)
            {
                return(false);
            }
            tMin = (float)Math.Min(t0, t1);
            tMax = (float)Math.Max(t0, t1);
            if (tMin > 0.01f)
            {
                t = tMin;
            }
            else if (tMax > 0.01f)
            {
                t = tMax;
            }
            else
            {
                return(false);
            }
            Point3D tempP = rayPoint + rayDir * t;
            //if (!this.boundBox.IsInside(tempP) && tMax > 0)
            //{
            //    tempP = rayPoint + rayDir * tMax;
            //}
            //bool isInsideBox = this->boundingBox->checkCollision(Box(tempP.getX(), tempP.getY(), tempP.getZ(),
            //														 tempP.getX(), tempP.getY(), tempP.getZ()));
            //if(!isInsideBox && t == tMin && tMax > 0)
            //{
            //    tempP = (*rayPoint) + ((*rayDir) * tMax);
            //    isInsideBox = this->boundingBox->checkCollision(Box(tempP.getX(), tempP.getY(), tempP.getZ(),
            //                                                         tempP.getX(), tempP.getY(), tempP.getZ()));
            //}
            //if(isInsideBox)
            //{
            //*point = new Point(tempP.getX(), tempP.getY(), tempP.getZ());
            //calculating normal
            float nX1     = 2 * this.a * tempP.X;
            float nX2     = this.d * tempP.Y;
            float nX3     = this.e * tempP.Z;
            float nY1     = 2 * this.b * tempP.Y;
            float nY2     = this.d * tempP.X;
            float nY3     = this.f * tempP.Z;
            float nZ1     = 2 * this.c * tempP.Z;
            float nZ2     = this.e * tempP.X;
            float nZ3     = this.f * tempP.Y;
            float normalX = nX1 + nX2 + nX3 + this.g;
            float normalY = nY1 + nY2 + nY3 + this.h;
            float normalZ = nZ1 + nZ2 + nZ3 + this.i;

            intersect.Normal = new Vector3D(normalX, normalY, normalZ);
            intersect.Normal.Normalize();
            intersect.HitPoint     = tempP;
            intersect.HitPrimitive = this;
            intersect.TMin         = t;
            return(true);
            //}
        }
Beispiel #3
0
        public override bool FindIntersection(Ray ray, out Intersection intersect)
        {
            intersect = new Intersection();
            float   maxFrontDist = float.NegativeInfinity;
            float   minBackDist = float.PositiveInfinity;
            HitSide frontType = HitSide.None, backType = HitSide.None; // 0, 1 = base, side
            float   viewPosdotCtr = ray.Origin * this.centralAxis;
            float   udotuCtr      = ray.Direction * this.centralAxis;

            if (viewPosdotCtr > (this.apexDotCenterAxis) && udotuCtr >= 0.0f)
            {
                return(false); // Above the cone's apex
            }
            // Start with the bounding base plane
            float pdotnCap = this.baseNormal * ray.Origin;
            float udotnCap = this.baseNormal * ray.Direction;

            if (pdotnCap > this.coefBasePlane)
            {
                if (udotnCap >= 0.0f)
                {
                    return(false); // Above (=outside) base plane, pointing away
                }
                maxFrontDist = (this.coefBasePlane - pdotnCap) / udotnCap;
                frontType    = HitSide.BottomPlane;
            }
            else if (pdotnCap < this.coefBasePlane)
            {
                if (udotnCap > 0.0f)
                {
                    // Below (=inside) base plane, pointing towards the plane
                    minBackDist = (this.coefBasePlane - pdotnCap) / udotnCap;
                    backType    = HitSide.BottomPlane;
                }
            }
            // Now handle the cone's sides
            Vector3D v        = ray.Origin - this.apex;
            float    pdotuCtr = v * this.centralAxis;
            float    pdotuA   = v * this.axisA;
            float    pdotuB   = v * this.axisB;
            // udotuCtr already defined above
            float udotuA = ray.Direction * this.axisA;
            float udotuB = ray.Direction * this.axisB;
            float C      = pdotuA * pdotuA + pdotuB * pdotuB - pdotuCtr * pdotuCtr;
            float B      = (pdotuA * udotuA + pdotuB * udotuB - pdotuCtr * udotuCtr);

            B += B;
            float A = udotuA * udotuA + udotuB * udotuB - udotuCtr * udotuCtr;
            float alpha1, alpha2; // The roots, in order
            int   numRoots = EquationSolver.SolveQuadric(A, B, C, out alpha1, out alpha2);

            if (numRoots == 0)
            {
                return(false); // No intersection
            }
            bool viewMoreVertical = (A < 0.0f);

            if (viewMoreVertical)
            {
                // View line leaves and then enters the cone
                if (alpha1 < minBackDist && pdotuCtr + alpha1 * udotuCtr <= 0.0f)
                {
                    if (alpha1 < maxFrontDist)
                    {
                        return(false);
                    }
                    minBackDist = alpha1;
                    backType    = HitSide.Cone;
                }
                else if (numRoots == 2 && alpha2 > maxFrontDist && pdotuCtr + alpha2 * udotuCtr <= 0.0f)
                {
                    if (alpha2 > minBackDist)
                    {
                        return(false);
                    }
                    maxFrontDist = alpha2;
                    frontType    = HitSide.Cone;
                }
            }
            else
            {
                // view line enters and then leaves
                if (alpha1 > maxFrontDist)
                {
                    if (pdotuCtr + alpha1 * udotuCtr > 0.0f)
                    {
                        return(false); // Enters dual cone instead
                    }
                    if (alpha1 > minBackDist)
                    {
                        return(false);
                    }
                    maxFrontDist = alpha1;
                    frontType    = HitSide.Cone;
                }
                if (numRoots == 2 && alpha2 < minBackDist)
                {
                    if (pdotuCtr + alpha2 * udotuCtr > 0.0f)
                    {
                        return(false); // Is leaving dual cone instead
                    }
                    if (alpha2 < maxFrontDist)
                    {
                        return(false);
                    }
                    minBackDist = alpha2;
                    backType    = HitSide.Cone;
                }
            }
            // Put it all together:
            float   alpha;
            HitSide hitSurface = HitSide.None;

            if (maxFrontDist > 0.0f)
            {
                alpha      = maxFrontDist;
                hitSurface = frontType;
            }
            else
            {
                alpha      = minBackDist;
                hitSurface = backType;
            }
            if (alpha < 0.0)
            {
                return(false);
            }
            intersect.TMin = alpha;
            // Set v to the intersection point
            intersect.HitPoint     = ray.Origin + intersect.TMin * ray.Direction;
            intersect.HitPrimitive = this;
            // Now set v equal to returned position relative to the apex
            v = intersect.HitPoint - this.apex;
            float vdotuA   = v * this.axisA;
            float vdotuB   = v * this.axisB;
            float vdotuCtr = v * this.centralAxis;

            switch (hitSurface)
            {
            case HitSide.BottomPlane:     // Base face
                intersect.Normal = this.baseNormal;
                if (this.material != null && this.material.IsTexturized)
                {
                    // Calculate U-V values for texture coordinates
                    vdotuA /= vdotuCtr;     // vdotuCtr is negative
                    vdotuB /= vdotuCtr;
                    vdotuA  = 0.5f * (1.0f - vdotuA);
                    vdotuB  = 0.5f * (1.0f - vdotuB);
                    //int widthTex = this.material.Texture.Width - 1;
                    //int heightTex = this.material.Texture.Height - 1;
                    //this.material.Color =
                    //    this.material.Texture.GetPixel((int)(vdotuB * widthTex), (int)(vdotuA * heightTex));
                    intersect.CurrentTextureCoordinate.U = vdotuB;
                    intersect.CurrentTextureCoordinate.V = vdotuA;
                }
                break;

            case HitSide.Cone:     // Cone's side
                intersect.Normal  = vdotuA * this.axisA;
                intersect.Normal += vdotuB * this.axisB;
                intersect.Normal -= vdotuCtr * this.centralAxis;
                intersect.Normal.Normalize();
                if (this.material != null && this.material.IsTexturized)
                {
                    // Calculate u-v coordinates for texture mapping (in range[0,1]x[0,1])
                    float uCoord = (float)(Math.Atan2(vdotuB, vdotuA) / (Math.PI + Math.PI) + 0.5);
                    float vCoord = (vdotuCtr + this.height) / this.height;
                    //int widthTex = this.material.Texture.Width - 1;
                    //int heightTex = this.material.Texture.Height - 1;
                    //this.material.Color =
                    //    this.material.Texture.GetPixel((int)(uCoord * widthTex), (int)(vCoord * heightTex));
                    intersect.CurrentTextureCoordinate.U = uCoord;
                    intersect.CurrentTextureCoordinate.V = vCoord;
                }
                break;
            }
            return(true);
        }
Beispiel #4
0
        public override bool FindIntersection(Ray ray, out Intersection intersect)
        {
            intersect = new Intersection();
            float        maxFrontDist = float.MinValue;
            float        minBackDist = float.MaxValue;
            HitPrimitive frontType = HitPrimitive.None, backType = HitPrimitive.None; // 0, 1, 2 = top, bottom, side
            // Start with the bounding planes
            float pdotn = (ray.Origin * this.centralAxis) - this.centerDotcentralAxis;
            float udotn = ray.Direction * this.centralAxis;

            if (pdotn > this.halfHeight)
            {
                if (udotn >= 0.0)
                {
                    return(false); // Above top plane pointing up
                }
                // Hits top from above
                maxFrontDist = (this.halfHeight - pdotn) / udotn;
                frontType    = HitPrimitive.TopPlane;
                minBackDist  = -(this.halfHeight + pdotn) / udotn;
                backType     = HitPrimitive.BottomPlane;
            }
            else if (pdotn < -this.halfHeight)
            {
                if (udotn <= 0.0)
                {
                    return(false); // Below bottom, pointing down
                }
                // Hits bottom plane from below
                maxFrontDist = -(this.halfHeight + pdotn) / udotn;
                frontType    = HitPrimitive.BottomPlane;
                minBackDist  = (this.halfHeight - pdotn) / udotn;
                backType     = HitPrimitive.TopPlane;
            }
            else if (udotn < 0.0)
            {
                // Inside, pointing down
                minBackDist = -(this.halfHeight + pdotn) / udotn;
                backType    = HitPrimitive.BottomPlane;
            }
            else if (udotn > 0.0)
            {
                // Inside, pointing up
                minBackDist = (this.halfHeight - pdotn) / udotn;
                backType    = HitPrimitive.TopPlane;
            }
            if (maxFrontDist < 0)
            {
                return(false);
            }
            // Now handle the cylinder sides
            Vector3D v = ray.Origin - this.center;
            float    pdotuA = v * this.axisA;
            float    pdotuB = v * this.axisB;
            float    udotuA = ray.Direction * this.axisA;
            float    udotuB = ray.Direction * this.axisB;
            float    C = pdotuA * pdotuA + pdotuB * pdotuB - 1.0f;
            float    B = (pdotuA * udotuA + pdotuB * udotuB);

            if (C >= 0.0 && B > 0.0)
            {
                return(false);    // Pointing away from the cylinder
            }
            B += B;               // Double B for final 2.0 factor
            float A = udotuA * udotuA + udotuB * udotuB;
            float alpha1, alpha2; // The roots, in order
            int   numRoots = EquationSolver.SolveQuadric(A, B, C, out alpha1, out alpha2);

            if (numRoots == 0)
            {
                return(false); // No intersection
            }
            if (alpha1 > maxFrontDist)
            {
                if (alpha1 > minBackDist)
                {
                    return(false);
                }
                maxFrontDist = alpha1;
                frontType    = HitPrimitive.Cylinder;
            }
            if (numRoots == 2 && alpha2 < minBackDist)
            {
                if (alpha2 < maxFrontDist)
                {
                    return(false);
                }
                minBackDist = alpha2;
                backType    = HitPrimitive.Cylinder;
            }
            // Put it all together:
            float        alpha;
            HitPrimitive hitSurface;

            if (maxFrontDist > 0.0)
            {
                intersect.HitFromInSide = true; // Hit from outside
                alpha      = maxFrontDist;
                hitSurface = frontType;
            }
            else
            {
                intersect.HitFromInSide = false; // Hit from inside
                alpha      = minBackDist;
                hitSurface = backType;
            }
            if (alpha < 0.01)
            {
                return(false);
            }
            intersect.TMin = alpha;
            intersect.TMax = alpha2;
            // Set v to the intersection point
            intersect.HitPoint     = ray.Origin + ray.Direction * alpha;
            intersect.HitPrimitive = this;
            // Now set v equal to returned position relative to the center
            v = intersect.HitPoint - this.center;
            float vdotuA = v * this.axisA;
            float vdotuB = v * this.axisB;
            float uCoord = 0;
            float vCoord = 0;

            switch (hitSurface)
            {
            case HitPrimitive.TopPlane:     // Top surface
                intersect.Normal = this.top.Normal;
                // Calculate U-V values for texture coordinates
                uCoord = 0.5f * (1.0f - vdotuA);
                vCoord = 0.5f * (1.0f + vdotuB);
                break;

            case HitPrimitive.BottomPlane:     // Bottom face
                intersect.Normal = this.bottom.Normal;
                // Calculate U-V values for texture coordinates
                uCoord = 0.5f * (1.0f + vdotuA);
                vCoord = 0.5f * (1.0f + vdotuB);
                break;

            case HitPrimitive.Cylinder:     // Cylinder's side
                intersect.Normal = ((vdotuA * this.axisA) + (vdotuB * this.axisB));
                intersect.Normal.Normalize();
                // Calculate u-v coordinates for texture mapping (in range[0,1]x[0,1])
                uCoord = (float)(Math.Atan2(vdotuB, vdotuA) / (Math.PI + Math.PI) + 0.5);
                vCoord = ((v * this.centralAxis) + this.halfHeight) * 1.0f / this.height;
                break;
            }
            if (this.material != null && this.material.IsTexturized)
            {
                //int widthTex = this.material.Texture.Width - 1;
                //int heightTex = this.material.Texture.Height - 1;
                //this.material.Color = this.material.Texture.GetPixel((int)(uCoord * widthTex), (int)(vCoord * heightTex));
                intersect.CurrentTextureCoordinate.U = uCoord;
                intersect.CurrentTextureCoordinate.V = vCoord;
            }
            return(true);
        }