⬆️ ⬇️

Improving 3d engine on js: Gouraud shading



The babarun post about a 3d engine on js caused a creative impulse to add toning Guro for greater realism. That's what happened (and now also with specularity). Compared with the usual (flat) tint, the normals need to have not for the faces, but for the vertices (that is, for the triangular face, three normals). For ready-made normals of faces, the vertex normals are calculated by simply averaging the normals of all the faces that include the given vertex; this is done once before rendering. The luminance of the vertices is calculated at the beginning of each frame, taking into account the change in the position of the camera.



The main difficulty was how to fill the gradient with a triangle.



Pixel access to the image buffer is dismissed as slow. In canvas there is a linear gradient , we also need to fill in a triangle so that the corners are given colors. Generally speaking, this task is not reduced to a linear gradient in general. A simple example: the three vertices of a triangle are colored red, green, and blue. However, if the color vectors of the vertices are linearly dependent, as in the babarun example, the problem can be reduced to a linear gradient. The only question is how to ask it.



So, we have three vertices (x1, y1), (x2, y2), (x3, y3) with colors c1, c2, c3. To define a linear gradient in canvas, you need to specify the starting point, end point and their colors. We sort the vertices so that the colors go in ascending order and combine the starting point of the linear gradient with the darkest vertex (x1, y1). Now we need to choose a direction of a linear gradient such that the lengths of the projections of the vectors (x2, y2) - (x1, y1) and (x3, y3) - (x1, y1) to this direction are proportional to the color differences (c2-c1) and ( c3-c1). We can fix the color of the end point of the linear gradient to the brightest of the desired (c3), that is, the projection (x3, y3) must exactly fall into the end point. This condition and the condition of proportionality of projections to color differences give two equations for the coordinates of the end point of a linear gradient. The equations are easily solved in your favorite solver (I used Maple), the babarun script is modified and laid out on the server .

')

All source code in html-file. Here are the new features:

calcGradientPos - calculates the position of the end of the linear gradient vector with the beginning at (0,0) (actually, solving a system of equations)

calcFullGradientPos - calls calcGradientPos, shifting the first vertex to (0,0) and then returning back.

getGradient - creates a CanvasGradient object for a given triangle.

paintGradientTriangle - draws a triangle to the canvas. Vertices are given a double array [3] [3], the first index is the number of the vertex, the second index specifies the x, y coordinates and color (from 0 to 1); at the end, the color is multiplied by the parameters (r, g, b) - the overall color of the shape.

calcVerticesNormals — calculate vertex normals by face normals.

There are also a number of changes in the draw_mesh function, in particular, at the very beginning of the cycle, in which vertices are highlighted.



FPS has fallen by half, but the possibilities for optimization have not been exhausted (they were in the original version). Who wants, may try to improve the result. I made only a version from 1920 polygons, anyone can easily add the rest.



Upd: there was an error with normalization of normals, so it was impossible to make specularity. Mirror is now added (thanks to lsdima for pushing to deal with this).

Source: https://habr.com/ru/post/94519/



All Articles