🎨 3D Transform Fundamentals

🎯 What are 3D Transforms?

3D transforms are operations that change the position, orientation, or scale of objects in three-dimensional space. They are fundamental to computer graphics, robotics, and computer vision.

Key concept: Transforms are represented using linear algebra, typically with 4×4 transformation matrices in homogeneous coordinates.

Deep Explanation

3D transforms are the foundation of computer graphics. They allow us to position objects in a scene, animate them, and project them onto a 2D screen using translation, rotation, scaling, and projection.

Why it matters: Understanding 3D transforms is essential for game development, 3D modeling, AR/VR, and computer vision.

🎨 Position📊 Orientation📋 Scale🔄 Linear Algebra
# 3D transform basics import numpy as np # Define a point in 3D point = np.array([1.0, 2.0, 3.0]) # Translation matrix (move by (2, 3, 4)) def translation_matrix(tx, ty, tz): return np.array([ [1, 0, 0, tx], [0, 1, 0, ty], [0, 0, 1, tz], [0, 0, 0, 1] ]) # Apply transform point_h = np.array([1.0, 2.0, 3.0, 1.0]) # Homogeneous T = translation_matrix(2, 3, 4) transformed = T @ point_h print(transformed[:3]) # [3.0, 5.0, 7.0]

📐 Vectors & Points

🎯 3D Geometry

3D transforms operate on points (positions) and vectors (directions). Points and vectors behave differently under transforms.

Geometric Primitives

Points: Represent positions in space (P = [x, y, z]). Vectors: Represent directions and magnitudes (V = [dx, dy, dz]). Difference: Points are position-dependent; vectors are position-independent.

Operations: Vector addition, dot product, cross product, scalar multiplication.

📐 Points📊 Vectors📋 Dot Product🔄 Cross Product
# Vector operations class Vector3D: def __init__(self, x, y, z): self.x = x self.y = y self.z = z def dot(self, other): return self.x * other.x + self.y * other.y + self.z * other.z def cross(self, other): return Vector3D( self.y * other.z - self.z * other.y, self.z * other.x - self.x * other.z, self.x * other.y - self.y * other.x ) def magnitude(self): return math.sqrt(self.x**2 + self.y**2 + self.z**2) def normalize(self): mag = self.magnitude() if mag == 0: return Vector3D(0, 0, 0) return Vector3D(self.x/mag, self.y/mag, self.z/mag) def __add__(self, other): return Vector3D(self.x + other.x, self.y + other.y, self.z + other.z) def __mul__(self, scalar): return Vector3D(self.x * scalar, self.y * scalar, self.z * scalar) # Usage v1 = Vector3D(1, 0, 0) v2 = Vector3D(0, 1, 0) v3 = v1.cross(v2) # (0, 0, 1)

📊 Transformation Matrices

🎯 Matrix Representation

3D transforms are represented by 4×4 matrices in homogeneous coordinates. Matrix multiplication composes transforms.

Matrix Properties

Affine transforms: Preserve lines and parallelism (translation, rotation, scaling, shear). Matrix multiplication: Non-commutative (order matters). Inverse: Undoes a transform. Identity: Does nothing.

Composition: M_total = M_n * ... * M_2 * M_1 (applied right to left).

📊 4×4📋 Affine🔄 Non-Commutative📈 Inverse
# Matrix operations def identity_4x4(): return np.eye(4) def matrix_multiply(A, B): return A @ B def compose_transforms(transforms): # Compose multiple transforms (apply in order) result = identity_4x4() for transform in transforms: result = transform @ result return result # Example: rotate then translate def transform_point(point, matrix): point_h = np.array([point[0], point[1], point[2], 1.0]) result = matrix @ point_h return result[:3]

🔄 Translation

🎯 Moving Objects

Translation moves an object by a vector (tx, ty, tz). It's the simplest 3D transform.

Translation Details

Matrix: [[1, 0, 0, tx], [0, 1, 0, ty], [0, 0, 1, tz], [0, 0, 0, 1]]. Inverse: Translate by (-tx, -ty, -tz). Properties: Commutative with scaling? No. With other translations? Yes.

