public Float3 lerpNormal(Float3 currentValue, Float3 newValue) { if (currentValue == Float3.zero) return newValue; return Float3.lerp(currentValue, newValue, 0.5f).normalize(); }
public Quaternion(float w, Float3 v) { this.w = w; this.x = v.x; this.y = v.y; this.z = v.z; }
public void NoTransformTest() { Float3 p = new Float3(1, 3, 7); Float4x4 M = Float4x4.identity; Assert.AreEqual(p, M.transformPoint(p)); }
public Vertex(Float3 position) { this.position = position; this.normal = Float3.zero; this.color = Color.Black; this.uv = new Float2(0, 0); }
public Float4(Float3 v, float w) { this.x = v.x; this.y = v.y; this.z = v.z; this.w = w; }
public IVertex(Vertex v) { this.position = (Int3)v.position; this.normal = v.normal; this.color = v.color; this.uv = v.uv; }
public void AddTranslationToExistingMatrixTests() { Float3 p = new Float3(0, 0, 1); Float3 t = new Float3(1, 3, 323); Float4x4 X = Float4x4.identity; X.setTranslation(t); Float4x4 minusX = Float4x4.identity; minusX.setTranslation(t.getOpposite()); Assert.AreEqual(p + t, X.transformPoint(p)); Assert.AreEqual(p, minusX.transformPoint(X.transformPoint(p))); }
public void SimpleTranslationTest() { Float3 p = new Float3(1, 3, 7); Float3 t = new Float3(1, 2, 3); Float4x4 M = new Float4x4(1 , 0 , 0 , 0, 0 , 1 , 0 , 0, 0 , 0 , 1 , 0, t.x, t.y, t.z, 1); Float4x4 M2 = Float4x4.getTranslationMatrix(t); Assert.AreEqual(M, M2); Assert.AreEqual(p + t, M.transformPoint(p)); Assert.AreEqual(p + t, M2.transformPoint(p)); }
public void SimpleProjectionTest() { Float3 p = new Float3(2, 4, 2); const float n = 3f; const float f = 100f; const float b = -10; const float t = 10; const float r = 10; const float l = -10; Float4x4 Projection = Float4x4.getProjectionMatrix(n, f, t, b, r, l); Float3 p2 = Projection.transformPoint(new Float3(r, b, n)); Float3 p1 = Projection.transformPoint(p); Assert.IsTrue(p1.x < 1f); }
public static Float3x3 getRotationMatrix(Float3 rotation) { float xAngle = rotation.x; float yAngle = rotation.y; float zAngle = rotation.z; xAngle *= ((float)Math.PI / 180.0f); yAngle *= ((float)Math.PI / 180.0f); zAngle *= ((float)Math.PI / 180.0f); Float3x3 aboutX = new Float3x3(1, 0, 0, 0, (float)Cos(xAngle), (float)Sin(xAngle), 0, (float)(-Sin(xAngle)), (float)Cos(xAngle)); Float3x3 aboutY = new Float3x3((float)Cos(yAngle), 0, (float)(-Sin(yAngle)), 0, 1, 0, (float)Sin(yAngle), 0, (float)Cos(yAngle)); return aboutX * aboutY; }
public Float3 cross(Float3 other) { //c = a cross b //cx = aybz − azby //cy = azbx − axbz //cz = axby − aybx return new Float3(this.y * other.z - this.z * other.y, this.z * other.x - this.x * other.z, this.x * other.y - this.y * other.x); }
public static Float3 lerp(Float3 start, Float3 end, float delta) { return start + (end - start) * delta; }
public void Render(SceneObject sObject, Float3 viewDirection, Float3 lightDirection, bool useProjection = true) { Mesh mesh = sObject.mesh; Color wireFrameColor = Color.LightGreen; RenderType renderType = sObject.material.renderType; // Vertex uniforms // scale matrix Float3x3 S = Float3x3.identity * sObject.uniformScale; // rotation matrix Float3x3 R = Float3x3.getRotationMatrix(sObject.rotation); Float3x3 CombinedLinear = S * R; // translation Float4x4 Tr = Float4x4.identity; Tr.setTranslation(sObject.localPosition); // projection Float4x4 Pr = useProjection ? Float4x4.getProjectionMatrix(10f, 1300f, 1f, 1f) : Float4x4.identity; // BACK FACE CULLING if (backFaceCulling) { for (int i = mesh.Triangles.Count - 1; i >= 0; i--) { Triangle t = mesh.Triangles[i]; Float3 v1 = mesh.Vertices[t[0] - 1].position; Float3 v2 = mesh.Vertices[t[1] - 1].position; Float3 v3 = mesh.Vertices[t[2] - 1].position; Float3 normal = Utils.getTriangleNormalR(v1, v2, v3); // remove faced back triangles if (viewDirection.dot(normal) >= 0) mesh.Triangles.Remove(t); } } // VERTEX SHADER for (int i = 0; i < mesh.Vertices.Count; i++) { Vertex v = mesh.Vertices[i]; // scale var p = v.position.mul(S); // rotate p = p.mul(R); // translate p = Tr.transformPoint(p); // project if(useProjection) p = Pr.transformPoint(p); // TODO: Transforming normals while NON UNIFORM TRANSFORMS v.normal = v.normal.mul(R); // TODO: place to center of screen if(useProjection) v.position = new Float3(p.x * Defaults.WIDTH + Defaults.WIDTH / 2f, p.y * Defaults.HEIGHT + Defaults.HEIGHT / 2f, p.z); else v.position = new Float3(p.x + Defaults.WIDTH / 2f, p.y + Defaults.HEIGHT / 2f, p.z); } if((renderType & RenderType.Regular) != 0) RenderRegular(mesh, sObject.material, lightDirection); if ((renderType & RenderType.Wireframe) != 0) RenderWireframe(mesh, wireFrameColor); if ((renderType & RenderType.Normals) != 0) DrawVertexNormals(mesh, Color.Red); }
public float dot(Float3 other) { return this.x * other.x + this.y * other.y + this.z * other.z; }
public void Rasterize(Mesh mesh, Material material, Float3 lightDirection) { // set interpolated color for (int i = 0; i < mesh.Triangles.Count; i++) { Triangle t = mesh.Triangles[i]; Vertex v1 = mesh.Vertices[t[0] - 1]; Vertex v2 = mesh.Vertices[t[1] - 1]; Vertex v3 = mesh.Vertices[t[2] - 1]; //v2.normal = v1.normal; //v3.normal = v1.normal; int cc1 = (int)(getLamberComponent(v1.normal, lightDirection) * 255); int cc2 = (int)(getLamberComponent(v2.normal, lightDirection) * 255); int cc3 = (int)(getLamberComponent(v3.normal, lightDirection) * 255); v1.color = Color.FromArgb(cc1, cc1, cc1);//.lerpTo(Color.Green, 0.5f); v2.color = Color.FromArgb(cc2, cc2, cc2);//.lerpTo(Color.Blue, 0.5f); v3.color = Color.FromArgb(cc3, cc3, cc3);//.lerpTo(Color.Red, 0.5f); } for (int i = 0; i < mesh.Triangles.Count; i++) { Triangle t = mesh.Triangles[i]; Vertex v1 = mesh.Vertices[t[0] - 1]; Vertex v2 = mesh.Vertices[t[1] - 1]; Vertex v3 = mesh.Vertices[t[2] - 1]; RenderTriangle2(v1, v2, v3, material, lightDirection); } }
private void RenderRegular(Mesh mesh, Material material, Float3 lightDirection) { rasterizer.Rasterize(mesh, material, lightDirection); // FRAGMENT SHADER for (int x = 0; x < Defaults.WIDTH; x++) for (int y = 0; y < Defaults.HEIGHT; y++) bitmap.elDrawPoint(x, y, zBuffer[x, y].color); }
private float getLamberComponent(Float3 normal, Float3 lightDirection) { normal = normal.normalize(); lightDirection = lightDirection.normalize(); float lambertComponent = normal.dot(lightDirection.normalize()); lambertComponent = lambertComponent < 0 ? 0 : lambertComponent; return Utils.Clamp(0, 255, lambertComponent); }
public float dot(Float3 other) { return(this.x * other.x + this.y * other.y + this.z * other.z); }
public void setTranslation(Float3 t) { this._m[3, 0] = t.x; this._m[3, 1] = t.y; this._m[3, 2] = t.z; }
public Float3 transformPoint(Float3 p) { Float4 tP = this.mul(new Float4(p, 1)); return(tP.xyz * (1f / tP.w)); }
private void RenderTriangle2(Vertex _v1, Vertex _v2, Vertex _v3, Material material, Float3 lightDirection) { IVertex v1 = new IVertex(_v1); IVertex v2 = new IVertex(_v2); IVertex v3 = new IVertex(_v3); if (v1.y > v2.y) Utils.swap(ref v1, ref v2); if (v1.y > v3.y) Utils.swap(ref v1, ref v3); if (v2.y > v3.y) Utils.swap(ref v2, ref v3); int triangleYHeight = v3.y - v1.y + 1; int firstSegmentHeight = v2.y - v1.y + 1; int secondSegmentHeight = v3.y - v2.y + 1; for (int y = v1.y; y <= v3.y; y++) { bool isFirstSegment = y < v2.y; int segmentStartY = isFirstSegment ? v1.y : v2.y; float alpha = (float)(y - v1.y) / (float)triangleYHeight; IVertex A = IVertex.lerp(v1, v3, alpha); float beta = (float)(y - segmentStartY) / (float)(isFirstSegment ? firstSegmentHeight : secondSegmentHeight); IVertex B = IVertex.lerp(isFirstSegment ? v1 : v2, isFirstSegment ? v2 : v3, beta); if (A.x > B.x) Utils.swap(ref A, ref B); for (int x = A.x; x <= B.x; x++) { // check extremes float delta = (A.x == B.x) ? 1.0f : (float)(x - A.x) / (float)(B.x - A.x); IVertex C = IVertex.lerp(A, B, delta); float lc = getLamberComponent(C.normal, lightDirection); int intLambert = (int)(lc * 255); Color c = Color.FromArgb(intLambert, intLambert, intLambert); c = tex2D(material.diffuseTexture, C.u, C.v); DrawPointToFrameBuffer(x, y, C.z, c); } } }
public static Float3 lerp(Float3 start, Float3 end, float delta) { return(start + (end - start) * delta); }
public Float3 transformPoint(Float3 p) { Float4 tP = this.mul(new Float4(p, 1)); return tP.xyz * (1f / tP.w); }
public static Float4x4 getTranslationMatrix(Float3 t) { return new Float4x4(1 , 0 , 0 , 0, 0 , 1 , 0 , 0, 0 , 0 , 1 , 0, t.x, t.y, t.z, 1); }
public static Mesh ReadMeshFromFile(string filePath) { Mesh result = new Mesh(); string[] lines = File.ReadAllLines(filePath); List<Float3> normals = new List<Float3>(); List<Float3> vPositions = new List<Float3>(); List<Float2> uvs = new List<Float2>(); List<WObjTriangle> wTriangles = new List<WObjTriangle>(); for (int i = 0; i < lines.Length; i++) { if (lines[i].Length == 0) continue; string[] lineParts = ReplaceMultipleSpaces(lines[i]).Split(' '); // vertex positions if (lineParts[0] == "v") { Float3 position = new Float3(float.Parse(lineParts[1], System.Globalization.CultureInfo.InvariantCulture), float.Parse(lineParts[2], System.Globalization.CultureInfo.InvariantCulture), float.Parse(lineParts[3], System.Globalization.CultureInfo.InvariantCulture) ); vPositions.Add(position); } // uv coordinates if (lineParts[0] == "vt") { Float2 uv = new Float2(float.Parse(lineParts[1], System.Globalization.CultureInfo.InvariantCulture), float.Parse(lineParts[2], System.Globalization.CultureInfo.InvariantCulture)); uvs.Add(uv); } // normals if (lineParts[0] == "vn") { Float3 normal = new Float3(float.Parse(lineParts[1], System.Globalization.CultureInfo.InvariantCulture), float.Parse(lineParts[2], System.Globalization.CultureInfo.InvariantCulture), float.Parse(lineParts[3], System.Globalization.CultureInfo.InvariantCulture) ); normals.Add(normal); } if (lineParts[0] == "f") { string[] f1 = lineParts[1].Split('/'); string[] f2 = lineParts[2].Split('/'); string[] f3 = lineParts[3].Split('/'); int v1 = int.Parse(f1[0]); int v2 = int.Parse(f2[0]); int v3 = int.Parse(f3[0]); int t1 = -1; int t2 = -1; int t3 = -1; // if texture coordinates specified if (f1.Length > 1) { if (!string.IsNullOrEmpty(f1[1])) t1 = int.Parse(f1[1]); if (!string.IsNullOrEmpty(f2[1])) t2 = int.Parse(f2[1]); if (!string.IsNullOrEmpty(f3[1])) t3 = int.Parse(f3[1]); } int n1 = 0, n2 = 0, n3 = 0; // if normals specified if (f1.Length > 2) { n1 = int.Parse(f1[2]); n2 = int.Parse(f2[2]); n3 = int.Parse(f3[2]); } wTriangles.Add(new WObjTriangle(v1, v2, v3, n1, n2, n3, t1, t2, t3)); result.Triangles.Add(new Triangle(v1, v2, v3)); } } result.Vertices = new List<Vertex>(); for(int i = 0; i < vPositions.Count; i++) { result.Vertices.Add(new Vertex(vPositions[i])); } for(int i = 0; i < wTriangles.Count; i++) { WObjTriangle wTriangle = wTriangles[i]; Vertex v1 = result.Vertices[wTriangle.v1 - 1]; Vertex v2 = result.Vertices[wTriangle.v2 - 1]; Vertex v3 = result.Vertices[wTriangle.v3 - 1]; if(normals.Count > 0) { v1.normal = normals[wTriangle.n1 - 1]; v2.normal = normals[wTriangle.n2 - 1]; v3.normal = normals[wTriangle.n3 - 1]; } if (uvs.Count > 0) { if (wTriangle.uv1 < 0 || wTriangle.uv2 < 0 || wTriangle.uv3 < 0) continue; v1.uv = uvs[wTriangle.uv1 - 1]; v2.uv = uvs[wTriangle.uv2 - 1]; v3.uv = uvs[wTriangle.uv3 - 1]; } } return result; }
public Float3x3(Float3[] rows) :this(rows[0].x, rows[0].y, rows[0].z, rows[1].x, rows[1].y, rows[1].z, rows[2].x, rows[2].y, rows[2].z) {}