This is a single class program that creates an SVG file containing a square with a non-linear radial gradient based on Phong shading function for specular highlights (function
The SVG has a number of stop colors
The program takes the initial color
Notice that the individual color components need to be processed independently. For simplicity and easier comprehension, the colors are dealt here as a sort of 3D (or 4D, including the alpha channel) vector representation. Indeed, colors can be represented as vectors where each color component corresponds to a different dimension.
One can now devise the complete algorithm. A gradient in SVG also needs the offset of each stop color from the center of the gradient (considered the gradient's origin). In the algorithm it's called
Let's start with an
Notice that since the control of the loop is totally independent from the incremented variables
Evidently, the algorithm above omits many details in order to simplify the logic, to show only the essential information, and to enhance comprehension. It only shows how the program calculates
Also of note, the names of the variables used in the pseudocode are given to enhance the algorithm comprehension and they don't correspond to the actual variable names.
Phong shading is a realistic shading algorithm for 3D scenes that calculates the color of each pixel by making the
The most impressive feature of Phong shading, though, is that it also includes a specular highlight calculation, producing spectacular glares whenever the surface reflects the light source towards the viewer, which renders the shading tremendously realistic. For this component of the shading we calculate the dot product between the unitary reflected light source vector
Given the vectors and angles shown in
Where,
-
$k_a$ is the ambient reflectivity coefficient. -
$I_a$ is the ambient light intensity. -
$k_d$ is the diffuse reflectivity coefficient. -
$\vec{L}$ is the normalized light direction vector pointing to the light source. -
$\vec{N}$ is the normalized surface normal vector. -
$I_{d}$ is the diffuse light intensity for the light source. -
$k_s$ is the specular reflectivity coefficient. -
$\vec{L_{r}}$ is the normalized reflection vector for the light source. -
$\vec{V}$ is the normalized view direction vector. -
$I_{s}$ is the specular light intensity for the light source. -
$n$ is the shininess exponent, which controls the size and sharpness of the specular highlight as shown in$Fig. 4$ .
The extension of Phong shading for
Where,
-
$\vec{L_i}$ is the normalized light direction vector pointing to light source$i$ . -
$I_{id}$ is the diffuse light intensity for light source$i$ . -
$\vec{L_{ri}}$ is the normalized reflection vector for light source$i$ . -
$I_{is}$ is the specular light intensity for light source$i$ .
The complete model is summarized in
As seen in formula
Let's forget now where
A quite precise approximation of the curves is shown in
In vector graphics we observe that the effect of the specular highlight is strikingly similar to the ones produced by radial gradients. The particular interest of using Phong's specular highlight to calculate stop colors in radial gradients is the smooth appearance of the gradients intensities that it produces. In this context, the expected gradients would be more realistic than the ones usually obtainable by simply making ad-hoc choices of stop colors. To be more specific, the intensities are still linearly interpolated between each two calculated stop colors, but with a sufficient number of stop colors the transitions are imperceptible.
In
We generated the gradients of
One could ask oneself what is the purpose of writing a program to generate gradients in SVG based on specular highlights, since this effect can be generated using SVG filters. There are a few simple reasons for doing that:
-
The program can be modified to use other functions, instead of
$cos^n(\alpha).$ Equal angular intervals don't correspond to linear variations in the offset domain. This is a problem to be adequately analyzed. A possible solution is using a polynomial function$f(x)$ with curves with similar shapes as$cos^n(\alpha),$ but with a linear domain in$x$ (the next program in this repository will implement that).In any case, these implementations provide increased simplicity and versatility to generate gradients than using filters.
-
It allows to hack an existing classical SVG gradient, that is, to manually substitute it by a gradient generated by the program. It requires only substituting the stop colors by the ones calculated by the program. This is especially interesting to give a more realistic look to a specular highlights (e.g., in illustrations with realistic effects in 3D).
-
One can use the method in another program that calculates the real specular highlights in 3D (using point light sources) and apply the resulting gradients in a projection of the 3D objects in SVG. This could be done by first building a 3D model of the object using sliced parametric surfaces and sliced implicit surfaces piece by piece, then determining the pieces visible according to the point of view, and proceeding in their projections as SVG paths.
This is not as hard to do as one can imagine, but the process wouldn't be automatic. First, the intersection of the surfaces with the cutting planes can be done by rotating the object to align the cutting plane with the plane defined by two axes, and then designing a path using Bezier curves approaching the cutting curve in 2D. Then we rotate back the control points of the path in the 3D space. When projecting the curve, it's enough to convert the control points to the projection plane to obtain the 2D path for the SVG. Paths should be closed by the visible silhouettes of the 3D object transformed in paths. The silhouettes points can be generated automatically. Maybe the paths can also be obtained automatically (there are AI based software that do that).
Finally, the highlights are simply a point (the center of the gradient) and a circle (gradient radius) transformed and projected. Obviously, the result is just an approximation of the original 3D object illumination, but it's a better and more realistic approximation that doing that in 2D from scratch. The diffuse shading can be approximated using linear gradients, for example. Cylindric surfaces, for example, can have diffuse and diffuse shading using linear gradients using Phong's complete model equation
$3$ to generate the stop colors.SVG filters can also be used for that as well, to better approximate the complete shading equation.