0

I'm trying to create a simple 3d rendering of a cube. As in this video from the Coding Train: https://www.youtube.com/watch?v=p4Iz0XJY-Qk on minute 14. I got stuck at one point. Since I'm pretty new to all of this, I'm not exactly sure what's causing my issue. When I start the project, the cube rotates as I want it to, but moves away from the screen to the left and it looks like it's making a circle.

import pygame
import numpy as np
import os
import math

WHITE = (255,255,255)
width, height = 700, 700
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()

points = []
angle = 0

points.append(np.array([[300], [250], [1]]))
points.append(np.array([[300], [350], [1]]))
points.append(np.array([[400], [250], [1]]))
points.append(np.array([[400], [350], [1]]))

projectionMatrix = np.array([[1, 0, 0],
                             [0, 1, 0]])

while True:
    clock.tick(30)
    screen.fill((0,0,0))

    rotation = np.array([[math.cos(angle), -math.sin(angle)],
                         [math.sin(angle), math.cos(angle)]])

    for event in pygame.event.get():
            if event.type == pygame.QUIT:
                os._exit(1)

    for point in points:
        projected2d = np.dot(projectionMatrix, point)
        rotated = np.dot(rotation, projected2d)
        pygame.draw.circle(screen, WHITE, (int(rotated[0][0]), int(rotated[1][0])), 5)

    angle += 0.01
    pygame.display.update()

I would really appreciate any help to why this is happening and how I could fix it so it's just rotating around.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • There is no bug in this code. The points rotate around the top left (0, 0). Most likely you have to look the tutorial to the end. – Rabbid76 Sep 17 '20 at 18:35
  • The video is in Processing. Its not python. I have the exact same matricies and he doesnt have such a problem. Thats what im asking. Why is it rotating? –  Sep 17 '20 at 18:50
  • p5.js uses a different coordinate system. In p5.js (0, 0) can be translated to the center of the screen. – Rabbid76 Sep 17 '20 at 18:50
  • Thank you. Now i understand whats wrong. Cheers –  Sep 17 '20 at 18:55

1 Answers1

1

There is no bug in this code. The points rotate around the top left (0, 0). Note, In 3D mode, p5.js uses a different coordinate system than pygame.

If you want to rotate the dots around the centre of the window, then define the points in range [-1, 1] (normalized device space:

points.append(np.matrix([ 0.5,  0.5, 1]))
points.append(np.matrix([ 0.5, -0.5, 1]))
points.append(np.matrix([-0.5,  0.5, 1]))
points.append(np.matrix([-0.5, -0.5, 1]))

Define a projection matrix from the range[-1, 1] to window space:

projectionMatrix = np.matrix([[height/2, 0, width/2],
                              [0, height/2, height/2]])

Specify a 3x3 rotation matrix:

rotation = np.array([[math.cos(angle), -math.sin(angle), 0],
                     [math.sin(angle), math.cos(angle), 0],
                     [0, 0, 1]])

First rotate the points, then project it to the window:

projected2d = projectionMatrix * rotation * point.reshape((3, 1))

Complete example:

import pygame
import numpy as np
import os
import math

WHITE = (255,255,255)
width, height = 400, 300
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()

points = []
angle = 0

points.append(np.matrix([ 0.5,  0.5, 1]))
points.append(np.matrix([ 0.5, -0.5, 1]))
points.append(np.matrix([-0.5,  0.5, 1]))
points.append(np.matrix([-0.5, -0.5, 1]))

projectionMatrix = np.matrix([[height/2, 0, width/2],
                             [0, height/2, height/2]])

while True:
    clock.tick(30)
    screen.fill((0,0,0))

    rotation = np.matrix([[math.cos(angle), -math.sin(angle), 0],
                         [math.sin(angle), math.cos(angle), 0],
                         [0, 0, 1]])

    for event in pygame.event.get():
            if event.type == pygame.QUIT:
                os._exit(1)

    for point in points:
        projected2d = projectionMatrix * rotation * point.reshape((3, 1))
        pygame.draw.circle(screen, WHITE, (int(projected2d[0][0]), int(projected2d[1][0])), 5)

    angle += 0.01
    pygame.display.update()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174