M.Sc. Jonas Lukasczyk - PhD Student

Leonardo da Vinci Inspired Illustrative Rendering

Leonardo di ser Piero da Vinci (15 April 1452 - 2 May 1519) was an Italian polymath, painter, sculptor, architect, musician, mathematician, engineer, inventor, anatomist, geologist, cartographer, botanist, and writer. He is widely considered to be one of the greatest painters of all time and perhaps the most diversely talented person ever to have lived [Wiki]. In this demo, I tried to recreate Leonardo da Vinci's drawing style by rendering 3D models with the techniques he used in his paintings. As can be seen from the picture to the right, he used shading, contours, and parallel line sketches to create his paintings. Obviously, it is easy to distinguish the rendering output from the original paintings, due to their randomness and small errors, which make them look hand-drawn. However, it would be possible to add more randomness in the rendering steps to make it less obvious that this is an algorithmically computed image, but this was not my intention. I tried to create a renderer which draws objects like Leonardo if he would have been a perfect machine.


Rendering Steps

As soon as I have time I plan to extend this page to give technical details, but for now I only explain the theory behind the renderer.

At first, I import the OBJ models to the main scene by using the THREE.OBJLoader. Then, I render the model in two steps. In the first step, the OBJ model is rendered with light, outer contours, and inner contours. Afterwards, the image of the first render pass is processed by a shader to add the sketch lines and the background.

1 First Render Pass

1.1 Light

The scene has two directional lights, both positioned relatively to the camera. One light always shines from the left, and the other light always shines from the top right corner of the current viewport. The light intensity and the positions of the lights are stored as shader uniforms.

1.2 Outer Contour

To understand how I render the outer contour, consider the scalar product between the view direction and the surface normal. If the camera looks directly on a flat surface, then the absolute value of the scalar product will be large, which indicates that the current position is not near an edge of the surface. But as we come closer to a rounded edge, the scalar product decreases. Therefore, we can use the scalar product as an indicator for edges. Hence, as soon as the scalar product is below a threshold, the shader starts to render a contour line.

1.3 Inner Contour

The inner contours follow the same principle as the outer contours, i.e., the scalar product between the view direction and the surface normal is used to approximate the shape of the object. The inner contours are basically isolines (see THREE.JS isoline example), except that they are faded out at the part of the surface we directly look at. Thus, the alpha value of an isoline depends on the scalar product between the view direction and the surface normal.

2 Second Render Pass (Post-Processing)

2.1 Blurring

After the first render pass, the resulting image is blurred diagonally to create an alpha map for the subsequent steps. This can be done by a simple Gaussian Blur shader.

2.2 Line Sketches

The alpha map of Step 2.1 is used to draw a texture of line sketches on top of the first render pass. Using this alpha map has the advantages that the sketche lines are faded in, and are most intense in the colored areas of the first render pass.

2.3 Background

In the final step, both rendering results and the background are merged together.

Valid XHTML 1.1 Valid CSS!