HPQ Coding For Gaming
HPQ Coding For Gaming
This HPQ project focuses on the complexity and puzzling nature 3D rendering has on gaming more
specifically the analysis of how it affects the Speed of the computers ALU. We are going to achieve this
by making a 3D rendering module ourselves this will help use do custom tests on the ALU giving us a
more deeper understanding of the effects.
First we must understand 3D rendering in its entirety to begin with so that we can dive deeper into the
specifics and details of my methods I have used in my artifact.
Orthographic Projection:
This method projects 3D points onto a 2D plane by dropping perpendiculars from each point to the
plane. It's a simple method but doesn't accurately represent depth, as all 3D points along a line
perpendicular to the plane project to the same 2D point.
Perspective Projection:
This method takes into account the distance of 3D points from a viewpoint, which helps convey depth in
the 2D projection. It's the basis for 3D rendering and drawings.
2. Mathematical Formulation:
Orthographic Projection:
The most basic projection involves discarding the z-coordinate, resulting in the transformation (x, y, z) →
(x, y).
Perspective Projection:
This method involves dividing the x and y coordinates by the z-coordinate, effectively mapping 3D points
to 2D points based on their relative distance from the viewpoint. The formula is often represented as (x,
y, z) → (dx/z, dy/z), where d is a distance parameter.
ORTHOGRAPHIC PROJECTION
A simple orthographic projection onto the plane z = 0 can be defined by the following matrix:
For each point v = (vx, vy, vz), the transformed point Pv would be
For each homogeneous vector v = (vx, vy, vz, 1), the transformed vector Pv would be.
In computer graphics, one of the most common matrices used for orthographic projection can
be defined by a 6-tuple, (left, right, bottom, top, near, far), which defines the clipping planes.
These planes form a box with the minimum corner at (left, bottom, -near) and the maximum
corner at (right, top, -far).
The box is translated so that its center is at the origin, then it is scaled to the unit cube which is
defined by having a minimum corner at (−1,−1,−1) and a maximum corner at (1,1,1) which can
be given as a scaling S followed by a translation T of the form the inversion of the projection
matrix P−1, which can be used as the unprojection matrix is defined:
In dimetric projection, the direction of viewing is such that two of the three axes of space
appear equally foreshortened, of which the attendant scale and angles of presentation are
determined according to the angle of viewing; the scale of the third direction is determined
separately.
In trimetric projection, the direction of viewing is such that all of the three axes of space
appear unequally foreshortened. The scale along each of the three axes and the angles among
them are determined separately as dictated by the angle of viewing. Trimetric perspective is
seldom used in technical drawings.
Multiview projection
Symbols used to define whether a multiview projection is either third-angle (right) or first-angle (left)
In multiview projection, up to six pictures of an object are produced, called primary views, with
each projection plane parallel to one of the coordinate axes of the object. The views are
positioned relative to each other according to either of two schemes: first-angle or third-
angle projection. In each, the appearances of views may be thought of as being projected onto
planes that form a six-sided box around the object. Although six different sides can be drawn,
usually three views of a drawing give enough information to make a three-dimensional object.
These views are known as front view (also elevation), top view (also plan) and end
view (also section). When the plane or axis of the object depicted is not parallel to the projection
plane, and where multiple sides of an object are visible in the same image, it is called
an auxiliary view. Thus isometric projection, dimetric projection and trimetric projection would be
considered auxiliary views in multiview projection. A typical characteristic of multiview projection
is that one axis of space is usually displayed as vertical.
game_module.init()
WINDOW_SIZE = 600
GAME_WINDOW = game_module.display.set_mode((WINDOW_SIZE, WINDOW_SIZE))
CLOCK = game_module.time.Clock()
FPS = 30
WHITE = (255, 255, 255)
RED = (255, 0, 0,)
BLACK = (0, 0, 0)
Colours = [(255,127,80), (255,165,0), (255,215,0), (127,255,0), (175,238,238),
(245,245,220)]
SCALE = 2
Rotaion_angle = 0.1
ANGLE_X = ANGLE_Y = ANGLE_Z = 0
PROJECTION_MATRIX = [[1, 0, 0],
[0, 1, 0],
[0, 0, 0]]
CUBE_POINTS = [n for n in range(8)]
CUBE_POINTS[0] = [[-1], [-1], [1]]
CUBE_POINTS[1] = [[1], [-1], [1]]
CUBE_POINTS[2] = [[1], [1], [1]]
CUBE_POINTS[3] = [[-1], [1], [1]]
CUBE_POINTS[4] = [[-1], [-1], [-1]]
CUBE_POINTS[5] = [[1], [-1], [-1]]
CUBE_POINTS[6] = [[1], [1], [-1]]
CUBE_POINTS[7] = [[-1], [1], [-1]]
CONNECTIONS = [
(0, 1), (0, 3), (0, 4),
(1, 2), (1, 5),
(2, 6), (2, 3),
(3, 7),
(4, 5), (4, 7),
(6, 5), (6, 7)
]
FACES = [
(0, 1, 2, 3), # Front
(3, 2, 6, 7), # Top
(1, 2, 6, 5), # right
(0, 3, 7, 4), # Left
(0, 1, 5, 4), # Bottom
(4, 5, 6, 7) # Back
]
POINTS = [0 for i in range(len(CUBE_POINTS))]
CAMERA = {
"x": 0,
"y": 100,
"z": 100, # Put it behind the object initially
"rotation_x": 0.1,
"rotation_y": 0,
"rotation_z": 0,
}
SPEED = 1
def connect_points(i, j, points):
game_module.draw.line(GAME_WINDOW, (255, 255, 255), (points[i][0],
points[i][1]) , (points[j][0], points[j][1]))
class cuboid_maker:
def __init__(self, cube_points, Height, Width, Length, start_x, start_y,
start_z):
self.cube_points = cube_points
self.width = Width
self.height = Height
self.length = Length
self.start_x = start_x
self.start_y = start_y
self.start_z = start_z
def make_cuboid(self):
self.cube_points = [
[[-self.width + self.start_x], [- self.length + self.start_y],
[self.height + self.start_z]], # 0
[[self.width + self.start_x], [- self.length + self.start_y],
[self.height + self.start_z]], # 1
[[self.width + self.start_x], [ self.length + self.start_y],
[self.height + self.start_z]], # 2
[[-self.width + self.start_x], [ self.length + self.start_y],
[self.height + self.start_z]], # 3
[[-self.width + self.start_x], [- self.length + self.start_y], [-
self.height + self.start_z]], # 4
[[self.width + self.start_x], [- self.length + self.start_y], [-
self.height + self.start_z]], # 5
[[self.width + self.start_x], [ self.length + self.start_y], [-
self.height + self.start_z]], # 6
[[-self.width + self.start_x], [ self.length + self.start_y], [-
self.height + self.start_z]], # 7
]
def perspective_project(x, y, z, fov, viewer_distance):
factor = fov / (viewer_distance + z) if (viewer_distance + z) != 0 else 1
return x * factor, y * factor
cuboid = [cuboid_maker(CUBE_POINTS, 10, 10, 10, 0, 10, 0),
cuboid_maker(CUBE_POINTS, 1, 100, 100, 0, -10, 0)]
for cube in cuboid:
cube.make_cuboid()
OLD_MOUSE_POS = game_module.mouse.get_pos()
while True:
KEYS = game_module.key.get_pressed()
MOUSE_POS = game_module.mouse.get_pos()
for event in game_module.event.get():
if event.type == game_module.QUIT:
game_module.quit()
system.exit()
if KEYS[game_module.K_w]:
CAMERA["z"] += SPEED
if KEYS[game_module.K_s]:
CAMERA["z"] -= SPEED
if KEYS[game_module.K_a]:
CAMERA["x"] -= SPEED
if KEYS[game_module.K_d]:
CAMERA["x"] += SPEED
if KEYS[game_module.K_q]:
CAMERA["y"] -= SPEED
if KEYS[game_module.K_e]:
CAMERA["y"] += SPEED
if KEYS[game_module.K_LEFT]:
CAMERA["rotation_y"] -= Rotaion_angle
if KEYS[game_module.K_RIGHT]:
CAMERA["rotation_y"] += Rotaion_angle
if KEYS[game_module.K_UP]:
CAMERA["rotation_x"] -= Rotaion_angle
if KEYS[game_module.K_DOWN]:
CAMERA["rotation_x"] += Rotaion_angle
if OLD_MOUSE_POS != MOUSE_POS:
if OLD_MOUSE_POS[0] != MOUSE_POS[0]:
if OLD_MOUSE_POS[0] > MOUSE_POS[0]:
CAMERA["rotation_y"] -= Rotaion_angle/3
OLD_MOUSE_POS = MOUSE_POS
else:
CAMERA["rotation_y"] += Rotaion_angle/3
OLD_MOUSE_POS = MOUSE_POS
if OLD_MOUSE_POS[1] != MOUSE_POS[1]:
if OLD_MOUSE_POS[1] > MOUSE_POS[1]:
CAMERA["rotation_x"] += Rotaion_angle/3
OLD_MOUSE_POS = MOUSE_POS
else:
CAMERA["rotation_x"] -= Rotaion_angle/3
OLD_MOUSE_POS = MOUSE_POS
GAME_WINDOW.fill(BLACK)
rotation_x = [[1, 0, 0],
[0, cos(ANGLE_X), -sin(ANGLE_X)],
[0, sin(ANGLE_X), cos(ANGLE_X)]]
px -= CAMERA["x"]
py -= CAMERA["y"]
pz -= CAMERA["z"]
rotate_x = game_NP.dot(rotation_x, [[px], [py], [pz]])
rotate_y = game_NP.dot(rotation_y, rotate_x)
rotate_z = game_NP.dot(rotation_z, rotate_y)
resultent_point = game_NP.dot(PROJECTION_MATRIX, rotate_z)
rx = float(resultent_point[0][0])
ry = float(resultent_point[1][0])
rz = float(resultent_point[2][0])
x_proj, y_proj = perspective_project(rx, ry, rz, 500, 50)
x = x_proj * SCALE + WINDOW_SIZE/2
y = y_proj * SCALE + WINDOW_SIZE/2
POINTS[i] = (x, y)
i += 1
game_module.draw.circle(GAME_WINDOW, WHITE, (x, y), 1)
for i, j in CONNECTIONS:
connect_points(i, j, POINTS)
col = 0
for a, b, c, d in FACES:
connect_faces(a, b, c, d, POINTS, Colours[col])
col += 1
CLOCK.tick(FPS)
game_module.display.update()
this is whole of the project which includes the code and my essay underneath.
The Arithmetic Logic Unit (ALU) is a critical component of the CPU responsible for performing
arithmetic and logical operations. In the context of 3D rendering, the ALU handles numerous
calculations, including:
The efficiency of the ALU directly impacts the speed and quality of 3D rendering, especially in
real-time applications like gaming.
These transformations are achieved using matrix operations, which are computationally handled
by the ALU.
Projection Techniques
Orthographic Projection
csharp
CopyEdit
[1 0 0 0]
[0 1 0 0]
[0 0 0 0]
[0 0 0 1]
This matrix effectively discards the z-coordinate, flattening the 3D scene onto a 2D plane.
Perspective Projection
Perspective projection simulates the way the human eye perceives the world, where objects
appear smaller as they are farther from the viewer. The transformation involves dividing the x
and y coordinates by the z-coordinate, introducing depth perception. The perspective projection
matrix is more complex and includes parameters like the field of view and aspect ratio.
game_module.init()
Here, Pygame is initialized, and essential modules are imported. math provides mathematical
functions, and numpy (aliased as game_NP) is used for efficient numerical computations,
particularly matrix operations.
A 600x600 window is created for rendering, and a clock is set to control the frame rate at 30
frames per second.
Colors are defined for rendering, and initial rotation angles are set. The SCALE factor adjusts the
size of the rendered objects on the screen.
Projection Matrix
PROJECTION_MATRIX = [[1, 0, 0],
[0, 1, 0],
[0, 0, 0]]
This matrix represents an orthographic projection, effectively ignoring the z-coordinate and
projecting the 3D points onto the 2D plane.
Eight points define the vertices of a cube in 3D space. Each point is a column vector representing
x, y, and z coordinates.
CONNECTIONS define the edges between vertices, and FACES define the surfaces of the cube, each
consisting of four vertices.
Camera Configuration
CAMERA = {
"x": 0,
"y": 100,
"z": 100,
"rotation_x": 0.1,
"rotation_y": 0,
"rotation_z": 0,
}
The camera is positioned in 3D space, and its orientation is defined by rotation angles around the
x, y, and z axes.
Creating Cuboids
class cuboid_maker:
def __init__(self, cube_points, Height, Width, Length, start_x, start_y,
start_z):
...
def make_cuboid(self):
...
This class generates cuboids by scaling and translating the base cube points. It allows for
creating multiple cuboids with different dimensions and positions.
This function applies a simple perspective projection by scaling the x and y coordinates based on
their distance from the viewer, introducing depth perception.
The main loop handles user input for camera movement and rotation. It processes keyboard and
mouse events to adjust the camera's position and orientation.
Rendering Process
GAME_WINDOW.fill(BLACK)
...
for cube in range(len(cuboid)):
...
for point in cuboid[cube].cube_points:
...
rotate_x = game_NP.dot(rotation_x, [[px], [py], [pz]])
...
x_proj, y_proj = perspective_project(rx, ry, rz, 500, 50)
...
game_module.draw.circle(GAME_WINDOW, WHITE, (x, y), 1)
...
for i, j in CONNECTIONS:
connect_points(i, j, POINTS)
...
for a, b, c, d in FACES:
connect_faces(a, b, c, d, POINTS, Colours[col])
Each frame, the screen is cleared, and the cuboids are rendered. Points are transformed using
rotation matrices, projected onto 2D space, and drawn. Edges and faces are then rendered to
complete the visualization.
These operations are handled by the ALU, and their efficiency directly affects rendering
performance. By analyzing the frame rate and responsiveness of the application, one can infer
the ALU's performance under different computational loads.
The initial spike shows the load the project at minimum running requirements takes on the computer as
the 3rd graph shows the alu the drasticly increased in calculations due to the heavy load of the threads
increased by the interdimensional calculatins done in a matter of seconds.