mirror of
https://github.com/kuhyx/WUT_Computer_Science.git
synced 2026-07-04 17:03:12 +02:00
git-subtree-dir: Programming/TRAK git-subtree-mainline:e11d703c3egit-subtree-split:777937fb9e
146 lines
7.7 KiB
Python
146 lines
7.7 KiB
Python
import numpy as np
|
|
from ..utils.constants import *
|
|
from ..utils.vector3 import vec3
|
|
from ..geometry import Primitive, Collider
|
|
|
|
class Cuboid(Primitive):
|
|
def __init__(self,center, material, width,height, length,max_ray_depth = 5, shadow = True):
|
|
super().__init__(center, material, max_ray_depth, shadow = shadow)
|
|
self.width = width
|
|
self.height = height
|
|
self.length = length
|
|
self.bounded_sphere_radius = np.sqrt((self.width/2)**2 + (self.height/2)**2 + (self.length/2)**2)
|
|
|
|
self.collider_list += [Cuboid_Collider(assigned_primitive = self, center = center, width = width, height =height ,length =length )]
|
|
|
|
|
|
def get_uv(self, hit):
|
|
u,v = hit.collider.get_uv(hit)
|
|
u,v = u/4,v/3
|
|
return u,v
|
|
|
|
|
|
"""
|
|
This was the old approach, but remplaced by a Box collider that is more efficient
|
|
#we model a cuboid as six planes
|
|
|
|
|
|
#BOTTOM #BOTTOM
|
|
self.collider_list += [Plane_Collider(assigned_primitive = self, center = center + vec3(0.0,-h, 0.0), u_axis = vec3(1.0, 0.0, 0.0), v_axis = vec3(0.0, 0.0, 1.0), w = w, h = l, uv_shift = (1,0))]
|
|
#TOP #TOP
|
|
self.collider_list += [Plane_Collider(assigned_primitive = self, center = center + vec3(0.0,h, 0.0), u_axis = vec3(1.0, 0.0, 0.0), v_axis = vec3(0.0, 0.0, -1.0), w = w, h = l, uv_shift= (1,2))]
|
|
#RIGHT #RIGHT
|
|
self.collider_list += [Plane_Collider(assigned_primitive = self, center = center + vec3(w,0.0, 0.0), u_axis = vec3(0.0, 0.0, -1.0), v_axis = vec3(0.0, 1.0, 0.0), w = l, h = h, uv_shift= (2,1))]
|
|
#LEFT #LEFT
|
|
self.collider_list += [Plane_Collider(assigned_primitive = self, center = center + vec3(-w,0.0, 0.0), u_axis = vec3(0.0, 0.0, 1.0), v_axis = vec3(0.0, 1.0, 0.0), w = l, h = h, uv_shift= (0,1))]
|
|
#FRONT #FRONT
|
|
self.collider_list += [Plane_Collider(assigned_primitive = self, center = center + vec3(0,0, l), u_axis = vec3(1.0, 0.0, 0.0), v_axis = vec3(0.0, 1.0, 0.0), w = w, h = h, uv_shift= (1,1))]
|
|
#BACK #BACK
|
|
self.collider_list += [Plane_Collider(assigned_primitive = self, center = center + vec3(0,0, -l), u_axis = vec3(-1.0, 0.0, 0.0), v_axis = vec3(0.0, 1.0, 0.0), w = w, h = h, uv_shift= (3,1))]
|
|
"""
|
|
|
|
|
|
class Cuboid_Collider(Collider):
|
|
def __init__(self, width, height,length,**kwargs):
|
|
super().__init__(**kwargs)
|
|
|
|
self.lb = self.center - vec3(width/2, height/2, length/2)
|
|
self.rt = self.center + vec3(width/2, height/2, length/2)
|
|
|
|
self.lb_local_basis = self.lb
|
|
self.rt_local_basis = self.rt
|
|
|
|
self.width = width
|
|
self.height = height
|
|
self.length = length
|
|
|
|
# basis vectors
|
|
self.ax_w = vec3(1.,0.,0.)
|
|
self.ax_h = vec3(0.,1.,0.)
|
|
self.ax_l = vec3(0.,0.,1.)
|
|
|
|
self.inverse_basis_matrix = np.array([[self.ax_w.x, self.ax_h.x, self.ax_l.x],
|
|
[self.ax_w.y, self.ax_h.y, self.ax_l.y],
|
|
[self.ax_w.z, self.ax_h.z, self.ax_l.z]])
|
|
|
|
self.basis_matrix = self.inverse_basis_matrix.T
|
|
|
|
|
|
def rotate(self,M, center):
|
|
self.ax_w = self.ax_w.matmul(M)
|
|
self.ax_h = self.ax_h.matmul(M)
|
|
self.ax_l = self.ax_l.matmul(M)
|
|
|
|
self.inverse_basis_matrix = np.array([[self.ax_w.x, self.ax_h.x, self.ax_l.x],
|
|
[self.ax_w.y, self.ax_h.y, self.ax_l.y],
|
|
[self.ax_w.z, self.ax_h.z, self.ax_l.z]])
|
|
|
|
self.basis_matrix = self.inverse_basis_matrix.T
|
|
|
|
self.lb = center + (self.lb-center).matmul(M)
|
|
self.rt = center + (self.rt-center).matmul(M)
|
|
|
|
self.lb_local_basis = self.lb.matmul(self.basis_matrix)
|
|
self.rt_local_basis = self.rt.matmul(self.basis_matrix)
|
|
|
|
def intersect(self, O, D):
|
|
|
|
|
|
O_local_basis = O.matmul(self.basis_matrix)
|
|
D_local_basis = D.matmul(self.basis_matrix)
|
|
|
|
dirfrac = 1.0 / D_local_basis
|
|
|
|
# lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
|
|
t1 = (self.lb_local_basis.x - O_local_basis.x)*dirfrac.x;
|
|
t2 = (self.rt_local_basis.x - O_local_basis.x)*dirfrac.x;
|
|
t3 = (self.lb_local_basis.y - O_local_basis.y)*dirfrac.y;
|
|
t4 = (self.rt_local_basis.y - O_local_basis.y)*dirfrac.y;
|
|
t5 = (self.lb_local_basis.z - O_local_basis.z)*dirfrac.z;
|
|
t6 = (self.rt_local_basis.z - O_local_basis.z)*dirfrac.z;
|
|
|
|
tmin = np.maximum(np.maximum(np.minimum(t1, t2), np.minimum(t3, t4)), np.minimum(t5, t6))
|
|
tmax = np.minimum(np.minimum(np.maximum(t1, t2), np.maximum(t3, t4)), np.maximum(t5, t6))
|
|
|
|
# if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
|
|
# if tmin > tmax, ray doesn't intersect AAB
|
|
mask1 = (tmax < 0) | (tmin > tmax)
|
|
|
|
# if tmin < 0 then the ray origin is inside of the AABB and tmin is behind the start of the ray so tmax is the first intersection
|
|
mask2 = tmin < 0
|
|
return np.select([mask1,mask2,True] , [FARAWAY , [tmax, np.tile(UPDOWN, tmin.shape)] , [tmin, np.tile(UPWARDS, tmin.shape)]])
|
|
|
|
|
|
def get_Normal(self, hit):
|
|
|
|
P = (hit.point-self.center).matmul(self.basis_matrix)
|
|
absP = vec3(1./self.width, 1./self.height, 1./self.length)*np.abs(P)
|
|
Pmax = np.maximum(np.maximum(absP.x, absP.y), absP.z)
|
|
P.x = np.where(Pmax == absP.x, np.sign(P.x), 0.)
|
|
P.y = np.where(Pmax == absP.y, np.sign(P.y), 0.)
|
|
P.z = np.where(Pmax == absP.z, np.sign(P.z), 0.)
|
|
|
|
return P.matmul(self.inverse_basis_matrix)
|
|
|
|
def get_uv(self, hit):
|
|
hit.N = self.get_Normal(hit)
|
|
M_C = hit.point - self.center
|
|
|
|
BOTTOM = (hit.N == vec3(0.,-1.,0.))
|
|
TOP = (hit.N == vec3(0., 1.,0.))
|
|
RIGHT = (hit.N == vec3(1.,0.,0.))
|
|
LEFT = (hit.N == vec3(-1.,0.,0.) )
|
|
FRONT = (hit.N == vec3(0.,0.,1.))
|
|
BACK = (hit.N == vec3(0.,0.,-1.))
|
|
|
|
#0.985 to avoid corners
|
|
u = np.select([BOTTOM , TOP, RIGHT, LEFT , FRONT , BACK], [((self.ax_w.dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 1), ((self.ax_w.dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 1), ((self.ax_l.dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 2), (((self.ax_l*-1).dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 0), (((self.ax_w*-1).dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 3), (( self.ax_w.dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 1)])
|
|
v = np.select([BOTTOM , TOP, RIGHT, LEFT , FRONT , BACK], [(((self.ax_l*-1).dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 0), ((self.ax_l.dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 2), ((self.ax_h.dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 1), (((self.ax_h).dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 1), (((self.ax_h).dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 1), (( self.ax_h.dot(M_C)/self.width*2 *0.985 + 1 ) /2 + 1)])
|
|
return u,v
|
|
|
|
|
|
|
|
|
|
|
|
|