gpt4 book ai didi

python - 如何测试 pygame 屏幕中的 2d 点是否是 PyOpenGL 中 3d 对象的一部分?

转载 作者:行者123 更新时间:2023-12-01 07:41:33 27 4
gpt4 key购买 nike

我正在 PyOpenGL 中制作一个游戏(RPG),我有一个十字准线。我想检查 3D 对象是否在十字准线中(或检测它是否在某个点),这是一个 2D 叠加。我怎样才能做到这一点?

我尝试使用 screen.get_at() 函数,但它显示错误“无法在 OpenGL 表面上调用”。另外,它也不好,因为它只检测颜色,而不检测物体(虽然你可以使用颜色来确定物体,但如果有多个物体具有相同的颜色怎么办?)。

这是我确定距离的方法:

        for person in persons:
if (touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])) < 5:
crosshair_color = (1,0,0)
if len(attacklist) >= 2:
bigger = attacklist[1] > touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])
if bigger == True:
attacklist = [person,touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])]
else:
attacklist = [person,touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])]
if attacklist:
if cam_attack == True:
attacklist[0].health -= cam_damage

触摸功能,您可以计算离您最近的距离:

def touched(tar_x,tar_y,tar_z,tar_x1,tar_y1,tar_z1):
centerPt = pygame.math.Vector3(tar_x,tar_y,tar_z)
point2 = pygame.math.Vector3(tar_x1, tar_y1, tar_z1)
distance = centerPt.distance_to(point2)
return distance

编辑 - 完整代码 - float 除以 0:

import pygame
from pygame.locals import *

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

import math,sys,numpy,random,ctypes

pygame.init()
display = (1500, 900)
screen = pygame.display.set_mode(display, DOUBLEBUF | OPENGL)

glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glShadeModel(GL_SMOOTH)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_BLEND)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)

glEnable(GL_LIGHT0)
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5, 1])
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1])

glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)

glMatrixMode(GL_MODELVIEW)
gluLookAt(0, -8, 0, 0, 0, 0, 0, 0, 1)
glTranslatef(0,-8,0)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
glLoadIdentity()

# init mouse movement and center mouse on screen
displayCenter = [screen.get_size()[i] // 2 for i in range(2)]
mouseMove = [0, 0]
pygame.mouse.set_pos(displayCenter)

cmddown = False
cam_attack = False
cam_damage = random.randint(20,30)
knockback = False
person_count = 1
up_down_angle = 0.0
camera_pos = (0,0,0)
paused = False
run = True
#xzy = xyz

#Functions & Classes
def InverseMat44(mat):
m = [mat[i][j] for i in range(4) for j in range(4)]
inv = [0]*16

inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]
inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]
inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]
inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9]
inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]
inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]
inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9]
inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]
inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]
inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6]
inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]
inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5]
inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6]
inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]
inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5]
inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5]

det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]
for i in range(16):
inv[i] /= det
return inv

def touched(tar_x,tar_y,tar_z,tar_x1,tar_y1,tar_z1):
centerPt = pygame.math.Vector3(tar_x,tar_y,tar_z)
point2 = pygame.math.Vector3(tar_x1, tar_y1, tar_z1)
distance = centerPt.distance_to(point2)
return distance

def follower(x,y,z,x1,y1,z1,speed):
dir_x, dir_y = (x1-x, y1-y)
distance = math.hypot(dir_x, dir_y)
dir_x, dir_y = (dir_x/distance, dir_y/distance)
angle = math.degrees(math.atan2(dir_y, dir_x)) + 90
return (dir_x*speed, dir_y*speed, 0, angle)

def random_pos(max_distance):
x_value_change = random.randrange(-max_distance + 2,max_distance + 2)
y_value_change = random.randrange(-max_distance + 2,max_distance + 2)
z_value_change = 0
return (x_value_change, y_value_change, z_value_change)

def blit_text(x,y,font,text,r,g,b):
blending = False
if glIsEnabled(GL_BLEND):
blending = True
glColor3f(r,g,b)
glWindowPos2f(x,y)
for ch in text:
glutBitmapCharacter(font,ctypes.c_int(ord(ch)))
if not blending:
glDisable(GL_BLEND)

