CT336/CT404 Graphics & Image Processing Section 3 Transformations [Translation, Rotation and Scaling] 3D: X3D 2D: Canvas 3D Translation To translate a 3D point, modify each dimension separately: x' = x + a1 y' = y + a2 z' = z + a3 Or in Matrix format: 3D Rotation: axis of rotation In 3D, we need to specify not only the angle (or amount) of rotation, but also the axis of rotation The “Right Hand Rule” for rotations: grasp axis with right hand with thumb oriented in positive direction of axis Your fingers will then curl in the direction of positive rotation for that axis Rotation about the Principle Axes These matrices define rotations by angle about the principle axes As a point rotates about the x axis, its x component remains unchanged To use one of these matrices, multiply your [x y z] matrix by it, e.g. [x' y' z'] = [x y z] RX Transformations in X3D A 3D coordinate system is a set of X, Y and Z axes that cross at an origin. Positions within a coordinate system are specified by X, Y and Z distances measured along each of the axes In X3D, translation, rotation and scaling of shapes are all accomplished using the Transform node A Transform node defines a child or nested coordinate system: any shapes contained within it will be centred on the origin of its own coordinate system The top-most coordinate system is called the root or world coordinate system Nested Coordinate Systems (Top): a nested coordinate system defined as a translation relative to the world coordinate system by -3.0 units along the X axis, 2.0 units along the Y axis, and 2.0 units along the Z axis (Bottom): A box shape contained in this nested coordinate system Why Nested Coordinate Systems are Useful Consider the steps required to build a room with a table and a lamp on it: Build a lamp, with each component relative to a lamp coordinate system Build a table, with each component relative to a table coordinate system Place the lamp on the table by nesting the lamp coordinate system in the table coordinate system Build a room, with each component relative to a room coordinate system Place the table (and its lamp) by nesting the table coordinate system in the room coordinate system This approach has allowed us to build each piece of the world independently: the structure of the lamp, for example, is independent of where it is placed on the table. This helps manage complexity as well as promote reusability and simplify the transformations of objects composed of multiple primitive shapes The X3D Transform Node The Transform node provides the functionality of translation, rotation and scaling Its children are typically Shape nodes and further Transform nodes By putting a Transform node inside (as a child of) another transform node, you are creating a child/nested coordinate system < Transform bboxCenter='0 0 0' bboxSize='-1 -1 -1' center='0 0 0' rotation='0 0 1 0' scale='1 1 1' translation='0 0 0' > </Transform> (These are the default values for the fields) X3D Translation Example <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "http://www.web3d.org/specifications/x3d-3.0.dtd"> <X3D xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' profile='Full' version='3.0' xsd:noNamespaceSchemaLocation='http://www.web3d.org/specifications/x3d-3.0.xsd'> <Scene DEF='scene'> <Transform translation='2 1 -2'> <Shape> <Appearance> <Material/> </Appearance> <Cylinder/> </Shape> </Transform> </Scene> </X3D> X3D Nested Coordinate System Example – a hut <Scene DEF='scene'> <Group> <Shape> <Appearance> <Material diffuseColor='0.7 0.0 0.2'/> </Appearance> <Cylinder radius='2'/> </Shape> <Transform translation='0 2 0'> <Shape> <Appearance> <Material diffuseColor='0.7 0.0 0.7'/> </Appearance> <Cone bottomRadius='2.5'/> </Shape> </Transform> </Group> </Scene> X3D Example – Two archways on the ground <Scene DEF='scene'> <Group> <Shape> <Appearance DEF='White'> <Material/> </Appearance> <Box size='25 0.1 25'/> </Shape> <Transform DEF='LeftColumn' translation='-2 3 0'> <Shape DEF='Column'> <Appearance USE='White'/> <Cylinder height='6' radius='0.3'/> </Shape> </Transform> <Transform DEF='RightColumn' translation='2 3 0'> <Shape USE='Column'/> </Transform> <Transform DEF='ArchwaySpan' translation='0 6.05 0'> <Shape> <Appearance USE='White'/> <Box size='4.6 0.4 0.6'/> </Shape> </Transform> <Transform translation='0 0 -2'> <Transform USE='LeftColumn'/> <Transform USE='RightColumn'/> <Transform USE='ArchwaySpan'/> </Transform> </Group> </Scene> X/Y/Z Rotations: Pitch, Yaw, Roll Rotation about the x axis is often called ‘pitch’ Rotation about the y axis is often called ‘yaw’ Rotation about the z axis is often called ‘roll’ Since all components of this aeroplane are inside its coordinate system, transformations of that coordinate system will preserve the relative positions of the components Rotation using the Transform Node In X3D, you can rotate about any line, not just the principal axes. You specify a 3D co-ordinate, and the axis of rotation is defined as the line that joins the origin to this point. e.g. a toy spinning top will rotate about the Y axis, defined as (0.0, 1.0, 0.0) You must also specify the amount to rotate by: this is measured as an angle in Radians Hence, rotations are defined using 4 numbers: the first 3 define the axis and the 4th defines the angle (amount) the centre of rotation is, by default, the origin of the coordinate system. To change this, specify a 3D co-ordinate in the transform node's center field Rotation Example <Scene DEF='scene'> <Transform rotation='1 0 0 -0.785'> <Shape> <Appearance> <Material/> </Appearance> <Box/> </Shape> </Transform> </Scene> Example <Scene DEF='scene'> <Group> <Shape DEF='Arm1'> <Appearance> <Material/> </Appearance> <Cylinder height='1' radius='0.1'/> </Shape> <Transform rotation='0 0 1 1.047'> <Shape USE='Arm1'/> </Transform> <Transform rotation='0 0 1 2.094'> <Shape USE='Arm1'/> </Transform> </Group> </Scene> Another Example <Scene DEF='scene'> <Group> <Shape DEF='Arm1'> <Appearance> <Material/> </Appearance> <Cylinder height='1' radius='0.1'/> </Shape> <Transform DEF='Arm2' rotation='0 0 1 1.047'> <Shape USE='Arm1'/> </Transform> <Transform DEF='Arm3' rotation='0 0 1 2.094'> <Shape USE='Arm1'/> </Transform> <Transform rotation='0 1 0 1.785'> <Transform USE='Arm2'/> <Transform USE='Arm3'/> </Transform> </Group> </Scene> Example using centre of rotation <Scene DEF='scene'> <Group> <Shape> <Appearance DEF='White'> <Material/> </Appearance> <Cylinder height='0.01' radius='0.1'/> </Shape> <Transform center='0 -0.15 0' rotation='1 0 0 -0.7' translation='0 0.15 0'> <Shape DEF='LampArm'> <Appearance USE='White'/> <Cylinder height='0.3' radius='0.01'/> </Shape> <Transform center='0 -0.15 0' rotation='1 0 0 1.9' translation='0 0.3 0'> <Shape USE='LampArm'/> </Transform> </Transform> </Group> </Scene> Scaling in X3D The Transform node allows you to scale a co-ordinate system's size relative to its parent co-ordinate system The scale is specified as a multiplication factor: to make something half of its original size, its scale factor is 0.5, while to make it triple its original size, its scale factor is 3.0 The Transform node's scale field uses three scale factors: one for each axis. By using different numbers here, you will scale a coordinate system by different amounts in the different directions. The transform node's scaleOrientation field allows you to specify a rotation prior to scaling, thereby enabling you to stretch a shape in any direction, not just along the principal axes The transform node's center field defines the centre point for scaling (as well as rotation). This allows you to scale a shape without moving it (e.g. a growing tree) Scaling Example <Scene DEF='scene'> <Group> <Transform DEF='Wing' scale='0.5 1 1.5'> <Shape> <Appearance DEF='White'> <Material/> </Appearance> <Cylinder height='0.025'/> </Shape> </Transform> <Transform DEF='Fuselage' scale='2 0.2 0.5'> <Shape> Fuselage <Appearance USE='White'/> <Sphere/> </Shape> Wing </Transform> <Transform scale='0.3 2 0.75'> <Transform USE='Wing'/> <Transform USE='Fuselage'/> </Transform> </Group> </Scene> 2D Translations with Canvas <html> <head> <script> function draw() { var canvas = document.getElementById("canvas"); var context = canvas.getContext('2d'); context.save(); // save the default (root) co-ord system canvasTranslateExample.html context.fillStyle="#CC00FF"; // purple context.fillRect(100,0,100,100); // translates from the origin, producing a nested co-ordinate system context.translate(75,50); context.fillStyle="#FFFF00"; // yellow context.fillRect(100,0,100,100); // transforms further, to produce another nested co-ord system context.translate(75,50); context.fillStyle="#0000FF"; // blue context.fillRect(100,0,100,100); context.restore(); // recover the default (root) co-ord system context.translate(-75,90); context.fillStyle="#00FF00"; // green context.fillRect(100,0,100,100); } </script> </head> These coordinate systems are nested <body onload="draw();"> <canvas id="canvas" width="600" height="600"></canvas> </body> </html> Order of Transformations Rotation by 45 degrees Then Translation 2 units along the red axis Translation 2 units along the red axis Then Rotation by 45 degrees Order of Transforms example canvasOrderOfTransformsExample.html <html> <head> <script> function draw() { var canvas = document.getElementById("canvas"); var context = canvas.getContext('2d'); context.save(); // save the default (root) co-ord system context.fillStyle="#CC00FF"; // purple context.fillRect(0,0,100,100); // positioned with TL corner at 0,0 // translate then rotate context.translate(100,0); context.rotate(Math.PI/3); context.fillStyle="#FF0000"; // red context.fillRect(0,0,100,100); // positioned with TL corner at 0,0 // recover the root co-ord system context.restore(); // rotate then translate context.rotate(Math.PI/3); context.translate(100,0); context.fillStyle="#FFFF00"; // yellow context.fillRect(0,0,100,100); // positioned with TL corner at 0,0 } </script> </head> <body onload="draw();"> <canvas id="canvas" width="600" height="600"></canvas> </body> </html> Canvas scale example canvasScaleExample.html <html> <head> <script> function draw() { var canvas = document.getElementById("canvas"); var context = canvas.getContext('2d'); context.fillStyle="#CC00FF"; // purple context.fillRect(0,0,100,100); // positioned with TL corner at 0,0 context.translate(150,0); context.scale(2,1.5); context.fillStyle="#FF0000"; // red context.fillRect(0,0,100,100); // positioned with TL corner at 0,0 } </script> </head> <body onload="draw();"> <canvas id="canvas" width="600" height="600"></canvas> </body> </html> Canvas: programmatic graphics example canvasRotateLoopExample.html <html> <head> <script> function draw() { var canvas = document.getElementById("canvas"); var context = canvas.getContext('2d'); context.translate(150,150); for (i=0;i<15;i++) { context.fillStyle = "rgb("+(i*255/15)+",0,0)"; context.fillRect(0,0,100,100); context.rotate(2*Math.PI/15); } } </script> </head> <body onload="draw();"> <canvas id="canvas" width="600" height="600"></canvas> </body> </html>