Skip to content

Commit 41187ef

Browse files
committed
add surfaces tutorial; resolve some autonormal degenerate cases
1 parent 383ed9d commit 41187ef

File tree

11 files changed

+209
-32
lines changed

11 files changed

+209
-32
lines changed

demos/stl.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232
var camera=new Camera(scene,45,1,1000).setDistance(80);
3333
GLUtil.loadStlFromUrl("holder.stl").then(function(mesh){
3434
scene.addShape(scene.makeShape(mesh).setColor("red"));
35-
},function(err){
36-
console.log(err)
3735
})
3836
GLUtil.renderLoop(function(){
3937
camera.update();

demos/surfaces.html

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -144,21 +144,38 @@
144144
}
145145
}
146146

147-
var ColorGradient={
148-
evaluate:function(u,v){
149-
return [1-u,v,u];
150-
}
151-
}
152-
153-
function makeMesh(func){
154-
var mesh=new Mesh();
155-
var ev=new SurfaceEval()
156-
.vertex(func)
157-
.color(ColorGradient)
158-
.setAutoNormal(true)
159-
.evalSurface(mesh,Mesh.TRIANGLES,50,50);
160-
return mesh;
161-
}
147+
function makeMesh(func){
148+
// create a new mesh
149+
var mesh=new Mesh();
150+
// define a color gradient evaluator for
151+
// demonstration purposes. Instead of X, Y, and Z,
152+
// generate a Red/Green/Blue color based on
153+
// the same parameters U and V as the surface
154+
// function for 3D points.
155+
var colorGradient={
156+
evaluate:function(u,v){ return [1-u,v,u]; }
157+
}
158+
// generate the parametric surface.
159+
// First, create a SurfaceEval object
160+
var ev=new SurfaceEval()
161+
// Specify the vertex evaluator passed as _func_
162+
.vertex(func)
163+
// Specify the color gradient evaluator defined above
164+
.color(colorGradient)
165+
// Generate normals for the parametric surface,
166+
// which is required for lighting to work correctly
167+
.setAutoNormal(true)
168+
// Evaluate the surface and generate a triangle
169+
// mesh, using 51 different U-coordinates ranging
170+
// from 0 to 1 (50 subdivisions plus 1), and 51
171+
// different V-coordinates ranging from 0 to 1
172+
// Instead of Mesh.TRIANGLES, we could use
173+
// Mesh.LINES to create a wireframe mesh,
174+
// or Mesh.POINTS to create a point mesh.
175+
.evalSurface(mesh,Mesh.TRIANGLES,50,50);
176+
// Surface generated, return the mesh
177+
return mesh;
178+
}
162179