def subtract(v0, v1):
return [v0[0]-v1[0], v0[1]-v1[1], v0[2]-v1[2]]
def dot(v0, v1):
return v0[0]*v1[0]+v0[1]*v1[1]+v0[2]*v1[2]
def length(v):
return math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2])
def mults(v, s):
return [v[0]*s, v[1]*s, v[2]*s]
def add(v0, v1):
return [v0[0]+v1[0], v0[1]+v1[1], v0[2]+v1[2]]
def cross(v0, v1):
return [
v0[1]*v1[2]-v1[1]*v0[2],
v0[2]*v1[0]-v1[2]*v0[0],
v0[0]*v1[1]-v1[0]*v0[1]]
def normalize(v):
l = length(v)
return [v[0]/l, v[1]/l, v[2]/l]
def PointInOrOn( P1, P2, A, B ):
CP1 = cross( subtract(B, A), subtract(P1, A) )
CP2 = cross( subtract(B, A), subtract(P2, A) )
return dot( CP1, CP2 ) >= 0
def PointInOrOnTriangle( P, A, B, C ):
return PointInOrOn( P, A, B, C ) and PointInOrOn( P, B, C, A ) and PointInOrOn( P, C, A, B )

def isectPlane(p0, p1, PA, PB, PC):
R0 = p0 # origin
D = normalize(subtract(p1, p0))
P0 = PA
NV = normalize( cross( subtract(PB, PA), subtract(PC, PA) ) )
dist_isect = dot( subtract(P0, R0), NV ) / dot( D, NV )
P_isect = add(R0, mults(D, dist_isect))
return P_isect, dist_isect

def isectQuad(p0, p1, PA, PB, PC, PD):
P, t = isectPlane(p0, p1, PA, PB, PC)
if t >= 0 and (PointInOrOnTriangle(P, PA, PB, PC) or PointInOrOnTriangle(P, PA, PC, PD)):
return t
return None

def isectCuboid(p0, p1, pMin, pMax):
pl = [ [pMin[0], pMin[1], pMin[2]], [pMax[0], pMin[1], pMin[2]], [pMax[0], pMax[1], pMin[2]], [pMin[0], pMax[1], pMin[2]],
[pMin[0], pMin[1], pMax[2]], [pMax[0], pMin[1], pMax[2]], [pMax[0], pMax[1], pMax[2]], [pMin[0], pMax[1], pMax[2]] ]
il = [[0, 1, 2, 3], [4, 5, 6, 7], [4, 0, 3, 7], [1, 5, 6, 2], [4, 3, 1, 0], [3, 2, 6, 7]]
t = None
for qi in il:
ts = isectQuad(p0, p1, pl[qi[0]], pl[qi[1]], pl[qi[2]], pl[qi[3]] )
if ts != None and ts >= 0 and (t == None or ts < t):
t = ts
return t

class Ground:
def __init__(self,mul=1):
self.vertices = [
[-20,20,-1],
[20,20,-1],
[-20,-300,-1],
[20,-300,-1]
]

def draw(self):
glBegin(GL_QUADS) #Begin fill
for vertex in self.vertices:
glColor3f(0,0.5,0.5)
glVertex3fv(vertex)
glEnd()

class Person:
def __init__(self):
self.vertices = [
[-1,0,1],
[-1,0,-1],
[1,0,-1],
[1,0,1],
[-1,1,1],
[-1,1,-1],
[1,1,-1],
[1,1,1]
]

self.vertices = list(numpy.multiply(numpy.array(self.vertices),1))
self.edges = (
(0,1),
(0,3),
(0,4),
(1,2),
(1,5),
(2,3),
(2,6),
(3,7),
(4,5),
(4,7),
(5,6),
(6,7)
)
self.surfaces = (
(0,1,2,3),
(0,1,5,4),
(4,5,6,7),
(1,2,6,5),
(0,3,7,4),
(2,3,7,6)
)
self.x = self.vertices[1][0]
self.y = self.vertices[1][2]
self.z = self.vertices[1][1]
self.pos = (self.x,self.y,self.z)
self.rot = 0
self.health = 100
self.damage = random.randint(20,40)
self.level = 1

def draw(self):
glTranslated(self.pos[0], self.pos[1], self.pos[2])
glRotated(self.rot,0,0,1)

#Get current view matrix, projection matrix and viewport rectangle
mv_matrix = glGetDoublev(GL_MODELVIEW_MATRIX)
proj_matrix = glGetDoublev(GL_PROJECTION_MATRIX)
vp_rect = glGetIntegerv(GL_VIEWPORT)

#Calculate "near" and "far" point
pt_near = gluUnProject(displayCenter[0], displayCenter[1], 0, mv_matrix, proj_matrix, vp_rect)
pt_far = gluUnProject(displayCenter[0], displayCenter[1], 1, mv_matrix, proj_matrix, vp_rect)
dist = isectCuboid(pt_near, pt_far, [-1, 0, -1], [1, 1, 1])

