Introduction

Physical simulation in 3D graphics involves using mathematical models to replicate real-world physical phenomena. This module will cover the fundamental concepts and techniques used to simulate physics in a 3D environment, including forces, motion, collisions, and fluid dynamics.

Key Concepts

  1. Newton's Laws of Motion

Understanding Newton's laws is crucial for simulating realistic physical behavior.

  1. First Law (Inertia): An object remains at rest or in uniform motion unless acted upon by an external force.
  2. Second Law (F=ma): The force acting on an object is equal to the mass of the object multiplied by its acceleration.
  3. Third Law (Action and Reaction): For every action, there is an equal and opposite reaction.

  1. Forces and Motion

Forces cause objects to move or change their motion. Common forces in simulations include gravity, friction, and applied forces.

  1. Collisions and Responses

Simulating collisions involves detecting when objects intersect and calculating the resulting forces and changes in motion.

  1. Fluid Dynamics

Simulating fluids involves complex mathematics to model the flow and interaction of liquids and gases.

Practical Examples

Example 1: Simulating Gravity

Gravity is a constant force that acts on all objects with mass. In a 3D simulation, gravity can be represented as a vector pointing downwards.

# Example: Simulating gravity in a 3D environment

class Object3D:
    def __init__(self, mass, position, velocity):
        self.mass = mass
        self.position = position
        self.velocity = velocity

    def apply_force(self, force, dt):
        # F = ma -> a = F/m
        acceleration = force / self.mass
        self.velocity += acceleration * dt
        self.position += self.velocity * dt

# Constants
gravity = np.array([0, -9.81, 0])  # Gravity vector
dt = 0.01  # Time step

# Create an object
ball = Object3D(mass=1.0, position=np.array([0, 10, 0]), velocity=np.array([0, 0, 0]))

# Simulate for 1 second
for _ in range(int(1 / dt)):
    ball.apply_force(gravity * ball.mass, dt)
    print(f"Position: {ball.position}, Velocity: {ball.velocity}")

Example 2: Collision Detection and Response

Detecting collisions and calculating the response is essential for realistic simulations.

# Example: Simple collision detection and response

class Object3D:
    def __init__(self, mass, position, velocity, radius):
        self.mass = mass
        self.position = position
        self.velocity = velocity
        self.radius = radius

    def apply_force(self, force, dt):
        acceleration = force / self.mass
        self.velocity += acceleration * dt
        self.position += self.velocity * dt

    def check_collision(self, other):
        distance = np.linalg.norm(self.position - other.position)
        return distance < (self.radius + other.radius)

    def resolve_collision(self, other):
        normal = (self.position - other.position) / np.linalg.norm(self.position - other.position)
        relative_velocity = self.velocity - other.velocity
        velocity_along_normal = np.dot(relative_velocity, normal)

        if velocity_along_normal > 0:
            return

        restitution = 0.5  # Coefficient of restitution
        impulse = (-(1 + restitution) * velocity_along_normal) / (1 / self.mass + 1 / other.mass)
        impulse_vector = impulse * normal

        self.velocity -= (1 / self.mass) * impulse_vector
        other.velocity += (1 / other.mass) * impulse_vector

# Create two objects
ball1 = Object3D(mass=1.0, position=np.array([0, 0, 0]), velocity=np.array([1, 0, 0]), radius=1.0)
ball2 = Object3D(mass=1.0, position=np.array([2, 0, 0]), velocity=np.array([-1, 0, 0]), radius=1.0)

# Simulate for 1 second
for _ in range(int(1 / dt)):
    ball1.apply_force(gravity * ball1.mass, dt)
    ball2.apply_force(gravity * ball2.mass, dt)

    if ball1.check_collision(ball2):
        ball1.resolve_collision(ball2)

    print(f"Ball1 Position: {ball1.position}, Velocity: {ball1.velocity}")
    print(f"Ball2 Position: {ball2.position}, Velocity: {ball2.velocity}")

Exercises

Exercise 1: Simulating a Bouncing Ball

Create a simulation of a ball bouncing on the ground. Consider gravity and the coefficient of restitution for the collision with the ground.

Solution:

class BouncingBall:
    def __init__(self, mass, position, velocity, radius):
        self.mass = mass
        self.position = position
        self.velocity = velocity
        self.radius = radius

    def apply_force(self, force, dt):
        acceleration = force / self.mass
        self.velocity += acceleration * dt
        self.position += self.velocity * dt

    def check_ground_collision(self):
        return self.position[1] - self.radius <= 0

    def resolve_ground_collision(self):
        self.velocity[1] = -self.velocity[1] * 0.8  # Coefficient of restitution

# Constants
gravity = np.array([0, -9.81, 0])
dt = 0.01

# Create a ball
ball = BouncingBall(mass=1.0, position=np.array([0, 10, 0]), velocity=np.array([0, 0, 0]), radius=1.0)

# Simulate for 2 seconds
for _ in range(int(2 / dt)):
    ball.apply_force(gravity * ball.mass, dt)
    if ball.check_ground_collision():
        ball.resolve_ground_collision()
    print(f"Position: {ball.position}, Velocity: {ball.velocity}")

Exercise 2: Simulating a Pendulum

Create a simulation of a simple pendulum. Consider the forces acting on the pendulum and the constraints of its motion.

Solution:

class Pendulum:
    def __init__(self, length, mass, angle, angular_velocity):
        self.length = length
        self.mass = mass
        self.angle = angle
        self.angular_velocity = angular_velocity

    def apply_gravity(self, dt):
        g = 9.81  # Gravity
        angular_acceleration = - (g / self.length) * np.sin(self.angle)
        self.angular_velocity += angular_acceleration * dt
        self.angle += self.angular_velocity * dt

    def position(self):
        return np.array([self.length * np.sin(self.angle), -self.length * np.cos(self.angle)])

# Constants
dt = 0.01

# Create a pendulum
pendulum = Pendulum(length=1.0, mass=1.0, angle=np.pi / 4, angular_velocity=0.0)

# Simulate for 5 seconds
for _ in range(int(5 / dt)):
    pendulum.apply_gravity(dt)
    print(f"Angle: {pendulum.angle}, Angular Velocity: {pendulum.angular_velocity}, Position: {pendulum.position()}")

Conclusion

In this module, we explored the fundamentals of physical simulation in 3D graphics, including Newton's laws of motion, forces, collisions, and fluid dynamics. We provided practical examples and exercises to reinforce these concepts. Understanding these principles is essential for creating realistic and interactive 3D environments. In the next module, we will delve into the representation of 3D objects and how to manipulate them for various applications.

© Copyright 2024. All rights reserved