Note: q
is the azimuthal angle, and j
is the polar angle.
Here is my code so far:
from math import pi, sin, cos, sqrt, acos
from pynput.mouse import Button, Controller
import pyautogui
import cv2
import numpy as np
import sympy as sp
zoom = 0.5
d = 200
q = 0
j = pi / 2
win = '3D'
side = 1000
unitsPerPixelJ = pi / side
unitsPerPixelQ = 2 * pi / side
cv2.namedWindow(win)
cv2.moveWindow(win, 0, 0)
mat = np.zeros((side, side, 3))
# A(d * cos(q) * sin(j), d * sin(q) * sin(j), d * cos(j)): d units in front of viewer's eyes
# B(x * t, y * t, z * t): intersection of line, from (x, y, z) to (0, 0, 0), and plane of vision
# C(d * cos(q) * sin(j) + r * sin(q), d * sin(q) * sin(j) - r * cos(q), d * cos(j)): point of reference to find an angle needed later
def RGBtoLAB(RGB):
return (RGB[2] / 255, RGB[1] / 255, RGB[0] / 255)
# maps a point (x, y, z) to the screen as a point (x, y)
def point(x, y, z):
# t: constant value required to find point B
t = d / (x * cos(q) * sin(j) + y * sin(q) * sin(j) + z * cos(j))
# r: distance from point A to point B
r = sqrt((d * cos(q) * sin(j) - x * t) ** 2 + (d * sin(q) * sin(j) - y * t) ** 2 + (d * cos(j) - z * t) ** 2)
BminusA = (x * t - d * cos(q) * sin(j), y * t - d * sin(q) * sin(j), z * t - d * cos(j))
CminusA = (r * sin(q), - r * cos(q), 0)
angleBAC = acos((BminusA[0] * CminusA[0] + BminusA[1] * CminusA[1]) / r ** 2)
return (round(zoom * r * cos(angleBAC) + side / 2), round(zoom * r * sin(angleBAC) + side / 2))
#(z != 0 and (abs(z) / z) or 1) *
def fillPoly(xLst, yLst, zLst, color = (255, 255, 255)):
xLst2D = []
yLst2D = []
for item in range(len(xLst)):
pt = point(xLst[item], yLst[item], zLst[item])
xLst2D += [pt[0]]
yLst2D += [pt[1]]
ptLst = []
for item in range(len(xLst2D)):
ptLst += [[xLst2D[item], yLst2D[item]]]
ptLst = np.array(ptLst)
cv2.fillPoly(mat, np.int32([ptLst]), RGBtoLAB(color))
print(ptLst)
pyautogui.moveTo(side / 2 + 8, side / 2 + 31)
mouse = Controller()
col = mouse.position[0]
row = mouse.position[1]
fillPoly([1, -1, -1, 1], [1, 1, -1, -1], [1, 1, 1, 1])
cv2.imshow(win, mat)
while True:
colNew = mouse.position[0]
rowNew = mouse.position[1]
if (col != colNew) or (row != rowNew):
fillPoly([1, -1, -1, 1], [1, 1, -1, -1], [1, 1, 1, 1], (0, 0, 0))
print('q = ' + str(q))
print('j = ' + str(j))
q += (col - colNew) * unitsPerPixelQ
j += (row - rowNew) * unitsPerPixelJ
col = colNew
row = rowNew
fillPoly([1, -1, -1, 1], [1, 1, -1, -1], [1, 1, 1, 1])
cv2.imshow(win, mat)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
My end goal is to make a 3D renderer, where you can input a point in (x, y, z) into a function that returns a point in (x, y). How would I go about doing this?
Is my point(x, y, z)
function inaccurate?
Thank you in advance.