glBegin(GL_QUADS) #Begin fill
for surface in self.surfaces:
for vertex in surface:
glColor3f(0,1,0)
glVertex3fv(self.vertices[vertex])
glEnd()
glLineWidth(5) #Set width of the line
glBegin(GL_LINES) #Begin outline
for edge in self.edges:
for vertex in edge:
glColor3f(1,1,0)
glVertex3fv(self.vertices[vertex])
glEnd()

def move(self,x,y,z):
self.pos = (self.pos[0]+x,self.pos[1]+y,self.pos[2]+z)

glutInit()
persons = [Person() for person in range(person_count)]
ground = Ground()
for person in persons:
person.pos = random_pos(12)
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
if event.key == pygame.K_p:
paused = not paused
if not paused:
if event.type == pygame.MOUSEMOTION:
mouseMove = [event.pos[i] - displayCenter[i] for i in range(2)]
pygame.mouse.set_pos(displayCenter)
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
cam_attack = True

pygame.mouse.set_visible(False)
if not paused:
#Get keys
keypress = pygame.key.get_pressed()

#Init model view matrix
glLoadIdentity()

#------------------------View------------------------
#Apply the look up and down (with 90° angle limit)
if up_down_angle < -90:
if mouseMove[1] > 0:
up_down_angle += mouseMove[1]*0.1
elif up_down_angle > 90:
if mouseMove[1] < 0:
up_down_angle += mouseMove[1]*0.1
else:
up_down_angle += mouseMove[1]*0.1
glRotatef(up_down_angle, 1.0, 0.0, 0.0)

#Init the view matrix
glPushMatrix()
glLoadIdentity()

#Apply the movement
if keypress[pygame.K_w]:
glTranslatef(0,0,0.1)
if keypress[pygame.K_s]:
glTranslatef(0,0,-0.1)
if keypress[pygame.K_d]:
glTranslatef(-0.1,0,0)
if keypress[pygame.K_a]:
glTranslatef(0.1,0,0)

if knockback:
#Knockback3
knockback_dist = 10
glTranslatef(0, 0, -knockback_dist)
knockback = False

#Apply the look left and right
glRotatef(mouseMove[0]*0.1, 0.0, 1.0, 0.0)
#------------------------View------------------------

#Multiply the current matrix by the new view matrix and store the final view matrix
glMultMatrixf(viewMatrix)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
invVM = InverseMat44(viewMatrix)
camera_pos = (invVM[12],invVM[13],invVM[14])

#Apply view matrix
glPopMatrix()
glMultMatrixf(viewMatrix)

glLightfv(GL_LIGHT0, GL_POSITION, [1, -1, 1, 0])

#Follow, attack
crosshair_color = (1,1,1)
attacklist = []
for person in persons:
freturn = follower(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2],0.02)
xchange,ychange,zchange = freturn[0],freturn[1],freturn[2]
person.rot = freturn[3]
if (touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])) < 2.5:
xchange,ychange,zchange = 0,0,0
knockback = True
person.move(xchange,ychange,zchange)
if (touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])) < 5 and dist != None:
crosshair_color = (1,0,0)
if len(attacklist) >= 2:
bigger = attacklist[1] > touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])
if bigger == True:
attacklist = [person,touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])]
else:
attacklist = [person,touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])]
if attacklist:
if cam_attack == True:
attacklist[0].health -= cam_damage

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

#Draw crosshair, health
blit_text(displayCenter[0] - 5,displayCenter[1] - 5,GLUT_BITMAP_TIMES_ROMAN_24,"+",crosshair_color[0],crosshair_color[1],crosshair_color[2])
for person in persons:
if person.health > 0:
#print(person.health)
pass

glPushMatrix()

glColor4f(0.2, 0.2, 0.5, 1)
for person in persons:
glPushMatrix()
person.draw()
glPopMatrix()

ground.draw()
glPopMatrix()

for person in persons:
if person.health <= 0:
persons.remove(person)

cam_attack = False
pygame.display.flip()
pygame.time.wait(10)

pygame.quit()
sys.exit()

最佳答案

您在视口(viewport)上看到的是 3 维场景的 2 维投影。因此,2D 视口(viewport)上的每个点都是 3D 场景中的一条光线,从近平面(靠近眼睛)到远平面。在视口(viewport)上“看到”的对象是该射线“击中”的第一个对象。

