33
Transforms Hierarchical Modeling Scene Graphs Using hierarchical modeling techniques in 3D software design Transforms Local basis Matrix math review Matrices and OpenGL Hierarchical modeling Benefits of hierarchical modeling Hierarchical modeling in C++ and OpenGL Recursive Hierarchical modeling

Transforms Hierarchical Modeling Scene Graphs Using hierarchical modeling techniques in 3D software design Transforms Local basis Matrix math review Matrices

Embed Size (px)

Citation preview

TransformsHierarchical ModelingScene Graphs

Using hierarchical modeling techniques in 3D software designTransforms

Local basis Matrix math review Matrices and OpenGL

Hierarchical modeling Benefits of hierarchical modeling Hierarchical modeling in C++ and OpenGL

Recursive Hierarchical modeling

What does it mean to talk about the center of the world?

“Giant Turtle”, from the Discworld series. Image (c) Jay Hurst

Transforms

Relative motion All motion takes place relative to a local origin.

Ex: throwing a ball to a friend as you both ride in a train.

The term local origin refers to the (0,0,0) that you’ve chosen to measure motion from.

The local origin may be moving relative to some greater frame of reference.

Transforms

Transforms

The following terms are used more-or-less interchangeably: Local basis Local transform Frame of reference

Each of these refers to the location, in the greater world, of the (0,0,0) you’re working with. They also include the concept of the current basis, which is the

X, Y, Z directions. By rotating the basis of a coordinate system, you can rotate the

world it describes.

Transforms

We’re used to defining points in space as [X,Y,Z]. But what does that actually mean? Where is (0,0,0)?

The actual truth is that there is no (0,0,0) in the real world. Things are always defined relative to each other.

You can move (0,0,0) and thus move all the points defined relative to that origin.

Matrix Math Review

Most matrices in graphics are 4x4:

[ 1 0 0 0 ] // The identity

[ 0 1 0 0 ] // matrix (all

[ 0 0 1 0 ] // 1’s down the

[ 0 0 0 1 ] // main diagonal)

Most vectors in graphics are 1x3:

[ X ]

[ Y ]

[ Z ]

Matrix Math Review

Translation:[ 1 0 0 Tx ]

[ 0 1 0 Ty ]

[ 0 0 1 Tz ]

[ 0 0 0 1 ]

Rotation:[ 1 0 0 0 ]

[ 0 cos(θ) sin(θ) 0 ] // Around X

[ 0 -sin(θ) cos(θ) 0 ]

[ 0 0 0 1 ]

Scaling:[ Sx 0 0 0 ]

[ 0 Sy 0 0 ]

[ 0 0 Sy 0 ]

[ 0 0 0 1 ]

Matrix Math Review

Multiplying a vector by a matrix: M * V = MV

[ 1 0 0 0 ] [ X ]

[ 0 1 0 0 ] * [ Y ] = [ X1 Y1 Z1 ]

[ 0 0 1 0 ] [ Z ]

[ 0 0 0 1 ] [ 1 ]

The formula: X = MRow1 • V = M[0][0]*X + M[1][0]*Y + M[2][0]*Z + M[3][0]

Y = MRow2 • V = M[0][1]*X + M[1][1]*Y + M[2][0]*Z + M[3][1]

Z = MRow3 • V = M[0][2]*X + M[1][2]*Y + M[2][0]*Z + M[3][2]

(Look! Dot products!)

Matrix Math Review

Multiplying a matrix by a matrix:[ 1 0 0 0 ] [ 1 0 0 0 ] [ 1 0 0 0 ]

[ 0 1 0 0 ] * [ 0 1 0 0 ] = [ 0 1 0 0 ]

[ 0 0 1 0 ] [ 0 0 1 0 ] [ 0 0 1 0 ]

[ 0 0 0 1 ] [ 0 0 0 1 ] [ 0 0 0 1 ]

The formula:

M = M1 * M2

M[col a][row b] = M1(row a) • M2(col b)

Matrices - Multiplication in C++

Vec M4x4::operator*(const Vec& V) const

{

Vec transformedPt;

transformedPt[0] = get(0,0)*V[0] + get(1,0)*V[1] + get(2,0)*V[2] + get(3,0);

transformedPt[1] = get(0,1)*V[0] + get(1,1)*V[1] + get(2,1)*V[2] + get(3,1);

transformedPt[2] = get(0,2)*V[0] + get(1,2)*V[1] + get(2,2)*V[2] + get(3,2);

return transformedPt;

}

M4x4 M4x4::operator*(const M4x4& M) const