Application: Positioning objects in a scene.

🔄 Move📊 Vector📋 Inverse🔄 Commutative
# Translation def translation(tx, ty, tz): return np.array([ [1, 0, 0, tx], [0, 1, 0, ty], [0, 0, 1, tz], [0, 0, 0, 1] ]) # Translation inverse def translation_inverse(T): return translation(-T[0,3], -T[1,3], -T[2,3]) # Apply translation to multiple points def translate_points(points, tx, ty, tz): T = translation(tx, ty, tz) transformed = [] for p in points: p_h = np.array([p[0], p[1], p[2], 1.0]) result = T @ p_h transformed.append(result[:3]) return transformed

🔄 Rotation

🎯 Rotating Objects

Rotation rotates an object around an axis by an angle. It is defined by axis and angle.

Rotation Details

Axis-aligned: Rotation around X, Y, or Z axis. Arbitrary axis: Rotation around any unit vector. Matrix: Uses sine and cosine. Properties: Orthogonal (R^T = R^{-1}), determinant = 1.

Applications: Orienting objects, camera movement.

🔄 Angle📊 Axis📋 Orthogonal🔄 Determinant 1
# Rotation matrices def rotation_x(angle): c = np.cos(angle) s = np.sin(angle) return np.array([ [1, 0, 0, 0], [0, c, -s, 0], [0, s, c, 0], [0, 0, 0, 1] ]) def rotation_y(angle): c = np.cos(angle) s = np.sin(angle) return np.array([ [c, 0, s, 0], [0, 1, 0, 0], [-s, 0, c, 0], [0, 0, 0, 1] ]) def rotation_z(angle): c = np.cos(angle) s = np.sin(angle) return np.array([ [c, -s, 0, 0], [s, c, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ]) # Rotation around arbitrary axis (Rodrigues formula) def rotation_axis(axis, angle): axis = axis / np.linalg.norm(axis) x, y, z = axis c = np.cos(angle) s = np.sin(angle) t = 1 - c return np.array([ [t*x*x + c, t*x*y - z*s, t*x*z + y*s, 0], [t*x*y + z*s, t*y*y + c, t*y*z - x*s, 0], [t*x*z - y*s, t*y*z + x*s, t*z*z + c, 0], [0, 0, 0, 1] ])

📏 Scaling

🎯 Changing Size

Scaling changes the size of an object. Uniform scaling preserves proportions; non-uniform scaling stretches or compresses.

Scaling Details

Uniform: sx = sy = sz. Non-uniform: Different factors per axis. Matrix: [[sx, 0, 0, 0], [0, sy, 0, 0], [0, 0, sz, 0], [0, 0, 0, 1]]. Inverse: Scale by 1/sx, 1/sy, 1/sz.

Properties: Does not commute with translation (scaling around origin).

📏 Uniform📊 Non-Uniform📋 Inverse🔄 Non-Commutative
# Scaling matrix def scale(sx, sy, sz): return np.array([ [sx, 0, 0, 0], [0, sy, 0, 0], [0, 0, sz, 0], [0, 0, 0, 1] ]) # Scale around a point (not origin) def scale_around_point(sx, sy, sz, center): # Translate to origin, scale, translate back T1 = translation(-center[0], -center[1], -center[2]) S = scale(sx, sy, sz) T2 = translation(center[0], center[1], center[2]) return compose_transforms([T2, S, T1]) # Scale inverse def scale_inverse(S): return scale(1/S[0,0], 1/S[1,1], 1/S[2,2])

🔀 Shear

🎯 Shearing Transforms

Shear distorts an object by sliding layers along an axis. It is used in oblique projections and deformations.

Shear Details

Matrix: [[1, sh_xy, sh_xz, 0], [sh_yx, 1, sh_yz, 0], [sh_zx, sh_zy, 1, 0], [0, 0, 0, 1]]. Properties: Preserves area/volume. Applications: Creating oblique views, distorting text.

Combination: Often combined with other transforms.

