private void Render() { Array.Clear(camera.depthBuffer, 0, camera.depthBuffer.Length); //Console.WriteLine(transform.Rotation.RotateVector3(obj.transform.Location - camPos)); fShader = (fShader ?? FlatShader); vShader = (vShader ?? new VertexShaderDelegate((x) => { })); for (int face = 0; face < mesh.faces.GetLength(0); face++) { float dot; dot = Vector3.Dot(mesh.faceNormals[face], -camera.transform.Forward); if (dot < 0) //Back face culling { continue; } //Region vertex shader camera.vertex.location = mesh.vertices[mesh.faces[face, 0]] + object3D.transform.Location; camera.vertex.objectPos = object3D.transform.Location; camera.vertex.camera = camera; vShader(camera.vertex); camera.vert1 = camera.transform.Rotation.Conjugate.RotateVector3(camera.vertex.location - camera.transform.Location); camera.vertex.location = mesh.vertices[mesh.faces[face, 1]] + object3D.transform.Location; camera.vertex.objectPos = object3D.transform.Location; camera.vertex.camera = camera; vShader(camera.vertex); camera.vert2 = camera.transform.Rotation.Conjugate.RotateVector3(camera.vertex.location - camera.transform.Location); camera.vertex.location = mesh.vertices[mesh.faces[face, 2]] + object3D.transform.Location; camera.vertex.objectPos = object3D.transform.Location; camera.vertex.camera = camera; vShader(camera.vertex); camera.vert3 = camera.transform.Rotation.Conjugate.RotateVector3(camera.vertex.location - camera.transform.Location); //End region vertex shader camera.e1.x = (camera.projectionDistance * camera.vert1.x) / camera.vert1.y; //Using similar triangles to project the verts onto the camera plane camera.e1.z = (camera.projectionDistance * camera.vert1.z) / camera.vert1.y; camera.e2.x = (camera.projectionDistance * camera.vert2.x) / camera.vert2.y; camera.e2.z = (camera.projectionDistance * camera.vert2.z) / camera.vert2.y; camera.e3.x = (camera.projectionDistance * camera.vert3.x) / camera.vert3.y; camera.e3.z = (camera.projectionDistance * camera.vert3.z) / camera.vert3.y; camera.e1.y = camera.vert1.y; camera.e2.y = camera.vert2.y; //Don't change e.y because we will use it for z-buffering later camera.e3.y = camera.vert3.y; camera.e1.x *= camera.screenNormCoeffX; camera.e1.z *= camera.screenNormCoeffZ; //Bound x and z to the range [-1,1] camera.e2.x *= camera.screenNormCoeffX; camera.e2.z *= camera.screenNormCoeffZ; camera.e3.x *= camera.screenNormCoeffX; camera.e3.z *= camera.screenNormCoeffZ; //camera.projectedTriangle.v0 = new Vector2(camera.e1.x, camera.e1.z); //camera.projectedTriangle.v1 = new Vector2(camera.e2.x, camera.e2.z); //camera.projectedTriangle.v2 = new Vector2(camera.e3.x, camera.e3.z); camera.projectedTriangle.z0 = camera.e1.y; camera.projectedTriangle.z1 = camera.e2.y; camera.projectedTriangle.z2 = camera.e3.y; camera.projectedTriangle.uv0 = mesh.uvcoords[mesh.uvs[face, 0]]; camera.projectedTriangle.uv1 = mesh.uvcoords[mesh.uvs[face, 1]]; camera.projectedTriangle.uv2 = mesh.uvcoords[mesh.uvs[face, 2]]; camera.projectedTriangle.vn0 = mesh.vertexNormalCoords[mesh.vertexNormals[face, 0]]; camera.projectedTriangle.vn1 = mesh.vertexNormalCoords[mesh.vertexNormals[face, 1]]; camera.projectedTriangle.vn2 = mesh.vertexNormalCoords[mesh.vertexNormals[face, 2]]; //New stuff: still need a solution to near/far clip camera.projectedTriangle.v0 = new Vector2(camera.renderWidth / 2f + (camera.e1.x * camera.normToScreen.x), camera.renderHeight / 2f + (camera.e1.z * camera.normToScreen.z)); camera.projectedTriangle.v1 = new Vector2(camera.renderWidth / 2f + (camera.e2.x * camera.normToScreen.x), camera.renderHeight / 2f + (camera.e2.z * camera.normToScreen.z)); camera.projectedTriangle.v2 = new Vector2(camera.renderWidth / 2f + (camera.e3.x * camera.normToScreen.x), camera.renderHeight / 2f + (camera.e3.z * camera.normToScreen.z)); DrawClipTriangle(camera.projectedTriangle, b, camera.depthBuffer, mesh.faceNormals[face], fShader); } }
private void DrawClipTriangle(Triangle tri, DirectBitmap b, float[] depthBuffer, Vector3 normal, FragmentShaderDelegate frag) { Fragment fragment = new Fragment(); float zBuf; int padding = 5; int minX = int.MaxValue, maxX = int.MinValue, minY = int.MaxValue, maxY = int.MinValue; foreach (Vector2 v in tri.Points) //Get bounding box { if (v.x > maxX) { maxX = (int)(v.x + 1);//Round up } if (v.x < minX) { minX = (int)(v.x); } if (v.y > maxY) { maxY = (int)(v.y + 1); } if (v.y < minY) { minY = (int)(v.y); } } if (maxX > camera.renderWidth) { maxX = camera.renderWidth; } if (minX < 0) { minX = 0; } if (maxY > camera.renderHeight) { maxY = camera.renderHeight; } if (minY < 0) { minY = 0; } Vector2 pt = new Vector2(); maxX = (maxX + padding > camera.renderWidth - 1 ? camera.renderWidth - 1 : maxX + padding); maxY = (maxY + padding > camera.renderHeight - 1 ? camera.renderHeight - 1 : maxY + padding); minX = (minX - padding < 0 ? 0 : minX - padding); minY = (minY - padding < 0 ? 0 : minY - padding); float z; for (int i = minX; i < maxX; i++) { for (int j = minY + 1; j <= maxY; j++) { pt.x = i + 0.5f; pt.y = j + 0.5f; Vector3 baryCoords = tri.GetBarycentricCoordinates(pt, out bool inside); if (inside) { //Do some interpolation with the z-buffer here z = tri.ZAt(baryCoords); zBuf = depthBuffer[(i) + (camera.renderHeight * (camera.renderHeight - j))]; if (zBuf == 0 || z < zBuf) { fragment.uv = tri.UVAt(baryCoords); fragment.normal = tri.NormalAt(baryCoords); fragment.color = Color.HotPink; fragment.triangle = tri; fragment.faceNormal = normal; fragment.camera = camera; fragment.thisMesh = mesh; fragment.x = i; fragment.y = j; fragment.z = z; frag(fragment); b.SetPixel(fragment.x, camera.renderHeight - fragment.y, fragment.color); depthBuffer[(fragment.x) + (camera.renderHeight * (camera.renderHeight - fragment.y))] = fragment.z; } } } } }