{

M4x4 retval;

const M4x4 &M1 = *this;

const M4x4 &M2 = M;

for (int row=0; row<4; row++)

for (int col=0; col<4; col++)

retval.data[row + col*4] =

M1.get(0,row) * M2.get(col, 0) +

M1.get(1,row) * M2.get(col, 1) +

M1.get(2,row) * M2.get(col, 2) +

M1.get(3,row) * M2.get(col, 3);

return retval;

}

Matrix Math Review

Example: Translating a point, V at (5,3,5), with the translation (-7,12,0):

[ 1 0 0 -7 ] [ 5 ]

[ 0 1 0 12 ] * [ 3 ] = [ X Y Z ]

[ 0 0 1 0 ] [ 5 ]

[ 0 0 0 1 ] [ 1 ] X = 1*5 + 0*3 + 0*5 + -7*1 = -2 Y = 0*5 + 1*3 + 0*5 + 12*1 = 15 Z = 0*5 + 0*3 + 1*5 + 0*1 = 5

...which is the same as[ 5, 3, 5 ] + [ -7, 12, 5 ] = [ -2, 15, 5 ]

Matrix Math Review

So, in general, you can writeV’ = M * V

to transform a point V by the matrix M. Ex:

M=Translation by (a,b,c)

V=(x,y,z)

V’ = M*V = (a+x, b+y, c+z) Ex:

M=Scale by (d,e,f)

V=(x,y,z)

V’ = M*V = (d*x, e*y, f*z)

This is called transforming V by M or applying the transform M to V.

Matrix Math Review

Of course, once you’ve applied a transform to a point, you have a new point. Which you can transform again with a new transform. V1 = M1 * V V2 = M2 * V1 V3 = M3 * V2 ...

Writing this out longhand, we have V1 = M1 * V V2 = M2 * (M1 * V) V3 = M3 * (M2 * (M1 * V))

Or V3 = (M3 * M2 * M1) * V // We can compose the M’s!

Matrix Math Review

This key idea--that you can compose multiple transforms before applying them to a point--makes it possible to do all sorts of wonderful optimizations. You can build up a series of transformations and compose them

together into a single matrix which rotates and translates and rotates again, then scales and translates once more.

The order of operations is preserved in the composed matrix. The order of the original operations is preserved in the composed matrix exactly as originally entered.

This means that you can build a single matrix which contains within its values an arbitrary sequence of translations, rotations and scales. And you can apply that matrix to your 3D models, to move them about.

Matrices and OpenGL

The Matrix Stacks OpenGL has three matrix stacks that you can use. They are:

ProjectionglMatrixMode(GL_PROJECTION);

Model and View glMatrixMode(GL_MODELVIEW);

TexturesglMatrixMode(GL_TEXTURE);

Every time you call glutSolidSphere, glVertex3f, or any other geometric primitive function, the primitive is transformed by the current topmost entry of the model stack.

(And of the projection stack, but that’s less relevant.)

Matrices and OpenGL

The modelling stack in action: glLoadIdentity(); glTranslatef(0,10,0); glPushMatrix(); glTranslatef(10,0,0); glRotatef(45,0,1,0); glPushMatrix(); glRotatef(45,0,1,0); glPopMatrix(); glPopMatrix(); glPopMatrix();

I * T

I * T

I * T

I * T

I * T * T

I * T

I * T * T * R

I * T

I * T * T * R

I * T * T * R

I * T

I * T * T * R

I * T * T * R * R

Matrices and OpenGL

Example: Say you call glLoadIdentity(), then glTranslatef(0,0,10). Then

the current matrix stack is

[ 1 0 0 0 ]

[ 0 1 0 0 ]

[ 0 0 1 10 ]

[ 0 0 0 1 ] If you were to call glVertex3f(0,0,0) now, it would appear at

[0,0,10]. If you were to call glutSolidSphere() now, it would appear

centered on [0,0,10].

Matrices and OpenGL

Example continued: Now, say you call glPushMatrix(). The current matrix is

copied and the copy is pushed onto the top of the stack. Then you call glRotatef(PI/2, 1,0,0). New topmost matrix is:

[ 1 0 0 0 ] [ 1 0 0 0 ]

[ 0 cos(θ) sin(θ) 0 ] * [ 0 1 0 0 ]

[ 0 -sin(θ) cos(θ) 0 ] [ 0 0 1 10 ]

[ 0 0 0 1 ] [ 0 0 0 1 ]and the old matrix is still on the stack below this new

one. To strip away your changes, call glPopMatrix() and the

modified copy is removed.

Hierarchical Modeling

