float dist(vec3 p, vec3 plane_p, vec3 plane_n)

    {
        vec3 n = RenderMath.Vector_Normalize(p);

        return(plane_n.x * p.x + plane_n.y * p.y + plane_n.z * p.z - RenderMath.Vector_DotProduct(plane_n, plane_p));
    }
    vec3 Vector_IntersectPlane(vec3 plane_p, vec3 plane_n, vec3 lineStart, vec3 lineEnd)
    {
        plane_n = RenderMath.Vector_Normalize(plane_n);
        float plane_d         = -RenderMath.Vector_DotProduct(plane_n, plane_p);
        float ad              = RenderMath.Vector_DotProduct(lineStart, plane_n);
        float bd              = RenderMath.Vector_DotProduct(lineEnd, plane_n);
        float t               = (-plane_d - ad) / (bd - ad);
        vec3  lineStartToEnd  = lineEnd - lineStart;
        vec3  lineToIntersect = lineStartToEnd * t;

        return(lineStart + lineToIntersect);
    }
    void RenderInit()
    {
        objMesh = new CustomMesh(null, null);
        if (objMesh.loadFromObjectFile(Application.dataPath + objPath))
        {
            Debug.Log(".obj mesh successfuly loaded.");
        }
        else
        {
            Debug.LogError(".obj mesh failed to import.");
        }
        objMesh.position = new vec3(0, 0, 5);
        objMesh.rotation = new vec3(0, 0, 0);
        float fNear        = 0.1f;
        float fFar         = 1000.0f;
        float fFov         = 60f;
        float fAspectRatio = (float)height / (float)width;

        projMat = RenderMath.Matrix_MakeProjection(fFov, fAspectRatio, fNear, fFar);
    }
Example #4
0
        public static Triangle[] ClipTriangleToPlane(Vector3d planeP, Vector3d planeN, Triangle tri)
        {
            planeN = planeN.Normalized();

            List <Vector3d> outsidePoints = new List <Vector3d>(3);
            List <Vector3d> insidePoints  = new List <Vector3d>(3);
            List <Vector2d> outsideTex    = new List <Vector2d>(3);
            List <Vector2d> insideTex     = new List <Vector2d>(3);


            // find if points are inside or outside of the plane
            float planePN = Vector3d.DotProduct(planeN, planeP);

            for (int i = 0; i < tri.p.Length; i++)
            {
                // signed min distance from point to plane
                float d = Vector3d.DotProduct(tri.p[i], planeN) - planePN;

                if (d >= 0)
                {
                    insidePoints.Add(tri.p[i]);
                    insideTex.Add(tri.uv[i]);
                }
                else
                {
                    outsidePoints.Add(tri.p[i]);
                    outsideTex.Add(tri.uv[i]);
                }
            }

            // break input triangle if needed

            if (insidePoints.Count == 0)
            {
                // all points lie outside the plane
                // no new triangles are generated. retun empty array
                return(new Triangle[0]);
            }
            if (insidePoints.Count == 3)
            {
                // all points are in plane
                // original triangle would not be changed
                return(new[] { tri });
            }

            Triangle newTri1 = new Triangle();

            newTri1.SetColor(tri.Color);
            newTri1.Normal = tri.Normal;

            float t; // how much of a edge was cut in range of [0; 1]

            if (insidePoints.Count == 1 && outsidePoints.Count == 2)
            {
                // other two points are outside of the plane so set them to be at intersect position
                // the one inside point is valid
                newTri1.p[0]  = insidePoints[0];
                newTri1.uv[0] = insideTex[0];

                newTri1.p[1]  = RenderMath.LineIntersectPlane(planeP, planeN, insidePoints[0], outsidePoints[0], out t);
                newTri1.uv[1] = t * (outsideTex[0] - insideTex[0]);

                newTri1.p[2]  = RenderMath.LineIntersectPlane(planeP, planeN, insidePoints[0], outsidePoints[1], out t);
                newTri1.uv[2] = t * (outsideTex[1] - insideTex[0]);

                if (visualiseClipping)
                {
                    newTri1.SetColor(Colors.Green);
                }

                // ret new triangle
                return(new[] { newTri1 });
            }

            if (insidePoints.Count == 2 && outsidePoints.Count == 1)
            {
                // if two points are inside and one outside
                // quad should be formed as two new triangles

                Triangle newTri2 = new Triangle();

                // the two inside points are valid
                newTri1.p[0]  = insidePoints[0];
                newTri1.uv[0] = insideTex[0];

                newTri1.p[1]  = insidePoints[1];
                newTri1.uv[1] = insideTex[1];

                newTri1.p[2]  = RenderMath.LineIntersectPlane(planeP, planeN, insidePoints[0], outsidePoints[0], out t);
                newTri1.uv[1] = t * (outsideTex[0] - insideTex[0]);

                if (visualiseClipping)
                {
                    newTri1.SetColor(Colors.GreenYellow);
                }

                // other two points are outside of the plane so set them to be at intersect point
                newTri2.p[0]  = insidePoints[1];
                newTri1.uv[0] = insideTex[1];

                newTri2.p[1]  = newTri1.p[2];
                newTri1.uv[1] = newTri1.uv[1];

                newTri2.p[2]  = RenderMath.LineIntersectPlane(planeP, planeN, insidePoints[1], outsidePoints[0], out t);
                newTri1.uv[2] = t * (outsideTex[0] - insideTex[1]);


                newTri2.SetColor(tri.Color);
                newTri2.Normal = tri.Normal;

                if (visualiseClipping)
                {
                    newTri2.SetColor(Colors.LightGreen);
                }

                // ret new triangleS
                return(new[] { newTri1, newTri2 });
            }

            throw new Exception("Wrong triangle clipping"); // we'll never get there
        }