🔀 Distortion📊 Sliding📋 Preserve Area🔄 Oblique
# Shear matrices def shear_xy(sh_xy, sh_yx): # Shear in XY plane return np.array([ [1, sh_xy, 0, 0], [sh_yx, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ]) def shear_xz(sh_xz, sh_zx): return np.array([ [1, 0, sh_xz, 0], [0, 1, 0, 0], [sh_zx, 0, 1, 0], [0, 0, 0, 1] ]) def shear_yz(sh_yz, sh_zy): return np.array([ [1, 0, 0, 0], [0, 1, sh_yz, 0], [0, sh_zy, 1, 0], [0, 0, 0, 1] ]) # General shear def shear_3d(sh_xy, sh_xz, sh_yx, sh_yz, sh_zx, sh_zy): return np.array([ [1, sh_xy, sh_xz, 0], [sh_yx, 1, sh_yz, 0], [sh_zx, sh_zy, 1, 0], [0, 0, 0, 1] ])

🧮 Homogeneous Coordinates

🎯 4D Representation

Homogeneous coordinates represent 3D points as 4D vectors (x, y, z, w). This enables affine transforms with a single matrix.

Homogeneous Details

Point: (x, y, z, 1). Vector: (x, y, z, 0). Perspective division: (x/w, y/w, z/w). Projective transforms: w can be anything.

Advantages: Unifies affine transforms, enables perspective projection.

🧮 4D📊 w=1 for points📋 w=0 for vectors🔄 Perspective
# Homogeneous coordinate operations def to_homogeneous(point_3d): # Convert 3D point to homogeneous (w=1) return np.array([point_3d[0], point_3d[1], point_3d[2], 1.0]) def to_homogeneous_vector(vector_3d): # Convert 3D vector to homogeneous (w=0) return np.array([vector_3d[0], vector_3d[1], vector_3d[2], 0.0]) def from_homogeneous(point_h): # Convert homogeneous to 3D (perspective division) w = point_h[3] if w == 0: return None # Point at infinity return np.array([point_h[0]/w, point_h[1]/w, point_h[2]/w]) def transform_homogeneous(point_h, matrix): # Apply transform in homogeneous coordinates return matrix @ point_h # Example: Transform a point point = np.array([1, 2, 3]) point_h = to_homogeneous(point) T = translation(2, 3, 4) result_h = transform_homogeneous(point_h, T) result = from_homogeneous(result_h) # (3, 5, 7)

🌀 Quaternions

🎯 Quaternion Rotation

Quaternions are a mathematical system for representing rotations. They avoid gimbal lock and provide smooth interpolation.

Quaternion Details

Format: q = (w, x, y, z) where w is scalar and (x,y,z) is vector. Rotation: q = (cos(θ/2), sin(θ/2) * axis). Multiplication: Non-commutative. SLERP: Smooth interpolation between quaternions.

Advantages: No gimbal lock, compact (4 numbers vs 9 for matrix).

🌀 w,x,y,z📊 Unit Quaternion📋 SLERP🔄 No Gimbal Lock
# Quaternion class class Quaternion: def __init__(self, w, x, y, z): self.w = w self.x = x self.y = y self.z = z def normalize(self): mag = math.sqrt(self.w**2 + self.x**2 + self.y**2 + self.z**2) return Quaternion(self.w/mag, self.x/mag, self.y/mag, self.z/mag) def conjugate(self): return Quaternion(self.w, -self.x, -self.y, -self.z) def multiply(self, other): return Quaternion( self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z, self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y, self.w * other.y - self.x * other.z + self.y * other.w + self.z * other.x, self.w * other.z + self.x * other.y - self.y * other.x + self.z * other.w ) def rotate_point(self, point): # Rotate a 3D point using quaternion p = Quaternion(0, point[0], point[1], point[2]) q = self q_inv = q.conjugate() result = q.multiply(p).multiply(q_inv) return np.array([result.x, result.y, result.z]) def to_rotation_matrix(self): # Convert to 3x3 rotation matrix w, x, y, z = self.w, self.x, self.y, self.z return np.array([ [1 - 2*y*y - 2*z*z, 2*x*y - 2*w*z, 2*x*z + 2*w*y], [2*x*y + 2*w*z, 1 - 2*x*x - 2*z*z, 2*y*z - 2*w*x], [2*x*z - 2*w*y, 2*y*z + 2*w*x, 1 - 2*x*x - 2*y*y] ]) # Create rotation quaternion from axis-angle def quaternion_from_axis_angle(axis, angle): axis = axis / np.linalg.norm(axis) half_angle = angle / 2 return Quaternion( np.cos(half_angle), axis[0] * np.sin(half_angle), axis[1] * np.sin(half_angle), axis[2] * np.sin(half_angle) )

