Home

extras/LightingWithTexture.js

Summary.

Equirectangular and Mercator projection viewer using lighting combined with texture mapping written in Vanilla Javascript and WebGL.

For educational purposes only.

This is just a demo for teaching CG, which became overly complicated, and it is similar to Lighting2, except we define a 3x3 matrix for material properties and a 3x3 matrix for light properties that are passed to the fragment shader as uniforms. Edit the light and material matrices in the global variables to experiment or startForReal to choose a model and select face or vertex normals. Three.js only uses face normals for polyhedra, indeed.

Texture coordinates can be set in each model or sampled at each pixel in the fragment shader. We can also approximate a sphere by subdividing a convex regular polyhedron and solving Mipmapping artifact issues by using Tarini's method, in this case. These artifacts show up due to the discontinuity in the seam when crossing the line with 0 radians on one side and 2π on the other. Some triangles may have edges that cross this line, causing the wrong mipmap level 0 to be chosen.

To lay a map onto a sphere, textures should have an aspect ratio of 2:1 for equirectangular projections or 1:1 (squared) for Mercator projections. Finding high-resolution, good-quality, and free cartographic maps is really difficult.

The initial position on the screen takes into account the obliquity of the earth (23.44°), and the Phong highlight projects onto the equator line if the user has not interacted using the Arcball. If PHP is running on the HTTP server, then any image file in directory textures will be available in the menu. Otherwise, sorry GitHub pages, only the images listed in the HTML file.

Mercator texture coordinates can be set in a model directly or in the shader that samples texture coordinates for each pixel. Since a unit sphere fits in the WebGL NDC space, it is possible to go into each fragment from:

  • cartesian → spherical (equirectangular) → Mercator
  • (x, y, z) → (long, lat) → (x, y)
  • sample texture at (x, y)

As a final remark, I thought it would be easier to deal with map images as textures, but I was mistaken. I tried, as long as I could, not to rewrite third-party code. Unfortunately, this was impossible. The main issue was that the prime meridian is at the center of a map image and not at its border, which corresponds to its antimeridian.

Initially, I used the basic-object-models-IFS package, but the models had their z-axis pointing up as the zenith, and I wanted the y-axis to be the north pole (up). Therefore, I switched to Three.js, and almost everything worked just fine. Nonetheless, a sphere created by subdividing a polyhedron had its texture coordinates rotated by 180° and a cylinder or cone by 90°. In fact, there is a poorly documented parameter, thetaStart, that does fix just that.

Nevertheless, I decided to adapt the hws software to my needs by introducing a global hook, yNorth, and rotating the models accordingly. Furthermore, I added the parameter stacks to uvCone and uvCylinder, to improve interpolation and fixed the number of triangles generated in uvCone. This way, the set of models in hws and three.js became quite similar, although I kept the "zig-zag" mesh for cones and cylinders in hws (I have no idea whether it provides any practical advantage). A user can switch between hws and three.js models by pressing a single key (Alt, ❖ or ⌘) in the interface.

There is a lot of redundancy in the form of vertex duplication in all of these models, which may preclude mipmapping artifacts. The theoretical number of vertices, 𝑣, for a manifold model and the actual number of vertices (🔴) are displayed in the interface. The number of edges, e, is simply three times the number of triangles, t, divided by two.

For any triangulation of a compact surface, the following holds (page=52):
  • 2e = 3t,
  • e = 3(𝑣 - χ), χ(S²)=2,
  • 𝑣 ≥ 1/2 (7 + √(49 - 24χ)).

As a proof of concept, I implemented a sphere model without any vertex duplication. Besides being much harder to code, its last slice (e.g., slices = 48) goes from 6.152285613280011 (2π/48 * 47) to 0.0 and not 2π (if there was an extra duplicate vertex), which generates texture coordinates going from 0.9791666666666666 (47/48) to 0.0 and not 1.0. Although this is what causes the mipmapping artifacts, it has nothing to do with the topology of the model but how mimapping is implemented on the GPU.

Of course, these are just polygon meshes suitable for visualization and not valid topological B-rep models that enforce the Euler characteristic by using the winged-edge, quad-edge, or radial-edge data structures required in solid modeling.

Homework:

  1. The application selects a random city and displays its location (when its name is checked in the interface) as the intersection of its line of latitude (parallel) and line of longitude (meridian) on the model surface (preferably a map onto a sphere). Your task is (using the mouse or any pointer device) to pick a point in the texture image and display its location on the map.
  2. A bigger challenge would be to pick the point directly onto the model's surface, but you'll have to implement a 3D pick in this case by casting a ray and finding its closest (first) intersection (relative to the viewer) with the polygonal surface of the model.
  3. To determine a ship's latitude at the sea (without a GPS), one needs a sextant. However, what is it necessary to get its longitude? What calculation should be done (it is simpler than you might think)?
  4. What does the obliquity of the earth have to do with the Glatial periods?
Since:
  • 30/01/2016
Author:
  • Paulo Roma
License:
Source:
See:

lib/TeapotGeometry.js

Summary.

Utah teapot.

In the early years of 3D modeling and rendering, Martin Newel created a computer-generated three dimensional teapot. The original "Utah teapot" was actually taller than the famed teapot we see in so many places today. Legend has it that during a demo, using a system with non-square pixels, Jim Blinn scaled the teapot rather than scaling the image. As this dataset became more widely distributed than the original, his edit changed the aspect of teapots in 3D software for years to come.
Since:
  • 07/01/2023
Author:
  • Martin Newell
Source:
See:

lib/basic-objects-IFS.js

Summary.

The functions in this file create models in an IFS (Indexed Face Set) format that can be drawn using gl.drawElements with primitive type gl.TRIANGLES.

Objects have vertex coordinates, normal vectors, and texture coordinates for each vertex, plus a list of indices for the element array buffer.

The return value of each function is an object, model, with properties:
  • model.vertexPositions -- the vertex coordinates;
  • model.vertexNormals -- the normal vectors;
  • model.vertexTextureCoords -- the texture coordinates;
  • model.indices -- the face indices.
The first three properties are of type Float32Array, while model.indices is of type Uint16Array.

This file also defines a variable (not a function) teapotModel, which is a model of the OpenGL teapot in the same format.

Since:
  • 08/01/2014
Author:
Source:
See:

lib/gl-matrix/dist/esm/common.js

Summary.

High performance matrix and vector operations.

Version:
  • 3.4.0
Author:
  • Brandon Jones
  • Colin MacKenzie IV
Source:
See:

polyhedron~lib/polyhedron.js

Summary.

Creates the model of a sphere by continuously subdividing an initial convex regular polyhedron.

The algorithm starts with just four, six, twenty, or twelve points, corresponding to a tetrahedron, octahedron, dodecahedron, or icosahedron, inscribed in the unit sphere, and recursively subdivides each triangle by inserting a new vertex at the midpoint of its three edges, which is then projected onto the surface of the sphere.
Since:
  • 21/11/2016
Author:
  • Paulo Roma Cavalcanti
Source:
See:

lib/simple-rotator.js

Summary.

The SimpleRotator class implements an ArcBall like interface.

Created by Ken Shoemake in 1992, it is the de facto standard for interactive 3D model manipulation and visualization.

The class defines the following methods for an object of type SimpleRotator:

Since:
  • 22/01/2016
Author:
Source:
See:

lib/teal_book/cuon-utils.js