|
Notes for Nov 18 class
Surface of revolution
Creating a surface of revolution
Given a spline curve S(v) that defines a radius from v=0 to v=1,
we can define a surface of revolution as follows:
For any (ui,vj), the vertex position is:
positioni,j = [ S(vj) * cos(2πui) , S(vj) * sin(2πui) , 2 * vj - 1 ]
To compute the surface normal at this vertex:
dx = cos(2πui)
dy = sin(2πui)
dz = (S(vj) - S(vj+1)) / 2(vj+1 - vj)
normali,j = normalize( [ dx , dy, dz ] )
Using a surface of revolution
The surface of revolution as defined above will be along the z axis, from z = -1 to z = +1.
You need to translate, rotate and scale it to create a shape of desired length and orientation.
Orientation of ribbons
To create a consistent orientation
for a ribbon, you need to follow along
the path of the ribbon from beginning to end,
at each step creating an iterative update to the
ribbon orientation so that the orientation remains consistent,
without unwanted twists.
One way to do this is in two stages.
First, compute the path from beginning to
end, together with orientation.
Then, use that path to build the actual
triangle strip geometry.
The general idea is as follows:
(1) Building the path:
At each step along the path, we use a spline function to compute point Pi along the center of the ribbon.
At each step along the path, we can compute direction along the path Wi - Pi+1 - Pi,k
as well as two mutually perpendicular cross vectors Ui and Vi.
We will do successive cross products to compute Ui and Vi at each step, while avoiding twists.
Given initial ribbon direction W0 = normalize(P1 - P0), choose an initial cross vector U0 perpendicular to W0.
Compute V0 = W0 ⨯ U0
For i = 1 to n along path:
Compute Wi = normalize(Pi+1 - Pi)
Compute Ui = normalize(Vi-1 ⨯ Wi)
Compute Vi = normalize(Wi ⨯ Ui)
(2) Building the ribbon:
To build a ribbon with width 2 * r:
For i = 0 to n along path:
The two vertices at this step along the path are at Pi - r * Ui and Pi + r * Ui.
Bump mapping
Bump mapping is an inexpensive way,
created by Jim Blinn in 1977,
to create the illusion of a highly
detailed model, without the expense
of using many triangles.
The trick is to use a texture to
modify the surface normal at each
pixel, before applying a shading
algorithm such as Phong shading.
The result will be that the object
appears to have bumps and other
surface irregularities, even though
the actual geometry is smooth
and featureless.
There are several parts to bump mapping:
- Adding a tangent direction to each vertex in your vertex buffer;
- Creating a bump map image;
- Rendering the bump map texture.
(1) Adding a tangent direction to each vertex:
In order to support bump mapping, you need to add a tangent vector
[tx,ty,tz]
to each vertex in your shapes (cubes, spheres, cylinders, etc).
So instead of storing
VERTEX_SIZE = 8
values per vertex in your vertex buffer, you will need to
store
VERTEX_SIZE = 11
values:
vertex = [ x,y,z, nx,ny,nz, tx,ty,tz, u,v ]
You can compute the tangent at each vertex by taking successive differences between
vertex positions:
tangenti,j = normalize(Pi+1,j - Pi,j)
where Pi,j is the position of the vertex at (ui,vj).
(2) Creating a bump map image:
You need to use the red,green and blue channels of your texture
image to encode the variations in u,v and w of the normal,
where u is the direction tangent to the surface along texture paramater u, w is the direction of your surface normal,
and v is the binormal, which is perpendicular to both the normal and the tangent,
is the direction tangent to the surface along texture paramater v.
For each of r,g,b, a pixel value between 0 and 255 encodes a value between -1.0 and +1.0.
(3) Rendering the bump map texture:
To render the bump map, you need to do some work in both your vertex shader and in your fragment shader.
In the vertex shader,
after you have transformed the normal and tangent vectors,
you need to compute the binormal:
vBinormal = normalize(cross(vNormal, vTangent));
In the fragment shader, you need to retrieve the values r,g,b from the texture map, and
then use those values to vary the surface normal, before doing Phong shading:
vec4 b = texture2D(uSampler[1], vUV) - 0.5; // We are assuming here that the bump map is texture[1].
vec3 normal = normalize(b.r * vTangent + b.g * vBinormal + b.b * vNormal);
Concept of locking for multi-user VR
We will be giving you the software infrastructure next Monday
to do the locking required for interaction between
multiple users. Meanwhile, just so you can get used to the idea,
here is what that interface will look like:
// CREATING A NEW LOCK
let lock1 = client.createLock();
...
// DEFINE ACTION FOR THE PLAYER WHO SUCCESSFULLY GRABS THE LOCK.
// playerID IS THE PLAYER WHO SUCCEEDED IN GRABBING THE LOCK.
// RETURN true TO CONTINUE HOLDING THE LOCK.
// OTHERWISE THE LOCK IS RELEASED AFTER THIS CALL.
lock1.onLock = playerID => { ... }
...
// REQUEST A LOCK. IF SUCCESSFUL, YOUR onLock() CALLBACK WILL BE CALLED.
lock1.requestLock();
Two link IK
When building animated characters, you sometimes
want to connect a shoulder to a wrist, by figuring out the
position of an elbow,
or connect a hip to an ankle, by figuring out the position of a knee.
This process is called inverse kinematics, or IK for short.
In particular, when there is only a single intermediate joint to be computed,
the process is called "two link IK".
High Level Concept:
The elbow is going to be at some point on a sphere
centered at the shoulder with radius
a ,
where
a
is the length of the upper arm.
It is also going to be at some point on a sphere
centered at the wrist with radius
b ,
where
b
is the length of the lower arm.
The intersection of these two spheres is a circle.
If you give a hint as to the direction the elbow is pointing,
that will allow you to compute the point along this circle
which is nearest to your hint direction,
and you can place the elbow there.
Implementation:
Given a dot product function
dot(a,b) ,
and assuming the shoulder is at the origin,
the wrist is at point
C ,
and the hint direction is placed into vector
D
before calling the function below,
the correct elbow direction will be placed into
D
and
also returned as the value of the function:
function ik(a, b, C, D) {
let cc = dot(C,C), x = (1 + (a*a - b*b)/cc) / 2, y = dot(C,D)/cc;
for (let i = 0 ; i < 3 ; i++) D[i] -= y * C[i];
y = sqrt(max(0,a*a - cc*x*x) / dot(D,D));
for (let i = 0 ; i < 3 ; i++) D[i] = x * C[i] + y * D[i];
return D;
}
Cool video we saw
At the end of class we watched the 2005 short film
Carlitopolis.
| |