📊 Euler Angles

🎯 Euler Angle Representation

Euler angles represent rotation as three successive rotations around the axes (e.g., roll, pitch, yaw).

Euler Details

Order: XYZ, ZYX, etc. Gimbal lock: Loss of one degree of freedom when two axes align. Advantages: Intuitive for humans. Disadvantages: Gimbal lock, non-unique representation.

Applications: Aircraft orientation, game cameras.

📊 Roll/Pitch/Yaw📋 Order🔄 Gimbal Lock📈 Non-Unique
# Euler angles to rotation matrix (XYZ order) def euler_to_matrix(roll, pitch, yaw): # Roll (X), Pitch (Y), Yaw (Z) Rz = rotation_z(yaw) Ry = rotation_y(pitch) Rx = rotation_x(roll) return compose_transforms([Rz, Ry, Rx]) # Matrix to Euler angles (XYZ order) def matrix_to_euler(R): # Extract euler angles from 3x3 rotation matrix # R is 3x3 or 4x4 matrix if R.shape[0] == 4: R = R[:3, :3] # Handle gimbal lock if abs(R[0, 2]) < 1 - 1e-8: yaw = np.arctan2(-R[0, 1], R[0, 0]) pitch = np.arcsin(R[0, 2]) roll = np.arctan2(-R[1, 2], R[2, 2]) else: # Gimbal lock roll = 0 if R[0, 2] < 0: pitch = np.pi / 2 yaw = np.arctan2(R[1, 0], R[1, 1]) else: pitch = -np.pi / 2 yaw = np.arctan2(-R[1, 0], R[1, 1]) return roll, pitch, yaw # Quaternion to Euler def quaternion_to_euler(q): # q is Quaternion object # Convert to matrix first R = q.to_rotation_matrix() return matrix_to_euler(R)

👁️ View Transform

🎯 Camera Position

The view transform positions the camera in the scene. It maps world coordinates to camera coordinates.

View Transform Details

Look-at matrix: Position camera at eye, looking at target. Components: Position, target, up vector. Inverse: Model transform (placing objects in world).

Applications: 3D rendering, AR/VR, navigation.

👁️ Look-At📊 Camera📋 Eye/Target/Up🔄 Model
# Look-at matrix (camera view) def look_at(eye, target, up): # eye: camera position (3D vector) # target: point camera is looking at (3D vector) # up: up direction (3D vector) z = (eye - target) / np.linalg.norm(eye - target) x = np.cross(up, z) / np.linalg.norm(np.cross(up, z)) y = np.cross(z, x) # Create rotation matrix R = np.array([ [x[0], x[1], x[2], 0], [y[0], y[1], y[2], 0], [z[0], z[1], z[2], 0], [0, 0, 0, 1] ]) # Translate by -eye T = translation(-eye[0], -eye[1], -eye[2]) return R @ T # Or use a simpler implementation def look_at_simple(eye, target, up): forward = (target - eye) / np.linalg.norm(target - eye) right = np.cross(forward, up) / np.linalg.norm(np.cross(forward, up)) up_new = np.cross(right, forward) # Build matrix return np.array([ [right[0], right[1], right[2], -np.dot(right, eye)], [up_new[0], up_new[1], up_new[2], -np.dot(up_new, eye)], [-forward[0], -forward[1], -forward[2], np.dot(forward, eye)], [0, 0, 0, 1] ])

