Ejemplo n.º 1
0
 public IntersectionResult(
     Mesh mesh,
     Triangle triangle,
     float u,
     float v,
     float d,
     Vector3 worldPosition)
 {
     this.mesh = mesh;
     this.triangle = triangle;
     this.u = u;
     this.v = v;
     this.d = d;
     this.worldPosition = worldPosition;
 }
Ejemplo n.º 2
0
        private void FindVertices(NodeContent node)
        {
            MeshContent mesh = node as MeshContent;
            if (mesh != null)
            {
                List<Triangle> triangles = new List<Triangle>();

                Matrix absoluteTransform = mesh.AbsoluteTransform;
                Matrix absoluteTransformInvertTranspose = Matrix.Transpose(Matrix.Invert(absoluteTransform));
                foreach (GeometryContent geometry in mesh.Geometry)
                {
                    VertexChannel texCoords = null;
                    if (geometry.Vertices.Channels.Contains(VertexChannelNames.TextureCoordinate(0)))
                    {
                        texCoords = geometry.Vertices.Channels[VertexChannelNames.TextureCoordinate(0)];
                    }
                    else if (this.UseTexture)
                    {
                        throw new InvalidContentException("Model is built with UseTexure but does not contain any TextureCoordinates.");
                    }

                    VertexChannel normals = null;
                    if(geometry.Vertices.Channels.Contains(VertexChannelNames.Normal(0)))
                    {
                        normals = geometry.Vertices.Channels[VertexChannelNames.Normal(0)];
                    }

                    VertexChannel colors = null;
                    if (geometry.Vertices.Channels.Contains(VertexChannelNames.Color(0)))
                    {
                        colors = geometry.Vertices.Channels[VertexChannelNames.Color(0)];
                    }

                    BasicMaterialContent basicMaterial = geometry.Material as BasicMaterialContent;
                    int triangleIndex = 0;
                    for (int i = 0; i < geometry.Indices.Count; i += 3)
                    {
                        Vector3 v1 = geometry.Vertices.Positions[geometry.Indices[i]];
                        Vector3 v2 = geometry.Vertices.Positions[geometry.Indices[i + 1]];
                        Vector3 v3 = geometry.Vertices.Positions[geometry.Indices[i + 2]];

                        Vector3 n1 = (Vector3)normals[geometry.Indices[i]];
                        Vector3 n2 = (Vector3)normals[geometry.Indices[i + 1]];
                        Vector3 n3 = (Vector3)normals[geometry.Indices[i + 2]];

                        Vector3.Transform(ref v1, ref absoluteTransform, out v1);
                        Vector3.Transform(ref v2, ref absoluteTransform, out v2);
                        Vector3.Transform(ref v3, ref absoluteTransform, out v3);

                        // I have no idea why I have to do this. If I do not, the Z and Y components of all normals are "switched" around.
                        //Vector3.Transform(ref n1, ref normalTransform, out n1);
                        //Vector3.Transform(ref n2, ref normalTransform, out n2);
                        //Vector3.Transform(ref n3, ref normalTransform, out n3);

                        // I am suspecting that what I suspected above is wrong. I mustve confused myself with weird models.
                        // It seems like the normals should be transformed by the absoluteTransfom;
                        //---
                        // SCRATCH THAT. The normals should be transformed by the transpose of the inverse of the absolute transform :D
                        Vector3.Transform(ref n1, ref absoluteTransformInvertTranspose, out n1);
                        Vector3.Transform(ref n2, ref absoluteTransformInvertTranspose, out n2);
                        Vector3.Transform(ref n3, ref absoluteTransformInvertTranspose, out n3);

                        n1.Normalize();
                        n2.Normalize();
                        n3.Normalize();

                        Vector3 edge1, edge2, surfaceNormal;
                        Vector3.Subtract(ref v2, ref v1, out edge1);
                        Vector3.Subtract(ref v3, ref v1, out edge2);
                        Vector3.Cross(ref edge2, ref edge1, out surfaceNormal);
                        surfaceNormal.Normalize();

                        Triangle triangle = new Triangle();
                        triangle.v1 = v1;
                        triangle.v2 = v2;
                        triangle.v3 = v3;
                        if (texCoords != null)
                        {
                            triangle.uv1 = (Vector2)texCoords[geometry.Indices[i]];
                            triangle.uv2 = (Vector2)texCoords[geometry.Indices[i + 1]];
                            triangle.uv3 = (Vector2)texCoords[geometry.Indices[i + 2]];
                        }
                        triangle.n1 = n1;
                        triangle.n2 = n2;
                        triangle.n3 = n3;
                        triangle.i1 = geometry.Indices[i];
                        triangle.i2 = geometry.Indices[i + 1];
                        triangle.i3 = geometry.Indices[i + 2];
                        triangle.id = triangleIndex++;
                        triangle.surfaceNormal = surfaceNormal;

                        if (this.UseVertexColors && colors != null)
                            triangle.color = ((Color)colors[geometry.Indices[i]]).ToVector4();
                        else
                            triangle.color = this.DiffuseColor.ToVector4();
                        triangles.Add(triangle);
                    }

                }

                BoundingBox box = this.CreateBoundingBox(triangles);
                Mesh tracerMesh = new Mesh(triangles.ToArray(), this.material, box);
                this.meshes.Add(tracerMesh);
            }

            foreach (NodeContent child in node.Children)
            {
                this.FindVertices(child);
            }
        }