We can model complex objects out of simple primitives by combining them together:

Scene

Robot Ball

Arm WheelsArm

UpperArm

LowerArm

Hand

Finger Finger

Wheel Wheel

Hierarchical Modeling

A scene graph node is any element in the graph A child node is any node which is an immediate

descendent of the node being discussed The parent node is the node from which the node

being discussed descends The root node is the ancestor of all other nodes

in the scene, and has no parent.Scene

Robot Ball

Arm WheelsArm

UpperArm

LowerArm

Hand

Finger Finger

Wheel Wheel

Hierarchical Modeling

The great strength of hierarchical modeling is that you can create complex models out of simple models. The fly at right was

built from one largesphere, one smallsphere translated alongthe Z axis, and two spheres which werescaled by (5,0.05,0.5)and then rotated a bitto buzz and translatedup the Y axis towardsthe top of the fly.

Hierarchical Modeling meets Transforms

Each object in your scene knows where it is. But you don’t have to store your location and orientation relative to the center of the world.

You can store your location and orientation relative to your parent in the scene graph.

The other great strength of hierarchical modeling is that objects can be constructed relative to their local coordinate system and then positioned relative to their parent object. Moving the parent repositions all children without effort.

Hierarchical Modeling and Transforms

Storing an object’s position and orientation relative to its parent means that you can create complex patterns of motion with simple, basic animations at multiple levels of the scene graph. The Fly Example

Hierarchical Modeling in C++ and OpenGL

Minimium contents of a scene graph node: A pointer to the node’s parent in the scene graph A list or array of the node’s children The node’s position and rotation

class SceneObject

{

SceneObject *m_pParent;

list<SceneObject*> m_lChildren;

Vec m_rotationAxis;

float m_rotationAngle;

Vec m_translation;

};

Hierarchical Modeling in C++ and OpenGL

A better scene graph node: Instead of storing the node’s position and rotation as two

separate pieces of data, you can compose an arbitrary series of transforms (translates, rotates and scales) by storing the object’s transformation in a 4x4 matrix.

class SceneObject

{

SceneObject *m_pParent;

list<SceneObject*> m_lChildren;

Matrix4x4 m_transform;

};

Hierarchical Modeling in C++ and OpenGL

Rendering your scene graph: The scene graph model is based on the concept of recursion. Your display routine will render the current scene graph node,

then call itself to render each of the children of the current node.

Your render() function won’t just render a global variable; instead, you’ll pass it a SceneObject * to render.

It will apply the object’s transform to the GL matrix stack, render the object, render the object’s children, and then pop the local transform off of the stack.

Hierarchical Modeling in C++ and OpenGL

The pseudocode of a renderer:void RenderObject(SceneObject *pObj)

{

glPushMatrix();

glMultMatrix(pObj->getTransform());

pObj->render();

for each child of pObj, do

RenderObject(child);

glPopMatrix();

}

void displayFunction(void)

{

RenderObject(pSceneRoot);

}

Hierarchical Modeling in C++ and OpenGL

To use hierarchical modeling effectively,

you need to create a family of C++ classes

to store the objects in your scene graph.

Your base class will contain your parent and child pointers and your local transform. It should also declare a virtual render() method.

Your derived classes will override the render() method of their base class to render the geometry of the object they represent.

Ex: SceneObject -> Sphere -> Ball -> JugglingBall

Hierarchical Modeling in C++ and OpenGL

A sample base class for a scene graph node:class SceneObject

{

private:

SceneObject* m_pParent;

std::list<SceneObject*> m_lChildren;

M4x4 m_transform;

public:

SceneObject(void);

virtual ~SceneObject(void);

SceneObject *addChild(SceneObject *pChild);

void setParent(SceneObject *pParent);

M4x4 &getTransform(void) { return m_transform; }

std::list<SceneObject*> &getChildren(void) { return m_lChildren; }

virtual void render(void) { /* do nothing */ }

};

Hierarchical Modeling in C++ and OpenGL

A class to render a sphere:class Sphere : public SceneObject

{

private:

float m_radius;

public:

Sphere(float rad = 1.0) { m_radius = rad; }

virtual ~SceneObject(void) { }

virtual void render(void)

{

glutSolidSphere(m_radius, 20, 20);

}

};

Recursive Hierarchical Modeling

You build your hierarchical objects as C++ classes. That means that you could make an instance of your object a

child of another instance of your object. You could potentially build a chain of nested instances of your

object, each inheriting from the next.

Recursive Hierarchical Modeling

By applying small transforms to every level of your scene graph, a recursive model can quickly generate some amazing images.