🎯 Projection Transform

🎯 3D to 2D Projection

The projection transform maps 3D points to 2D screen coordinates. Perspective and orthographic projections are the main types.

Projection Types

Perspective: Objects farther away appear smaller (realistic). Orthographic: No perspective distortion (technical drawings). Frustum: View volume for perspective projection.

Matrix: Projection matrix + perspective division.

🎯 Perspective📊 Orthographic📋 Frustum🔄 Division
# Perspective projection matrix def perspective(fov_y, aspect, near, far): # fov_y: vertical field of view in radians # aspect: width / height # near, far: clipping planes f = 1.0 / np.tan(fov_y / 2.0) return np.array([ [f / aspect, 0, 0, 0], [0, f, 0, 0], [0, 0, (far + near) / (near - far), (2 * far * near) / (near - far)], [0, 0, -1, 0] ]) # Orthographic projection def orthographic(left, right, bottom, top, near, far): return np.array([ [2/(right-left), 0, 0, -(right+left)/(right-left)], [0, 2/(top-bottom), 0, -(top+bottom)/(top-bottom)], [0, 0, -2/(far-near), -(far+near)/(far-near)], [0, 0, 0, 1] ]) # Apply projection and perspective division def project_point(point, projection_matrix): point_h = to_homogeneous(point) projected = projection_matrix @ point_h return from_homogeneous(projected)

🔄 Compositing

🎯 Transform Composition

Compositing combines multiple transforms into a single matrix. The order of operations matters.

Composition Rules

Local vs World: Local transforms are applied in object space. Order: Scale → Rotate → Translate (for local). Parent hierarchy: Children inherit parent transforms.

Matrix stack: Push/pop for hierarchical animation.

🔄 Hierarchy📊 Local/World📋 Stack🔄 Inheritance
# Transform stack class TransformStack: def __init__(self): self.stack = [identity_4x4()] def push(self): self.stack.append(self.stack[-1].copy()) def pop(self): if len(self.stack) > 1: return self.stack.pop() def multiply(self, matrix): self.stack[-1] = self.stack[-1] @ matrix def get_current(self): return self.stack[-1] # Object hierarchy transform class TransformNode: def __init__(self, name): self.name = name self.children = [] self.parent = None self.local_transform = identity_4x4() def add_child(self, child): self.children.append(child) child.parent = self def get_world_transform(self): if self.parent: return self.parent.get_world_transform() @ self.local_transform return self.local_transform def set_transform(self, T): self.local_transform = T

💼 Applications

🎯 Where 3D Transforms are Used

3D transforms are essential in game development, 3D modeling, AR/VR, robotics, and computer vision.

Application Domains

Games: Object positioning, animation, camera control. 3D modeling: Manipulating vertices and objects. AR/VR: Tracking and rendering. Robotics: Kinematics and motion planning. Vision: Camera calibration and 3D reconstruction.

Medical imaging: Registration and visualization.

🎮 Games📊 Modeling📋 AR/VR🔄 Robotics
# Application: 3D object renderer class Renderer: def __init__(self): self.objects = [] self.camera = Camera() def render_frame(self): # Get view and projection transforms view_matrix = self.camera.get_view_matrix() proj_matrix = self.camera.get_projection_matrix() for obj in self.objects: # Get object's transform model_matrix = obj.get_world_transform() # Model-View-Projection matrix mvp = proj_matrix @ view_matrix @ model_matrix # Transform vertices transformed_vertices = [] for vertex in obj.vertices: vertex_h = to_homogeneous(vertex) transformed = mvp @ vertex_h screen_pos = from_homogeneous(transformed) transformed_vertices.append(screen_pos) # Draw object self.draw(transformed_vertices, obj.color) def draw(self, vertices, color): # Rasterization code pass # Application: Animation with keyframes class Animation: def __init__(self, target, keyframes): self.target = target self.keyframes = keyframes # (time, position, rotation, scale) self.current_time = 0 def update(self, delta_time): self.current_time += delta_time # Interpolate between keyframes (SLERP for rotation) # Apply transform to target pass