How To Rotate A Square Around X-axis In A 3d Space
So i have been trying to learn how 3D rendering works. I tried write a script with the goal to rotate a flat (2D) square in 3D space. I started by defining a square in a normalised
Solution 1:
It is not necessary to rotate each component of a vector separately. If you do
p1.x = rotation.rotate(p1, thetax, axis='x').x
then the x
component of p1
has changed and the p1
which is passed to the next instruction is different
p1.y = rotation.rotate(p1, thetay, axis='x').y
It is sufficient to rotate the entire vertices once:
p1 = rotation.rotate(p1, thetax, axis='x')
p2 = rotation.rotate(p2, thetax, axis='x')
p3 = rotation.rotate(p3, thetax, axis='x')
p4 = rotation.rotate(p4, thetax, axis='x')
When you multiply a vector by a rotation matrix, then the vector is rotated a round (0, 0, 0). You have to do the translation after the rotation.
Add a +
-operator to the Vec3
class:
classVec3:
# 3D VECTORdef__init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def__add__(a, b):
return Vec3(a.x+b.x, a.y+b.y, a.z+b.z)
Never change the original vertex coordinates p1
, p2
, p3
and p4
. Compute the rotation and then the translation:
# TRANSLATING THE POINTS OF THE CUBE A LITTLE BIT INTO THE SCREEN#p1.z += 6 <--- DELETE#p2.z += 6#p3.z += 6#p4.z += 6
transVec = Vec3(0, 0, 6)
# [...]while run:
# ROTATING THE POINTS AROUND X AXIS
point1 = rotation.rotate(p1, thetax, axis='x')
# [...]# TRANSLATING THE POINTS OF THE CUBE A LITTLE BIT INTO THE SCREEN
point1 = point1 + transVec
# [...]# TRANSLATING THE SQUARE SHEET INTO THE SCREEN SPACE
point1 = transform.worldSpaceTransform(point1, SCREENWIDTH, SCREENHEIGHT)
# [...]
I recommend to organize the vertex coordinates in lists:
# ASSIGNING 4 Vec3's FOR 4 SIDES OF SQUARE IN NORMALIZED SPACE
s = 1
modelPoints = [Vec3(-s, -s, -s), Vec3(s, -s, -s), Vec3(s, s, -s), Vec3(-s, s, -s)]
# TRANSLATING THE POINTS OF THE CUBE A LITTLE BIT INTO THE SCREEN
transVec = Vec3(0, 0, 6)
# ASSIGNING THE ROTATION ANGLES
thetax = 0# APPLICATION LOOP
run = Truewhile run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
D.fill((255, 255, 255))
# ROTATING THE POINTS AROUND X AXIS
points = [rotation.rotate(pt, thetax, axis='x') for pt in modelPoints]
# TRANSLATING THE POINTS OF THE CUBE A LITTLE BIT INTO THE SCREEN
points = [pt + transVec for pt in points]
# TRANSLATING THE SQUARE SHEET INTO THE SCREEN SPACE
points = [transform.worldSpaceTransform(pt, SCREENWIDTH, SCREENHEIGHT) for pt in points]
# STORING THE POINTS TO A TUPLE SO IT CAN BE DRAWN USING pygame.draw.lines
points = [(pt.x, pt.y) for pt in points]
See the complete example:
import pygame
from math import sin, cos, radians
pygame.init()
### PYGAME STUFF ######################################
SCREENWIDTH = 600
SCREENHEIGHT = 600
D = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
pygame.display.set_caption("PRESS SPACE TO ROTATE AROUND X")
######### MATH FUNCTIONS AND CLASSES ####################classMat3:
# 3X3 MATRIX INITIALIZED WITH ALL 0'sdef__init__(self):
self.matrix = [[0for i inrange(3)],
[0for i inrange(3)],
[0for i inrange(3)]]
classVec2:
# 2D VECTORdef__init__(self, x, y):
self.x = x
self.y = y
classVec3:
# 3D VECTORdef__init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def__add__(a, b):
return Vec3(a.x+b.x, a.y+b.y, a.z+b.z)
defmultVecMatrix(vec3, mat3):
# MULTIPLIES A Vec3 OBJECT WITH Mat3 OBJECT AND RETURNS A NEW Vec3
x = vec3.x * mat3.matrix[0][0] + vec3.y * mat3.matrix[0][1] + vec3.z * mat3.matrix[0][2]
y = vec3.x * mat3.matrix[1][0] + vec3.y * mat3.matrix[1][1] + vec3.z * mat3.matrix[1][2]
z = vec3.x * mat3.matrix[2][0] + vec3.y * mat3.matrix[2][1] + vec3.z * mat3.matrix[2][2]
return Vec3(x, y, z)
classTransform:
# IT TRANSFORMS THE X AND Y FROM NORMALIZED SPACE TO SCREEN SPACE WITH PROJECTION APPLIEDdefworldSpaceTransform(self, vec3, w, h):
if vec3.z == 0:
vec3.z = 0.001
zInverse = 1/ vec3.z
xTransformed = ((vec3.x * zInverse) + 1) * (w/2)
yTransformed = ((-vec3.y * zInverse) + 1) * (h/2)
xTransformed = str(xTransformed)[:6]
yTransformed = str(yTransformed)[:6]
return Vec2(float(xTransformed), float(yTransformed))
classRotation:
defrotateX(self, theta):
# ROTATION MATRIX IN X AXIS
sinTheta = sin(theta)
cosTheta = cos(theta)
m = Mat3()
m.matrix = [[1, 0, 0],
[0, cosTheta, sinTheta],
[0, -sinTheta, cosTheta]]
return m
defrotate(self, vec3, theta, axis=None):
# ROTATES A Vec3 BY GIVEN THETA AND AXISif axis == "x":
return multVecMatrix(vec3, self.rotateX(theta))
if axis == "y":
return multVecMatrix(vec3, self.rotateY(theta))
if axis == "z":
return multVecMatrix(vec3, self.rotateZ(theta))
transform = Transform()
rotation = Rotation()
# ASSIGNING 4 Vec3's FOR 4 SIDES OF SQUARE IN NORMALIZED SPACE
s = 1
modelPoints = [Vec3(-s, -s, -s), Vec3(s, -s, -s), Vec3(s, s, -s), Vec3(-s, s, -s)]
# TRANSLATING THE POINTS OF THE CUBE A LITTLE BIT INTO THE SCREEN
transVec = Vec3(0, 0, 6)
# ASSIGNING THE ROTATION ANGLES
thetax = 0# APPLICATION LOOP
run = Truewhile run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
D.fill((255, 255, 255))
# ROTATING THE POINTS AROUND X AXIS
points = [rotation.rotate(pt, thetax, axis='x') for pt in modelPoints]
# TRANSLATING THE POINTS OF THE CUBE A LITTLE BIT INTO THE SCREEN
points = [pt + transVec for pt in points]
# TRANSLATING THE SQUARE SHEET INTO THE SCREEN SPACE
points = [transform.worldSpaceTransform(pt, SCREENWIDTH, SCREENHEIGHT) for pt in points]
# STORING THE POINTS TO A TUPLE SO IT CAN BE DRAWN USING pygame.draw.lines
points = [(pt.x, pt.y) for pt in points]
keys = pygame.key.get_pressed()
# ROTATE X ?if keys[pygame.K_SPACE]:
thetax -= 0.005
pygame.draw.lines(D, (0, 0, 0), True, points)
pygame.display.flip()
Post a Comment for "How To Rotate A Square Around X-axis In A 3d Space"