Example #5
0
        private void BeginRendering()
        {
            Thread.Sleep(1000);
            var renderer = new WorldRenderer(ClientRectangle.Width, ClientRectangle.Height);

            Cursor.Hide();
            var    center_c     = new Point(Width / 2, Height / 2);
            var    center_s     = PointToScreen(center_c);
            var    lastFrame    = DateTime.Now;
            Thread renderThread = new Thread(() =>
            {
                Stopwatch watch = new Stopwatch();
                while (true)
                {
                    var deltatime = (float)(DateTime.Now - lastFrame).TotalSeconds * 5;
                    lastFrame     = DateTime.Now;

                    watch.Start();
                    var img = renderer.RenderWorld();
                    if (IsDisposed)
                    {
                        Environment.Exit(0);
                        return;
                    }
                    Invoke((MethodInvoker)(delegate
                    {
                        BackgroundImage = (Image)img.Clone();
                        long fps = watch.ElapsedMilliseconds;
                        var p = PointToClient(MousePosition);

                        var dx = (p.X - center_c.X) / 2;
                        var dy = (p.Y - center_c.Y) / 2;
                        StatsLabel.Text = "FrameTime = " + watch.ElapsedMilliseconds.ToString() + "ms (" + (1000 / fps) + " fps)      " + dx + "      " + dy;
                        RayCraftGame.Instance.Player.Yaw += (dx * 2) * deltatime;
                        RayCraftGame.Instance.Player.Pitch += (dy * 2) * deltatime;
                        if (RayCraftGame.Instance.Player.Pitch > 90)
                        {
                            RayCraftGame.Instance.Player.Pitch = 90;
                        }
                        if (RayCraftGame.Instance.Player.Pitch < -90)
                        {
                            RayCraftGame.Instance.Player.Pitch = -90;
                        }
                        if (w_down)
                        {
                            RayCraftGame.Instance.Player.PosX += -Math.Sin(RenderMath.ToRadians(-RayCraftGame.Instance.Player.Yaw)) * deltatime;
                            RayCraftGame.Instance.Player.PosZ += -Math.Cos(RenderMath.ToRadians(-RayCraftGame.Instance.Player.Yaw)) * deltatime;
                        }
                        if (s_down)
                        {
                            RayCraftGame.Instance.Player.PosX += Math.Sin(RenderMath.ToRadians(-RayCraftGame.Instance.Player.Yaw)) * deltatime;
                            RayCraftGame.Instance.Player.PosZ += Math.Cos(RenderMath.ToRadians(-RayCraftGame.Instance.Player.Yaw)) * deltatime;
                        }
                        if (a_down)
                        {
                            RayCraftGame.Instance.Player.PosX += Math.Sin(RenderMath.ToRadians(-(RayCraftGame.Instance.Player.Yaw + 90))) * deltatime;
                            RayCraftGame.Instance.Player.PosZ += Math.Cos(RenderMath.ToRadians(-(RayCraftGame.Instance.Player.Yaw + 90))) * deltatime;
                        }
                        if (d_down)
                        {
                            RayCraftGame.Instance.Player.PosX += Math.Sin(RenderMath.ToRadians(-(RayCraftGame.Instance.Player.Yaw - 90))) * deltatime;
                            RayCraftGame.Instance.Player.PosZ += Math.Cos(RenderMath.ToRadians(-(RayCraftGame.Instance.Player.Yaw - 90))) * deltatime;
                        }
                        if (shift_down)
                        {
                            RayCraftGame.Instance.Player.PosY -= deltatime;
                        }
                        if (space_down)
                        {
                            RayCraftGame.Instance.Player.PosY += deltatime;
                        }
                        Cursor.Position = center_s;
                    }));

                    try
                    {
                        watch.Reset();
                    }
                    catch
                    {
                    }
                }
            });

            renderThread.Start();
        }
    int Triangle_ClipAgainstPlane(vec3 plane_p, vec3 plane_n, RenderTriangle in_tri, ref RenderTriangle out_tri1, ref RenderTriangle out_tri2)
    {
        // Make sure plane normal is indeed normal
        plane_n = RenderMath.Vector_Normalize(plane_n);

        // Return signed shortest distance from point to plane, plane normal must be normalised

        // Create two temporary storage arrays to classify points either side of plane
        // If distance sign is positive, point lies on "inside" of plane
        vec3[] inside_points = new vec3[3]; int nInsidePointCount = 0;
        vec3[] outside_points = new vec3[3]; int nOutsidePointCount = 0;

        // Get signed distance of each point in triangle to plane
        float d0 = dist(in_tri.points[0], plane_p, plane_n);
        float d1 = dist(in_tri.points[1], plane_p, plane_n);
        float d2 = dist(in_tri.points[2], plane_p, plane_n);

        if (d0 >= 0)
        {
            inside_points[nInsidePointCount++] = in_tri.points[0];
        }
        else
        {
            outside_points[nOutsidePointCount++] = in_tri.points[0];
        }
        if (d1 >= 0)
        {
            inside_points[nInsidePointCount++] = in_tri.points[1];
        }
        else
        {
            outside_points[nOutsidePointCount++] = in_tri.points[1];
        }
        if (d2 >= 0)
        {
            inside_points[nInsidePointCount++] = in_tri.points[2];
        }
        else
        {
            outside_points[nOutsidePointCount++] = in_tri.points[2];
        }

        // Now classify triangle points, and break the input triangle into
        // smaller output triangles if required. There are four possible
        // outcomes...

        if (nInsidePointCount == 0)
        {
            // All points lie on the outside of plane, so clip whole triangle
            // It ceases to exist

            return(0); // No returned triangles are valid
        }

        if (nInsidePointCount == 3)
        {
            // All points lie on the inside of plane, so do nothing
            // and allow the triangle to simply pass through
            out_tri1 = in_tri;

            return(1); // Just the one returned original triangle is valid
        }

        if (nInsidePointCount == 1 && nOutsidePointCount == 2)
        {
            // Triangle should be clipped. As two points lie outside
            // the plane, the triangle simply becomes a smaller triangle

            // Copy appearance info to new triangle
            out_tri1.lightValue = in_tri.lightValue;
            out_tri1.faceColor  = in_tri.faceColor;
            // The inside point is valid, so keep that...
            out_tri1.points[0] = inside_points[0];

            // but the two new points are at the locations where the
            // original sides of the triangle (lines) intersect with the plane
            out_tri1.points[1] = Vector_IntersectPlane(plane_p, plane_n, inside_points[0], outside_points[0]);
            out_tri1.points[2] = Vector_IntersectPlane(plane_p, plane_n, inside_points[0], outside_points[1]);

            return(1); // Return the newly formed single triangle
        }

        if (nInsidePointCount == 2 && nOutsidePointCount == 1)
        {
            // Triangle should be clipped. As two points lie inside the plane,
            // the clipped triangle becomes a "quad". Fortunately, we can
            // represent a quad with two new triangles

            // Copy appearance info to new triangles
            out_tri1.lightValue = in_tri.lightValue;
            out_tri1.faceColor  = in_tri.faceColor;
            out_tri2.lightValue = in_tri.lightValue;
            out_tri2.faceColor  = in_tri.faceColor;



            // The first triangle consists of the two inside points and a new
            // point determined by the location where one side of the triangle
            // intersects with the plane
            out_tri1.points[0] = inside_points[0];
            out_tri1.points[1] = inside_points[1];
            out_tri1.points[2] = Vector_IntersectPlane(plane_p, plane_n, inside_points[0], outside_points[0]);

            // The second triangle is composed of one of he inside points, a
            // new point determined by the intersection of the other side of the
            // triangle and the plane, and the newly created point above
            out_tri2.points[0] = inside_points[1];
            out_tri2.points[1] = out_tri1.points[2];
            out_tri2.points[2] = Vector_IntersectPlane(plane_p, plane_n, inside_points[1], outside_points[0]);

            return(2); // Return two newly formed triangles which form a quad
        }
        return(0);
    }
    void RenderCustomMesh(CustomMesh renderMesh)
    {
        vec3 rotation = renderMesh.rotation * Mathf.Deg2Rad;

        rotMat = RenderMath.Matrix_MakeRotation(new vec3(rotation.x, 0, rotation.z));
        RenderTriangle triProjected, triTransformed, triViewed;
        // float outputColor = 0f;
        Matrix4x4 transMat = RenderMath.Matrix_MakeTranslation(renderMesh.position);
        Matrix4x4 worldMat = RenderMath.Matrix_MakeIdentity();

        worldMat = rotMat;
        worldMat = RenderMath.Matrix_MultiplyMatrix(worldMat, transMat);
        vec3      vUp          = new vec3(0, 1, 0);
        vec3      vTarget      = new vec3(0, 0, 1);
        Matrix4x4 cameraRotMat = RenderMath.Matrix_MakeRotationY(cameraRotation.y);

        vLookDir = RenderMath.Matrix_MultiplyVector(vTarget, cameraRotMat);
        vTarget  = vCamera + vLookDir;
        Matrix4x4 cameraMat = RenderMath.Matrix_PointAt(vCamera, vTarget, vUp);
        Matrix4x4 viewMat   = RenderMath.Matrix_QuickInverse(cameraMat);

        for (int i = 0; i < renderMesh.tris.Count; i += 3)
        {
            triProjected             = new RenderTriangle();
            triTransformed           = new RenderTriangle();
            triViewed                = new RenderTriangle();
            triTransformed.points[0] = RenderMath.Matrix_MultiplyVector(renderMesh.verts[renderMesh.tris[i]], worldMat);
            triTransformed.points[1] = RenderMath.Matrix_MultiplyVector(renderMesh.verts[renderMesh.tris[i + 1]], worldMat);
            triTransformed.points[2] = RenderMath.Matrix_MultiplyVector(renderMesh.verts[renderMesh.tris[i + 2]], worldMat);


            // triTransformed.Log();


            vec3 normal, line1, line2;
            line1  = triTransformed.points[1] - triTransformed.points[0];
            line2  = triTransformed.points[2] - triTransformed.points[0];
            normal = RenderMath.Vector_CrossProduct(line1, line2);
            normal = RenderMath.Vector_Normalize(normal);
            //Debug.DrawRay(new Vector3(triTransformed.averagePos.x,triTransformed.averagePos.y,triTransformed.averagePos.z), new Vector3(normal.x,normal.y,normal.z)); //show mesh normals in scene view;
            if (RenderMath.Vector_DotProduct(normal, triTransformed.points[0] - vCamera) < 0f)
            {
                vec3 light_direction = new vec3(0, 1, -1);
                light_direction      = RenderMath.Vector_Normalize(light_direction);
                triViewed.lightValue = Mathf.Max(0.1f, RenderMath.Vector_DotProduct(light_direction, normal));
                triViewed.faceColor  = (renderMesh.triColors.Count * 3 == renderMesh.tris.Count ? renderMesh.triColors[i / 3] : Color.white);



                triViewed.points[0] = RenderMath.Matrix_MultiplyVector(triTransformed.points[0], viewMat);
                triViewed.points[1] = RenderMath.Matrix_MultiplyVector(triTransformed.points[1], viewMat);
                triViewed.points[2] = RenderMath.Matrix_MultiplyVector(triTransformed.points[2], viewMat);

                int nClippedTriangles    = 0;
                RenderTriangle[] clipped = new RenderTriangle[2];
                clipped[0]        = new RenderTriangle();
                clipped[1]        = new RenderTriangle();
                nClippedTriangles = Triangle_ClipAgainstPlane(new vec3(0.0f, 0.0f, 0.1f), new vec3(0.0f, 0.0f, 1.0f), triViewed, ref clipped[0], ref clipped[1]);

                for (int n = 0; n < nClippedTriangles; n++)
                {
                    triProjected.lightValue = clipped[n].lightValue;
                    triProjected.faceColor  = clipped[n].faceColor;
                    triProjected.points[0]  = RenderMath.Matrix_MultiplyVector(triViewed.points[0], projMat);
                    triProjected.points[1]  = RenderMath.Matrix_MultiplyVector(triViewed.points[1], projMat);
                    triProjected.points[2]  = RenderMath.Matrix_MultiplyVector(triViewed.points[2], projMat);

                    triProjected.points[0] = RenderMath.Vector_Normalize(triProjected.points[0]);
                    triProjected.points[1] = RenderMath.Vector_Normalize(triProjected.points[1]);
                    triProjected.points[2] = RenderMath.Vector_Normalize(triProjected.points[2]);

                    /*
                     * triProjected.points[0].x *= -1.0f;
                     * triProjected.points[1].x *= -1.0f;
                     * triProjected.points[2].x *= -1.0f;
                     * triProjected.points[0].y *= -1.0f;
                     * triProjected.points[1].y *= -1.0f;
                     * triProjected.points[2].y *= -1.0f;
                     */
                    vec3 vOffsetView = new vec3(1, 1, 0);

                    triProjected.points[0] += vOffsetView;
                    triProjected.points[1] += vOffsetView;
                    triProjected.points[2] += vOffsetView;

                    triProjected.points[0].x *= 0.5f * (float)width;
                    triProjected.points[0].y *= 0.5f * (float)height;
                    triProjected.points[1].x *= 0.5f * (float)width;
                    triProjected.points[1].y *= 0.5f * (float)height;
                    triProjected.points[2].x *= 0.5f * (float)width;
                    triProjected.points[2].y *= 0.5f * (float)height;

                    vecTrianglesToRaster.Add(triProjected);
                }
            }
        }
    }