Ejemplo n.º 3
0
        public void CastRay(ref Ray ray, out Color resultColor, int iteration, Triangle origin, Mesh ignoreObject, float currentRefIndex)
        {
            resultColor = Color.White;

            RayTraceProject.Spatial.IntersectionResult? nullableResult;

            if (CurrentScene.GetRayIntersection(ref ray, out nullableResult, origin, ignoreObject))
            {
                RayTraceProject.Spatial.IntersectionResult result = (RayTraceProject.Spatial.IntersectionResult)nullableResult;
                Material material = result.mesh.MeshMaterial;
                Vector3 fragmentNormal;

                // Calculate intersection normal
                if (material.InterpolateNormals)
                {
                    Vector3 n1 = result.triangle.n2 - result.triangle.n1;
                    Vector3 n2 = result.triangle.n3 - result.triangle.n1;
                    fragmentNormal = result.triangle.n1 + (n1 * result.u) + (n2 * result.v);
                    fragmentNormal.Normalize();

                }
                else
                {
                    fragmentNormal = result.triangle.surfaceNormal;
                }

                // Calculate light
                Vector3 lightResult = Vector3.Zero;
                for (int i = 0; i < this.lights.Count; i++)
                {
                    float lightAmount = this.IsLightPathObstructed(result, this.lights[i]);
                    if (lightAmount != 1f)
                    {
                        lightResult += this.lights[i].GetLightForFragment(result.worldPosition, fragmentNormal) * (1.0f - lightAmount);
                    }
                }
                addRayPoints(ray.Position, result.worldPosition, Color.White);

                if (iteration < this.MaxReflections)
                {
                    Ray r = new Ray();
                    r.Position = result.worldPosition;
                    r.Direction = Vector3.Reflect(ray.Direction, fragmentNormal);
                    r.Direction.Normalize();

                    Color reflectionColor;

                    // If the triangle is part of convex geometry, there is no need to check for collisions for this next ray.

                    if (result.triangle.convexGeometry)
                        this.CastRay(ref r, out reflectionColor, iteration + 1, result.triangle, result.mesh, currentRefIndex);
                    else
                        this.CastRay(ref r, out reflectionColor, iteration + 1, result.triangle, null, currentRefIndex);

                    Vector3 surfaceColor;

            #if DEBUG_NORMALS
                    resultColor = new Color(fragmentNormal);
            #elif DEBUG_CONVEXFLAG
                    resultColor = result.triangle.convexGeometry ? Color.Green : Color.Red;
            #else
                    if (material.UseTexture)
                    {
                        Vector2 uv1 = (result.triangle.uv2) - (result.triangle.uv1);
                        Vector2 uv2 = (result.triangle.uv3) - (result.triangle.uv1);
                        Vector2 interpolatedUV = (result.triangle.uv1) + (uv1 * result.u) + (uv2 * result.v);

                        material.LookupUV(interpolatedUV, this.AddressMode, this.TextureFiltering, out surfaceColor);
                    }
                    else
                    {
                        surfaceColor.X = result.triangle.color.X;
                        surfaceColor.Y = result.triangle.color.Y;
                        surfaceColor.Z = result.triangle.color.Z;
                    }

                    //addRayPoints(ray.Position, result.worldPosition, Color.White );
                    Vector3 colorVector = Vector3.Lerp(reflectionColor.ToVector3(), surfaceColor, 1.0f - material.Reflectiveness) * lightResult;

                    if (material.Transparent)
                    {
                        ////addRayPoints(ray.Position, result.worldPosition, Color.White);
                        //float theta1;

                        //float n1, n2;

                        //if (currentRefIndex == material.RefractionIndex)
                        //{
                        //    // Ray is inside material. Exiting to vacuum.
                        //    n1 = currentRefIndex;
                        //    n2 = 1.0f; // Index of vacuum.
                        //    //theta1 = Math.Abs(Vector3.Dot(fragmentNormal, ray.Direction));
                        //    theta1 = 1 - Vector3.Dot(fragmentNormal, ray.Direction);
                        //    //addRayPoints(ray.Position, ray.Position + (ray.Direction * 10), Color.Red);
                        //    //theta1 = -theta1;

                        //}
                        //else
                        //{
                        //    n1 = currentRefIndex;
                        //    n2 = material.RefractionIndex;

                        //    theta1 = 1 - Vector3.Dot(fragmentNormal, -ray.Direction);
                        //}

                        //    //}
                        //    ////// SER DET INTE UT SOM EN SKÅLFORMAD LINS? DEN SKA INVERTERAS!
                        //    // n1 * sin(vinkel1) = n2 * sin(vinkel2)
                        //    // (n1 * sin(vinkel1) / n2 = sin(vinkel2)
                        //    // Jag tror inte jag behöver ta sinus av theta1, det är redan en sine.
                        //float theta2 = n1 * (float)Math.Asin((theta1) / n2);
                        //    //float theta2 = (float)Math.Asin((n1 * theta1) / n2);
                        //    Vector3 refraction;
                        //    if (float.IsNaN(theta1) || float.IsNaN(theta2))
                        //    {
                        //        colorVector = Vector3.UnitZ;
                        //        refraction = ray.Direction;
                        //    }
                        //    else if (theta1 != 0.0f && theta2 != 0.0f)
                        //    {

                        //        //addRayPoints(ray.Position, result.worldPosition, new Color(1, 0, 0));
                        //        Vector3 rotateAxis = Vector3.Cross(fragmentNormal, ray.Direction);
                        //        //addRayPoints(result.worldPosition, result.worldPosition + rotateAxis, Color.Red);
                        //        //addRayPoints(result.worldPosition, result.worldPosition + fragmentNormal, Color.Green);
                        //        Matrix rotateMatrix = Matrix.CreateFromAxisAngle(rotateAxis, theta2);
                        //        refraction = Vector3.Transform(-fragmentNormal, rotateMatrix);

                        //    }
                        //    else
                        //    {
                        //        refraction = ray.Direction;
                        //    }
                        //    ray.Position = result.worldPosition;
                        //    ray.Direction = refraction;
                        //    ray.Direction.Normalize();

                        ////addRayPoints(result.worldPosition, (refraction * 1000), new Color(red, red, red));
                        ////red = (red + (255 / 2)) % 255;
                        //Color refractColor;

                        //this.CastRay(ref ray, out refractColor, iteration + 1, result.triangle, null, n2);
                        ////addRayPoints(ray.Position, ray.Direction * 100, new Color(0, theta1, theta2));
                        //colorVector = Vector3.Lerp(refractColor.ToVector3(), colorVector, result.triangle.color.W);

                        // --- Avkommentera allt ovan.

                        float n1, n2;

                        if (currentRefIndex == material.RefractionIndex)
                        {
                            n1 = 1.0f;
                            n2 = currentRefIndex;
                        }
                        else
                        {
                            n1 = material.RefractionIndex;
                            n2 = 1.0f;
                        }

                        //n1 = 0.9f;
                        //n2 = 1.0f;

                        //ray.Direction = new Vector3(0.707107f, -0.707107f, 0);
                        //fragmentNormal = new Vector3(0, 1, 0);

                        float cos1 = Vector3.Dot(fragmentNormal, -ray.Direction);
                        float cos2 = (float)Math.Sqrt(1 - Math.Pow(n1 / n2, 2.0) * (1 - Math.Pow(cos1, 2.0)));
                        float theta1 = (float)Math.Acos(cos1);

                        float theta2 = (float)Math.Acos(cos2);

                        Vector3 refract;
                        if (cos1 >= 0)
                        {
                            refract = (n1 / n2) * ray.Direction + ((n1 / n2) * cos1 - cos2) * fragmentNormal;
                        }
                        else
                        {
                            refract = (n1 / n2) * ray.Direction - ((n1 / n2) * cos1 - cos2) * fragmentNormal;
                        }

                        ray.Position = result.worldPosition;
                        ray.Direction = refract;
                        ray.Direction.Normalize();

                        Color refractColor;

                        this.CastRay(ref ray, out refractColor, iteration + 1, result.triangle, null, n2);
                        colorVector = Vector3.Lerp(refractColor.ToVector3(), colorVector, result.triangle.color.W);

                        addRayPoints(ray.Position, ray.Direction * 100, Color.Red);
                    }

                    resultColor = new Color(colorVector);
            #endif
                }
                else
                {
                    Vector3 surfaceColor;
                    if (material.UseTexture)
                    {
                        Vector2 uv1 = (result.triangle.uv2) - (result.triangle.uv1);
                        Vector2 uv2 = (result.triangle.uv3) - (result.triangle.uv1);
                        Vector2 interpolatedUV = (result.triangle.uv1) + (uv1 * result.u) + (uv2 * result.v);

                        material.LookupUV(interpolatedUV, this.AddressMode, this.TextureFiltering, out surfaceColor);
                    }
                    else
                    {
                        surfaceColor.X = result.triangle.color.X;
                        surfaceColor.Y = result.triangle.color.Y;
                        surfaceColor.Z = result.triangle.color.Z;
                    }

                    resultColor = new Color(lightResult * surfaceColor);
                }
            }
            else // Ray does not intersect any object.
            {

                resultColor = new Color(Vector3.Zero);

                //addRayPoints(ray.Position, ray.Position + (1000 * ray.Direction));
            }
        }
