Add eye_atZ to your Canvas class. Now the eye is at (0, 0, eye_atZ), and the Canvas is parallel to xy-plane, with its center at z-axis and of distance vReso/2 to the eye.
The eye and the four corners of the Canvas forms a semi-infinite pyramid, which is called viewing volume, since only models inside of it are projected onto the canvas and show up in the image.
You should initialize the eye_atZ (2.0 is a good try).
Add this private member to Canvas class.
// given a space point, return its projected point on the canvas plane. Point project(Point const& P) const;
We already have this FillTriangle(),
which takes three vertexes ON the canvas as its argument.void FillTriangle(int x1, int y1, RGB const col1, int x2, int y2, RGB const col2, int x3, int y3, RGB const col3);
Now write another one,
which takes three 3D space points as its argument.void FillTriangle(Point const& P1, RGB const col1, Point const& P2, RGB const col2, Point const& P3, RGB const col3);
You should use project() and then call the initial version of FillTriangle().
A tetrahedra is a regular polydedra with four triangle faces.
Try to find texture coordinates for all four vertexes so that the texture mapping has no distortion.
Add to TriangleMesh this member function,
which draw the model. Basically you just iterate through each triangle, and call FillTriangle() in each iteration.void Draw(Canvas& canvas) const;
Here is the typical way to iterate through each triangle,
for(int f = 0; f < total_triangles; ++f) { int i = F[f].i, j = F[f].j, k = F[f].k; int ni = F[f].ni, nj = F[f].nj, nk = F[f].nk; int ti = F[f].ti, tj = F[f].tj, tk = F[f].tk; canvas.FillTriangle(V[i], T[ti], V[j], T[tj], V[k], T[tk]); }
Download this OBJ file and the texture image to try your code, sphere2 sphere3 sphere4 sphere5 earth2.ppm
You should use texture mapping to set the color, which means you get the texture coordinates from TriangleMesh and feed them to FillTriangle()
This is to make sure Draw() works correctly.
If either of the 3 vertexes is back facing, do not draw the triangle.
Because the eye is at (0, 0, eye_atZ > 0), looking along negative z-axis, a vertex is back facing if and only if its normal has a negative z component.
for(int f = 0; f < total_triangles; ++f) { int i = F[f].i, j = F[f].j, k = F[f].k; int ni = F[f].ni, nj = F[f].nj, nk = F[f].nk; int ti = F[f].ti, tj = F[f].tj, tk = F[f].tk; if(N[ni].z >= 0 && N[nj].z >= 0 && N[nk].z >= 0) canvas.FillTriangle(V[i], T[ti], V[j], T[tj], V[k], T[tk]); }
Now try to set pixel color by lighting computation.
The color we perceive on a surface point is computed as
Add this to Point.h, which computes the consine of the angle between two directions.
float Cosine(Point const& rhs) const { return (*this) * rhs / ( GetNorm() * rhs.GetNorm() ); }
For the second step, you should use this member function in RGB class.
RGB operator*(RGB const&rhs) const { RGB ret(*this); return ret *= rhs; }
And for the third step, you should use this one.
RGB operator*(float scale) const { RGB ret(*this); return ret *= scale; }
RGB mcol = Red, lcol = White; float cosI = N[ni].Cosine(light), cosJ = N[nj].Cosine(light), cosK = N[nk].Cosine(light); if(cosI >= 0 && cosJ >= 0 && cosK >= 0) canvas.FillTriangle(V[i], mcol * lcol * cosI, V[j], mcol * lcol * cosJ, V[k], mcol * lcol * cosK);
1.3.6