163180
function link1(){
164181
if(shape)scene.removeShape(shape);

glutil-eval.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,7 @@ SurfaceEval.prototype.evalOne=function(mesh,u,v){
627627
var dv=0.001
628628
// Find the partial derivatives of u and v
629629
var vu=this.vertexSurface.evaluate(u+du,v);
630+
var vuz=vu[2];
630631
var vv=this.vertexSurface.evaluate(u,v+dv);
631632
GLMath.vec3subInPlace(vv,vertex);
632633
GLMath.vec3subInPlace(vu,vertex);
@@ -637,14 +638,19 @@ SurfaceEval.prototype.evalOne=function(mesh,u,v){
637638
GLMath.vec3normInPlace(vv);
638639
if(GLMath.vec3length(vu)==0){
639640
// partial derivative of u is degenerate
640-
//console.log([vu,vv]+" u degen")
641+
//console.log([vu,vv,u,v]+" u degen")
641642
vu=vv;
642643
} else if(GLMath.vec3length(vv)!=0){
643644
vu=GLMath.vec3cross(vu,vv);
644645
GLMath.vec3normInPlace(vu);
645646
} else {
646647
// partial derivative of v is degenerate
647-
//console.log([vu,vv]+" v degen")
648+
//console.log([vu,vv,u,v]+" v degen")
649+
if(vu[2]==vertex[2]){
650+
// the close evaluation returns the same
651+
// z as this evaluation
652+
vu=[0,0,1];
653+
}
648654
}
649655
mesh.normal3(vu[0],vu[1],vu[2]);
650656
} else if(normal){

glutil_min.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

objmtl.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ http://creativecommons.org/publicdomain/zero/1.0/
66
If you like this, you should donate to Peter O.
77
at: http://upokecenter.dreamhosters.com/articles/donate-now-2/
88
*/
9-
/** @class OBJ file. */
9+
/**
10+
OBJ file.<p>
11+
* To use this class, you must include the script "objmtl.js"; the
12+
* class is not included in the "glutil_min.js" file which makes up
13+
* the HTML 3D Library. Example:<pre>
14+
* &lt;script type="text/javascript" src="glutil_min.js">&lt;/script></pre>
15+
@class */
1016
function ObjData(){
1117
/** URL of the OBJ file */
1218
this.url=null;
@@ -23,11 +29,7 @@ function MtlData(){
2329
}
2430
/**
2531
* Creates one or more 3D shapes from the data
26-
* in this OBJ file.<p>
27-
* To use this class, you must include the script "objmtl.js"; the
28-
* class is not included in the "glutil_min.js" file which makes up
29-
* the HTML 3D Library. Example:<pre>
30-
* &lt;script type="text/javascript" src="glutil_min.js">&lt;/script></pre>
32+
* in this OBJ file.
3133
* @param {Scene3D} scene 3D scene to load the shape with.
3234
* @return {glutil.ShapeGroup} Group of shapes.
3335
*/

tutorials/camera.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,8 @@ orthographic projection, described below.
4242
### Perspective Projection
4343

4444
A perspective projection gives the 3D scene a sense of depth. In this projection, closer objects
45-
look bigger than more distant objects with the same size.
46-
47-
The perspective projection is similar to how our eyes see the world.
45+
look bigger than more distant objects with the same size, making the
46+
projection similar to how our eyes see the world.
4847

4948
![Two rows of spheres, and a drawing of a perspective view volume.](persp1.png)
5049

tutorials/surfaces.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
## Introduction
2+
3+
This tip describes parametric surfaces and how to generate them using my
4+
public-domain [HTML 3D Library](http://peteroupc.github.io/html3dutil).
5+
6+
**Download the latest version of the library at the [HTML 3D Library's Releases page](https://github.com/peteroupc/html3dutil/releases).**
7+
8+
## What Is a Parametric Surface?
9+
10+
A _parametric surface_ is a surface generated by evaluating the results of a _vector function_. This vector function
11+
takes two numbers, U and V, and returns a 3D point, X, Y, and Z. Each (U, V) point corresponds to an (X, Y, Z)
12+
point that lies on the surface.
13+
14+
A _vector function_ in 3D is a combination of three functions, one for each axis:
15+
16+
* **F**(u, v) = [ _x_(u, v), _y_(u, v), _z_(u, v) ];
17+
18+
The _x_ function returns an X coordinate given u and v, and likewise for _y_ and _z_.
19+
Since the _z_ function returns a Z coordinate, the surface will be in 2D if _z_ always returns
20+
the same value.
21+
22+
For example, if we have a parametric surface defined by the following functions:
23+
24+
* _x_(u, v) = u * v
25+
* _y_(u, v) = -u
26+
* _z_(u, v) = u * sqrt(v)
27+
28+
and we evaluate the UV point (2, 4), then we have:
29+
30+
* **F**(2, 3) = [ 2 * 4, -2, 2 * sqrt(4) ];
31+
* **F**(2, 3) = [ 8, -2, 4 ];
32+
33+
So (8, -2, 4) is one point that lies on this parametric surface, and any other point on the
34+
surface can be found by evaluating different UV points. By the way, the surface looks like this:
35+
36+
![The parametric surface.](surfaces1.png)
37+
38+
## Parametric Surfaces in the HTML 3D Library
39+
40+
The HTML 3D Library supports parametric surfaces using a class named `SurfaceEval`. It helps
41+
generate vertex coordinates, texture coordinates, normals, and colors using a parametric surface
42+
function. The following helper function, `makeMesh`, generates a parametric surface mesh
43+
that was used to produce the pictures on this page.
44+
45+
The comments explain how `makeMesh` works in detail.
46+
47+
function makeMesh(func){
48+
// create a new mesh
49+
var mesh=new Mesh();
50+
// define a color gradient evaluator for
51+
// demonstration purposes. Instead of X, Y, and Z,
52+
// generate a Red/Green/Blue color based on
53+
// the same parameters U and V as the surface
54+
// function for 3D points.
55+
var colorGradient={
56+
evaluate:function(u,v){ return [1-u,v,u]; }
57+
}
58+
// generate the parametric surface.
59+
// First, create a SurfaceEval object
60+
var ev=new SurfaceEval()
61+
// Specify the vertex evaluator passed as _func_
62+
.vertex(func)
63+
// Specify the color gradient evaluator defined above
64+
.color(colorGradient)
65+
// Generate normals for the parametric surface,
66+
// which is required for lighting to work correctly
67+
.setAutoNormal(true)
68+
// Evaluate the surface and generate a triangle
69+
// mesh, using 51 different U-coordinates ranging
70+
// from 0 to 1 (50 subdivisions plus 1), and 51
71+
// different V-coordinates ranging from 0 to 1
72+
// Instead of Mesh.TRIANGLES, we could use
73+
// Mesh.LINES to create a wireframe mesh,
74+
// or Mesh.POINTS to create a point mesh.
75+
.evalSurface(mesh,Mesh.TRIANGLES,50,50);
76+
// Surface generated, return the mesh
77+
return mesh;
78+
}
79+
80+
In the HTML 3D Library, parametric surface objects define one method, "evaluate",
81+
which returns a 3D point given a U parameter and a V parameter. (By default, U and
82+
V each range from 0 through 1.)
83+
84+
The following code is a very simple surface evaluator.
85+
86+
var evaluator = {
87+
"evaluate":function(u, v){
88+
// Take the U parameter as the X coordinate,
89+
// the V parameter as the X coordinate, and 0 as
90+
// coordinate.
91+
return [u, v, 0];
92+
}
93+
}
94+
95+
That evaluator simply generates a square at the top-right quadrant:
96+
97+
![The parametric surface.](surfaces2.png)
98+
99+
And the following evaluator generates a circle:
100+
101+
var evaluator = {
102+
"evaluate":function(u, v){
103+
// Extend the range of v
104+
v*=Math.PI*2;
105+
// Return circle coordinates.
106+
return [u*Math.cos(v),u*Math.sin(v),0];
107+
}
108+
}
109+
110+
![The parametric surface.](surfaces3.png)
111+
112+
Now here's the interesting part: This evaluator returns not a circle,
113+
but a _cone_, whose length runs along the negative z-axis:
114+
115+
var evaluator = {
116+
"evaluate":function(u, v){
117+
// Extend the range of v
118+
v*=Math.PI*2;
119+
// Return cone coordinates, using the u
120+
// parameter as the z-axis.
121+
return [u*Math.cos(v),u*Math.sin(v),-u];
122+
}
123+
}
124+
125+
The following shape was rotated to show the z-axis; the rotation isn't perfect.
126+
127+
![The parametric surface.](surfaces4.png)
128+
129+
Note that all three examples above use a value named `evaluator`. To generate
130+
a mesh with an evaluator and add it to the 3D scene, you then need to do:
131+
132+
// Assumes that a Scene3D object named _scene_ was previously defined.
133+
// Create a 3D shape using the makeMesh method given earlier on this page
134+
var shape = scene.makeShape(makeMesh(evaluator));
135+
// Add the shape to the 3D scene
136+
scene.addShape(shape);
137+
138+
The generated 3D mesh from a parametric surface is just like any
139+
other mesh, and the same functions and methods you use for other meshes
140+
can be used on this mesh as well. For more information, see the
141+
[overview page](http://www.codeproject.com/Tips/896839/Public-Domain-HTML-ThreeD-Library)
142+
and the API references for the [`Mesh`](http://peteroupc.github.io/html3dutil/glutil.Mesh.html) and
143+
[`Shape`](http://peteroupc.github.io/html3dutil/glutil.Shape.html) classes.
144+
145+
## Demo
146+
147+
* [surfaces.html](https://peteroupc.github.io/html3dutil/demos/surfaces.html) - Demonstrates parametric surfaces.
148+
149+
## Other Pages
150+
151+
The following pages of mine on CodeProject also discuss this library:
152+
153+
* [_Public-Domain HTML 3D Library_](http://www.codeproject.com/Tips/896839/Public-Domain-HTML-ThreeD-Library)
154+
* [_Creating shapes using the Public Domain HTML 3D Library_](http://www.codeproject.com/Tips/987914/Creating-shapes-using-the-Public-Domain-HTML-D-Lib)
155+
* [_The "Camera" and the Perspective and View Transforms_](http://www.codeproject.com/Tips/989978/The-Camera-and-the-Projection-and-View-Transforms)

tutorials/surfaces1.png

36.4 KB
Loading

tutorials/surfaces2.png

51.7 KB
Loading

tutorials/surfaces3.png

29.4 KB
Loading

0 commit comments

Comments
 (0)