\( \newcommand{\vecIII}[3]{\left[\begin{array}{c} #1\\#2\\#3 \end{array}\right]} \newcommand{\vecIV}[4]{\left[\begin{array}{c} #1\\#2\\#3\\#4 \end{array}\right]} \newcommand{\Choose}[2]{ { { #1 }\choose{ #2 } } } \newcommand{\vecII}[2]{\left[\begin{array}{c} #1\\#2 \end{array}\right]} \newcommand{\vecIII}[3]{\left[\begin{array}{c} #1\\#2\\#3 \end{array}\right]} \newcommand{\vecIV}[4]{\left[\begin{array}{c} #1\\#2\\#3\\#4 \end{array}\right]} \newcommand{\matIIxII}[4]{\left[ \begin{array}{cc} #1 & #2 \\ #3 & #4 \end{array}\right]} \newcommand{\matIIIxIII}[9]{\left[ \begin{array}{ccc} #1 & #2 & #3 \\ #4 & #5 & #6 \\ #7 & #8 & #9 \end{array}\right]} \)

CS307: Transparency and Text

Plan

  • Rendering scenes with occlusion: z-buffer & painter's algorithms
  • Representing transparency & rendering transparent surfaces
  • Quiz questions — there were none!
  • Please update: projects
  • Demo: transparency tutor
  • Text in Three.js
  • Exercise: snow globe

Rendering Scenes with Occlusion

To understand why transparency is hard, we need to understand how opaque objects are rendered. Throughout the course, we've taken for granted that we can draw multiple objects that may "overlap" in the image, and the rendering will show them properly overlapping. How is this possible?

town scene

There are two algorithms:

  • the z-buffer algorithm (depth buffer algorithm)
  • the painter's algorithm (depth sort algorithm)

The z-buffer algorithm proceeds as follows:

  1. Initialize each pixel of the z-buffer to the maximum (most distant) depth in the scene
  2. Initialize the framebuffer (image buffer) to the background color
  3. For each new surface (or each triangular face of a new object):
    • calculate the depth value of each pixel
    • if the new depth value at a pixel is less than (closer to the camera than) the current depth value in the z-buffer, replace the depth in the z-buffer and color in the framebuffer at this pixel with those of the new surface

After all the surfaces have been processed, each pixel of the framebuffer stores the color of a visible surface at that pixel.

In the diagram below, the depth buffer and framebuffer are shown together on the right, larger depth values are closer to the camera, and the objects are rendered in the order S2, S1, S3:

z-buffer algorithm

As suggested by the picture below (from Patrick Hurley), the painter's algorithm proceeds as follows:

  1. sort surfaces/polygons by their depth (Z value)
  2. draw objects in order, from farthest to closest

painter's algorithm

Scenerios such as the following pose a challenge for the painter's algorithm — which object is in front? Would the z-buffer algorithm handle this example correctly?

painter's algorithm

We've been using the z-buffer algorithm successfully, but it doesn't work so well with transparency, because it's not certain what the depth of a transparent pixel is, or how it should interact with things at other depths.

So, now it's time to use a little of the painter's algorithm, in the sense that we're going to draw the transparent things last and not update the depth buffer.

Representing Transparency & Rendering Transparent Surfaces

Transparency is represented with an "alpha" value with the color or material, e.g. RGB$\alpha$, in the range from $0$ to $1$:

  • $\alpha=1$ means perfectly opaque
  • $\alpha=0$ means perfectly transparent

In Three.js, we can set the transparent and opacity properties of a Material:

var mat = new THREE.MeshBasicMaterial( {color: 0x00ffff,
                                        transparent: true,
                                        opacity: 0.5} );

To render scenes with opaque and transparent objects, Three.js does the following :

  1. initialize the z-buffer (depth buffer)
  2. draw opaque objects first
  3. turn off the depth buffer
  4. draw transparent objects from farthest to nearest

How is the color of a transparent object combined with the color of background surfaces as it is rendered?

Let (RF, GF, BF) refer to the color currently stored in the framebuffer at a particular pixel, and let (RS, GS, BS, $\alpha$S) refer to the color and opacity of the new transparent surface to be added at this pixel. The new color stored at this pixel is given by the following expression:

        $\alpha$S (RS, GS, BS) $+$ ($1 -$ $\alpha$S) (RF, GF, BF)

Transparency Tutor

Let's explore these ideas with this transparency tutor in Three.js:

transparency tutor

Text in Three.js

Our version of Three.js has a basic capability to create 3D text using the THREE.TextGeometry class. Oddly, this is a subclass of THREE.ExtrudeGeometry, because 2D text is extruded to make 3D text.

There are a limited number of fonts available, and the desired font must be loaded using the THREE.FontLoader class that is similar to the THREE.TextureLoader class used to load images for texture mapping.

The following demo adds 3D text to a scene:

Here is the key code:

var loader = new THREE.FontLoader();

path = 'https://cs.wellesley.edu/~cs307/threejs/r80/examples/fonts/';

loader.load(
   path + 'helvetiker_regular.typeface.json',
   function (font) {
      var textGeom = new THREE.TextGeometry('Wellesley College', 
                                            {font: font,
                                             size: 6,
                                             height: 2,
                                            } );
      var textMat = new THREE.MeshBasicMaterial({color: 0x0000ff});
      var textObj = new THREE.Mesh(textGeom, textMat);
      textObj.position.set(-28,2,2);
      scene.add(textObj);
      TW.render();
   } );

Exercise: Snow Globe

In this exercise, you'll create your own snow globe:

snow globe

The starting point for this exercise is this snowGlobe-start.html code file, which creates a town scene on a circular ground of snow:

Your task is to build the scene into a snow globe, something like this:

The things you should add to the code are described in comments near the end of the file, and include the following:

  • Add a shiny, transparent globe around the scene (enter 'a' to see the location of the origin of the scene coordinate frame)

    Hints: use a radius of 10 for the sphere, and transparent Phong material with a color of 0xaaaaaa (or try something a little darker if you don't see the highlights on the globe, like 0x575757)

  • Add the black base to hold the globe
  • Add a call to the addSnow() function to add snow inside the globe (examine the code to see what it does)
  • Add code to load a font and create text to add to the sign near the middle of town (the earlier code snippet can be a useful starting point)
  • Add a base of snow to the bottom part of the globe (this is tricky, so I left it for last — see the documentation for the THREE.SphereGeometry class to see all of its inputs)

Here's a sample solution: snowGlobe.html