可以轻松找到射线。查看问题的答案ray intersection misses the target .

识别被这条射线击中的物体是很困难的。它很大程度上取决于场景中绘制的对象(网格),可以通过 Ray casting 来实现.
您必须与每个对象(网格)相交并计算 Euclidean distance到交点。最接近相机(眼睛)位置的物体是“获胜者”。
如何使射线与物体相交取决于物体的几何形状和定义。

<小时/>

让我用一个例子来演示这一点。下面我引用你上一个问题的代码:How to rotate a certain object (Quad) in PyOpenGL?

要找到穿过世界的射线,您必须将窗口坐标映射到对象坐标。
如果屏幕中间有十字准线,则 x 和 y 窗口坐标为

cross_x, cross_y = display[0]/2, display[1]/2

从相机位置看,具有相同 x 和 y 坐标的所有点都在同一条射线上。
射线上 2 个点的 z 坐标是最小深度值 (0) 和最大深度值 (1)。要将窗口坐标映射到对象坐标,gluUnProject可以使用。
参数为gluUnProject属于 GLdouble 类型:

# get current view matrix, projection matrix and viewport rectangle 
mv_matrix = glGetDoublev(GL_MODELVIEW_MATRIX)
proj_matrix = glGetDoublev(GL_PROJECTION_MATRIX)
vp_rect = glGetIntegerv(GL_VIEWPORT)

# calculate "near" and "far" point
pt_near = gluUnProject(cross_x, cross_y, 0, mv_matrix, proj_matrix, vp_rect)
pt_far = gluUnProject(cross_x, cross_y, 1, mv_matrix, proj_matrix, vp_rect)

在之后添加此代码

#Apply view matrix
glPopMatrix()
glMultMatrixf(viewMatrix)

如果您有一个圆形物体,那么您必须使光线与球体相交。编写一个函数,如果射线与球体相交,则返回到球体的距离,否则
以下函数的算法我取自 Peter Shirley 的书 Ray Tracing in One Weekend :

def subtract(v0, v1):
return [v0[0]-v1[0], v0[1]-v1[1], v0[2]-v1[2]]
def dot(v0, v1):
return v0[0]*v1[0]+v0[1]*v1[1]+v0[2]*v1[2]
def length(v):
return math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2])
def normalize(v):
l = length(v)
return [v[0]/l, v[1]/l, v[2]/l]

# Ray - Sphere intersection
#
# Sphere: dot(p-C, p-C) = R*R `C`: center, `p`: point on the sphere, `R`, radius
# Ray: p(t) = A + B * t `A`: origin, `B`: direction
# Intersection: dot(A+B*t-C, A+B*t-C) = R*R
# t*t*dot(B,B) + 2*t*dot(B,A-C) + dot(A-C,A-C) - R*R = 0
def isectSphere(p0, p1, C, R):
A = p0 # origin
B = normalize(subtract(p1, p0)) # direction
oc = subtract(A, C)
a = dot(B, B)
b = 2 * dot(oc, B)
c = dot(oc, oc) - R*R
discriminant = b*b - 4*a*c
if discriminant > 0:
t1 = (-b - math.sqrt(discriminant)) / (2*a)
t2 = (-b + math.sqrt(discriminant)) / (2*a)
t = min(t1, t2)
return t if t >= 0.0 else None
return None

按如下方式使用该函数:

dist = isectSphere(pt_near, pt_far, person.pos, 1.0)

if dist != None:
print(dist)
else:
print("no hit")
<小时/><小时/>

与轴对齐的长方体的相交需要更多的努力。长方体有 6 条边。您必须将每条边相交并找到最接近的一条。每条边都是一个四边形。与四边形的交集可以由 2 个三角形组成。

为了使射线和三角形相交,我已经移植了问题How to identify click inside the 3D object or outside 3D object using near and far positions的答案代码。从 C++ 到 Python:

def mults(v, s):
return [v[0]*s, v[1]*s, v[2]*s]
def add(v0, v1):
return [v0[0]+v1[0], v0[1]+v1[1], v0[2]+v1[2]]
def cross(v0, v1):
return [
v0[1]*v1[2]-v1[1]*v0[2],
v0[2]*v1[0]-v1[2]*v0[0],
v0[0]*v1[1]-v1[0]*v0[1]]
def PointInOrOn( P1, P2, A, B ):
CP1 = cross( subtract(B, A), subtract(P1, A) )
CP2 = cross( subtract(B, A), subtract(P2, A) )
return dot( CP1, CP2 ) >= 0
def PointInOrOnTriangle( P, A, B, C ):
return PointInOrOn( P, A, B, C ) and PointInOrOn( P, B, C, A ) and PointInOrOn( P, C, A, B )