Ejemplo n.º 4
0
        public bool GetRayIntersection(ref Ray ray, out IntersectionResult? result, Triangle ignoreTriangle, Mesh ignoreObject)
        {
            result = null;

            SortedList<float, List<CubeNode>> cubeoids = new SortedList<float, List<CubeNode>>();
            //SortedDictionary<float, CubeNode> cubeoids = new SortedDictionary<float, CubeNode>();
            this.GetRayCubeNodeIntersections(ref ray, this.root, cubeoids);
            if (cubeoids.Count == 0)
                return false;

            List<List<CubeNode>> intersectedCubeoids = cubeoids.Values.ToList();

            int cubeoidIndex = 0;

            float minDistance = float.MaxValue;
            bool intersectionFound = false;
            Mesh intersectedMesh = null;
            SceneObject intersectedSceneObject = null;
            RayTracerTypeLibrary.MeshOctree.TriangleIntersectionResult? intersectedTriangleResult = null;
            RayTracerTypeLibrary.MeshOctree.TriangleIntersectionResult? triangleResult;

            Vector3 v1, v2, rayDirPosition;
            while (!intersectionFound && cubeoidIndex < cubeoids.Count)
            {
                List<CubeNode> cuboidGroup = intersectedCubeoids[cubeoidIndex++];
                for (int k = 0; k < cuboidGroup.Count; k++)
                {
                    List<ISpatialBody> objects = cuboidGroup[k].containingObjects;

                    for (int i = 0; i < objects.Count; i++)
                    {
                        if (ignoreObject == null || ignoreObject != objects[i])
                        {

                            SceneObject sceneObject = (SceneObject)objects[i];

                            Matrix inverseWorld = sceneObject.InverseWorld;
                            // -- While the below LOOKS like it should work, it does not. Correct solution below!
                            //Ray transformedRay;
                            //Vector3.Transform(ref ray.Position, ref inverseWorld, out transformedRay.Position);
                            //Vector3.Transform(ref ray.Direction, ref inverseWorld, out transformedRay.Direction);
                            //transformedRay.Direction.Normalize();

                            //Vector3 v1 = Vector3.Transform(ray.Position, inverseWorld);
                            //Vector3 v2 = Vector3.Transform(ray.Position + ray.Direction, inverseWorld);
                            Vector3.Add(ref ray.Position, ref ray.Direction, out rayDirPosition);

                            Vector3.Transform(ref ray.Position, ref inverseWorld, out v1);
                            Vector3.Transform(ref rayDirPosition, ref inverseWorld, out v2);
                            Vector3.Subtract(ref v2, ref v1, out rayDirPosition);
                            Ray transformedRay = new Ray(v1, rayDirPosition);
                            transformedRay.Direction.Normalize();

                            for (int meshIndex = 0; meshIndex < sceneObject.Meshes.Count; meshIndex++)
                            {
                                if (sceneObject.Meshes[meshIndex].RayIntersects(ref transformedRay))
                                {
                                    if (sceneObject.Meshes[meshIndex].Octree.GetRayIntersection(ref transformedRay, out triangleResult, ignoreTriangle) &&
                                        triangleResult.Value.d < minDistance)
                                    {
                                        minDistance = triangleResult.Value.d;
                                        intersectedTriangleResult = triangleResult;
                                        intersectedMesh = sceneObject.Meshes[meshIndex];
                                        intersectedSceneObject = sceneObject;
                                        intersectionFound = true;
                                    }

                                    //Triangle[] triangles = sceneObject.Meshes[meshIndex].Triangles;
                                    //// Backface culling IF first triangle (and thus the rest) is transparent. Rewrite this in the future.
                                    //if (sceneObject.Meshes[meshIndex].MeshMaterial.Transparent)
                                    //{
                                    //    for (int j = 0; j < triangles.Length; j++)
                                    //    {
                                    //        if (ignoreTriangle == null || ignoreTriangle != triangles[j])
                                    //        {
                                    //            float currentU, currentV, distance;
                                    //            if (transformedRay.IntersectsTriangle(triangles[j], out currentU, out currentV, out distance) &&
                                    //                distance < minDistance)
                                    //            {
                                    //                minDistance = distance;
                                    //                intersectionU = currentU;
                                    //                intersectionV = currentV;
                                    //                intersectedTriangle = triangles[j];
                                    //                intersectedMesh = sceneObject.Meshes[meshIndex];
                                    //                intersectedSceneObject = sceneObject;
                                    //                // Signal that intersection was found. Remaining objects in this cubeoid will be examined, but no more cubeoids.
                                    //                intersectionFound = true;
                                    //            }
                                    //        }
                                    //    }
                                    //}
                                    //else
                                    //{
                                    //    for (int j = 0; j < triangles.Length; j++)
                                    //    {
                                    //        if (ignoreTriangle == null || ignoreTriangle != triangles[j])
                                    //        {
                                    //            float currentU, currentV, distance;
                                    //            if (transformedRay.IntersectsTriangleBackfaceCulling(triangles[j], out currentU, out currentV, out distance) &&
                                    //                distance < minDistance)
                                    //            {
                                    //                minDistance = distance;
                                    //                intersectionU = currentU;
                                    //                intersectionV = currentV;
                                    //                intersectedTriangle = triangles[j];
                                    //                intersectedMesh = sceneObject.Meshes[meshIndex];
                                    //                intersectedSceneObject = sceneObject;
                                    //                // Signal that intersection was found. Remaining objects in this cubeoid will be examined, but no more cubeoids.
                                    //                intersectionFound = true;
                                    //            }
                                    //        }
                                    //    }
                                    //}

                                }
                            }

                        }
                    }
                }

            }

            if (intersectionFound)
            {
                Vector3 interpolatedPosition;
                Matrix world = intersectedSceneObject.World;
                Vector3 objectSpacePosition = intersectedTriangleResult.Value.objectSpacePosition;
                Vector3.Transform(ref objectSpacePosition, ref world, out interpolatedPosition);

                result = new IntersectionResult(
                    intersectedMesh,
                    intersectedTriangleResult.Value.triangle,
                    intersectedTriangleResult.Value.u,
                    intersectedTriangleResult.Value.v,
                    minDistance,
                    interpolatedPosition);
            }

            return intersectionFound;
        }