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); }
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 }
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); } } } }