# p0, p1 points on ray
# PA, PB, PC points of the triangle
def isectPlane(p0, p1, PA, PB, PC):
R0 = p0 # origin
D = normalize(subtract(p1, p0))
P0 = PA
NV = normalize( cross( subtract(PB, PA), subtract(PC, PA) ) )
dist_isect = dot( subtract(P0, R0), NV ) / dot( D, NV )
P_isect = add(R0, mults(D, dist_isect))
return P_isect, dist_isect
def isectTrianlge(p0, p1, PA, PB, PC):
P, t = isectPlane(p0, p1, PA, PB, PC)
if t >= 0 and PointInOrOnTriangle(P, PA, PB, PC):
return t
return None

四边形的交集与三角形的交集类似:

def PointInOrOnQuad( P, A, B, C, D ):
return (PointInOrOn( P, A, B, C ) and PointInOrOn( P, B, C, D ) and
PointInOrOn( P, C, D, A ) and PointInOrOn( P, D, A, B ))

def isectQuad(p0, p1, PA, PB, PC, PD):
P, t = isectPlane(p0, p1, PA, PB, PC)
if t >= 0 and PointInOrOnQuad(P, PA, PB, PC, PD):
return t
return None

对于与长方体的交集,必须在循环中找到与壁橱一侧的交集。长方体由其体积对角线上的 2 个点定义:

def isectCuboid(p0, p1, pMin, pMax):
t = None
try:
pl = [[pMin[0], pMin[1], pMin[2]], [pMax[0], pMin[1], pMin[2]],
[pMax[0], pMax[1], pMin[2]], [pMin[0], pMax[1], pMin[2]],
[pMin[0], pMin[1], pMax[2]], [pMax[0], pMin[1], pMax[2]],
[pMax[0], pMax[1], pMax[2]], [pMin[0], pMax[1], pMax[2]]]
il = [[0, 1, 2, 3], [4, 5, 6, 7], [4, 0, 3, 7], [1, 5, 6, 2], [4, 3, 1, 0], [3, 2, 6, 7]]
for qi in il:
ts = isectQuad(p0, p1, pl[qi[0]], pl[qi[1]], pl[qi[2]], pl[qi[3]] )
if ts != None and ts >= 0 and (t == None or ts < t):
t = ts
except:
t = None
return t

长方体在场景中移动,因此可以定义它在世界中的位置。但由于旋转,它的方向也会动态变化。因此,长方体在世界空间中不是轴对齐的,但在对象空间中是轴对齐的。
这意味着光线的点必须转换到物体空间而不是世界空间。对象空间矩阵是在长方体的 .draw() 方法中进行模型转换后设置的。将相交测试移至 .draw() 方法:

class Person:

# [...]

def draw(self):
global dist

glTranslated(self.pos[0], self.pos[1], self.pos[2])
glRotated(self.rot,0,0,1)

mv_matrix = glGetDoublev(GL_MODELVIEW_MATRIX)
proj_matrix = glGetDoublev(GL_PROJECTION_MATRIX)
vp_rect = glGetIntegerv(GL_VIEWPORT)

cross_x, cross_y = display[0]/2, display[1]/2
pt_near = gluUnProject(cross_x, cross_y, 0, mv_matrix, proj_matrix, vp_rect)
pt_far = gluUnProject(cross_x, cross_y, 1, mv_matrix, proj_matrix, vp_rect)

#dist = isectSphere(pt_near, pt_far, [0, 0, 0], 1.0)
dist = isectCuboid(pt_near, pt_far, [-1, 0, -1], [1, 1, 1])

if dist != None:
print(dist)
else:
print("no hit")

glBegin(GL_QUADS) #Begin fill
for surface in self.surfaces:
for vertex in surface:
glColor3f(0,1,0)
glVertex3fv(self.vertices[vertex])
glEnd()
glLineWidth(5) #Set width of the line
glBegin(GL_LINES) #Begin outline
for edge in self.edges:
for vertex in edge:
glColor3f(1,1,0)
glVertex3fv(self.vertices[vertex])
glEnd()

关于python - 如何测试 pygame 屏幕中的 2d 点是否是 PyOpenGL 中 3d 对象的一部分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56681932/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com