Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用相机自己的新轴进行三维旋转_Python_Matrix_3d - Fatal编程技术网

Python 使用相机自己的新轴进行三维旋转

Python 使用相机自己的新轴进行三维旋转,python,matrix,3d,Python,Matrix,3d,为了理解3D图形(主要是矩阵变换部分), 我用tkinter制作了一个简单的3D引擎 问题是,现在,在添加了一个摄像头之后,我被卡住了。我想绑定WASDEQ键来移动相机(W是向上的,S是向下的,A是向左的,D是向右的,E是向前的,Q是向后的)和箭头键来旋转它。然而,在尝试这些特性时,我发现它们总是相对于XYZ轴进行的。这意味着,如果我的相机指向正下方,我会期望(按下E键后)朝向它所看到的地方。但是,它指向负Z轴 旋转相机也是如此。由于某些原因,总是相对于相机的当前位置进行左右查看,但上下查看是相

为了理解3D图形(主要是矩阵变换部分), 我用tkinter制作了一个简单的3D引擎

问题是,现在,在添加了一个摄像头之后,我被卡住了。我想绑定WASDEQ键来移动相机(W是向上的,S是向下的,A是向左的,D是向右的,E是向前的,Q是向后的)和箭头键来旋转它。然而,在尝试这些特性时,我发现它们总是相对于XYZ轴进行的。这意味着,如果我的相机指向正下方,我会期望(按下E键后)朝向它所看到的地方。但是,它指向负Z轴

旋转相机也是如此。由于某些原因,总是相对于相机的当前位置进行左右查看,但上下查看是相对于X轴进行的,而不是相对于相机的当前位置。如果有人能为我提供一个解决方案或材料,解释必要的转换顺序,我将不胜感激

以下是完整的代码,相对较短:

import numpy
import math
import tkinter

#Window dimensions
width = 800
height = 800

#An empty canvas
cnv = tkinter.Canvas(bg='white', width=width, height=height)

#Triangle rasterization
def drawTriangle(triangle):
    cnv.create_line(triangle[0][0],height-triangle[0][1],triangle[1][0],height-triangle[1][1])
    cnv.create_line(triangle[1][0],height-triangle[1][1],triangle[2][0],height-triangle[2][1])
    cnv.create_line(triangle[2][0],height-triangle[2][1],triangle[0][0],height-triangle[0][1])

#Adding a homogenous coordinate (w)
def homogenous(vertex):
    vertex.append(1)

#Transforming row major vertexes to column major vertexes
def transpose(vertex):
    return numpy.array([vertex]).T


#SPACE CONVERSION

#Our cube is in its model space. We want to put it onto our scene, while rotating it a bit and moving it further away from the camera.
#model space->world space
#Applying the transformation to all of our vertexes
def modelToWorld(vertex,x,y,z):
    # Rotation angles
    xangle = math.radians(x)
    yangle = math.radians(y)
    zangle = math.radians(z)

    # Rotation matrices
    xRotationMatrix = numpy.array(
        [[1, 0, 0, 0], [0, math.cos(xangle), -math.sin(xangle), 0], [0, math.sin(xangle), math.cos(xangle), 0],
         [0, 0, 0, 1]])
    yRotationMatrix = numpy.array(
        [[math.cos(yangle), 0, math.sin(yangle), 0], [0, 1, 0, 0], [-math.sin(yangle), 0, math.cos(yangle), 0],
         [0, 0, 0, 1]])
    zRotationMatrix = numpy.array(
        [[math.cos(zangle), -math.sin(zangle), 0, 0], [math.sin(zangle), math.cos(zangle), 0, 0], [0, 0, 1, 0],
         [0, 0, 0, 1]])
    # Translation along the negative Z axis
    TranslationMatrix = numpy.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, -6], [0, 0, 0, 1]])
    # Combining the transformations into one model matrix
    ModelMatrix = numpy.dot(yRotationMatrix, xRotationMatrix)
    ModelMatrix = numpy.dot(zRotationMatrix, ModelMatrix)
    ModelMatrix = numpy.dot(TranslationMatrix, ModelMatrix)
    return numpy.dot(ModelMatrix,vertex)


#Now we want to move our camera
#We cannot move the camera itself, we need to move the world. So in order to move the camera 1 unit closer to the cube,
#we need to move the cube closer to the camera. Remember, the camera always points to the negative Z axis.
#world space->view space
zoom_num=0
#View matrix
#Applying the transformation to all of our vertexes
xcam=0
ycam=0
zcam=0
camXangle=0
camYangle=0
camZangle=0
def worldToView(vertex):
    CamyRotationMatrix = numpy.array(
        [[math.cos(math.radians(camYangle)), 0, math.sin(math.radians(camYangle)), 0], [0, 1, 0, 0], [-math.sin(math.radians(camYangle)), 0, math.cos(math.radians(camYangle)), 0],
         [0, 0, 0, 1]])
    CamxRotationMatrix = numpy.array(
        [[1, 0, 0, 0], [0, math.cos(math.radians(camXangle)), -math.sin(math.radians(camXangle)), 0], [0, math.sin(math.radians(camXangle)), math.cos(math.radians(camXangle)), 0],
         [0, 0, 0, 1]])
    CamTranslationMatrix = numpy.array([[1, 0, 0, 0+xcam], [0, 1, 0, 0+ycam], [0, 0, 1, 0 + zcam], [0, 0, 0, 1]])
    CamRotationMatrix = numpy.dot(CamyRotationMatrix, CamxRotationMatrix)
    ViewMatrix = numpy.dot(CamRotationMatrix, CamTranslationMatrix)
    return numpy.dot(ViewMatrix,vertex)

#Now we need to apply the projection matrix to create perspective.
#view space->clip space

#Projection matrix
ProjectionMatrix = numpy.array([[0.8,0,0,0], [0,0.8,0,0],[0,0,-1.22,-2.22],[0,0,-1,0]])
#ProjectionMatrix = numpy.array([[0.25,0,0,0], [0,0.25,0,0],[0,0,-0.22,-1.22],[0,0,0,1]])
def viewToClip(vertex):
    return numpy.dot(ProjectionMatrix,vertex)


#In order to turn the resulting coordinates into NDC, we need to divide by W.
def perspectiveDivision(vertex):
    for j in range(4):
        vertex[j]=vertex[j]/vertex[3]
    return vertex

#Turning values from -1 to 1 into individual pixels on the screen
def viewportTransformation(vertex):
    vertex[0] = (vertex[0] * 0.5 + 0.5) * width
    vertex[1] = (vertex[1] * 0.5 + 0.5) * height
    return vertex

#Rounding the resulting values
def roundPixel(vertex):
    vertex[0]=  int(round(vertex[0][0]))
    vertex[1] = int(round(vertex[1][0]))
    return vertex




#Vertexes of cube triangles
cubeMesh2=[
                [-1,-1,-1],[1,-1,-1],[1,-1,1]  ,  [-1,-1,-1],[1,-1,1],[-1,-1,1], #TOP
                [1,-1,-1],[1,1,-1],[1,1,1]     ,  [1,-1,-1],[1,1,1],[1,-1,1],    #RIGHT
                [-1,1,-1],[-1,-1,-1],[-1,-1,1] ,  [-1,1,-1],[-1,-1,1],[-1,1,1],  #LEFT
                [1,1,-1],[-1,1,-1],[-1,1,1]    ,  [1,1,-1],[-1,1,1],[1,1,1],     #BOTTOM
                [-1,-1,1],[1,-1,1],[1,1,1]   ,  [-1,-1,1],[1,1,1],[-1,1,1],      #NEAR
                [1,-1,-1],[-1,-1,-1],[-1,1,-1]  ,  [1,-1,-1],[-1,1,-1],[1,1,-1]  #FAR
]

cubeMesh=[
[-2, 0, -2],[2, 0, -2],[-2, 0, 2],
[-2, 0, 2],[2, 0, -2],[2, 0, 2],
[-0.5, 0., -0.5 ],
[-0.5, 1., -0.5 ],
[-0.5, 0, 0.5],
[-0.5, 1, -0.5],
[-0.5, 0., 0.5],
[-0.5, 1., 0.5],
[-0.5, 0., -0.5],
[-0.5, 1., -0.5],
[0.5, 0., -0.5],
[-0.5, 1., -0.5],
[0.5, 0., -0.5],
[0.5, 1., -0.5],
[0.5, 0., -0.5],
[0.5, 1., -0.5],
[0.5, 0., 0.5],
[0.5, 1., -0.5],
[0.5, 0., 0.5],
[0.5, 1, 0.5],
[-0.5, 0., 0.5],
[-0.5, 1., 0.5],
[0.5, 0., 0.5],
[-0.5, 1., 0.5],
[0.5, 0., 0.5],
[0.5, 1., 0.5],
[-0.5, 1., -0.5],
[-0.5, 1., 0.5],
[0., 2., 0.0],
[0.5, 1., -0.5],
[0.5, 1., 0.5],
[0., 2., 0.0],
[-0.5, 1., -0.5],
[0.5, 1., -0.5],
[0., 2., 0.0],
[-0.5, 1, 0.5],
[0.5, 1, 0.5],
[0., 2., 0.0]
]


#An empty triangle
Triangle=[[0,0,0],[0,0,0],[0,0,0]]

#Colors
colors = [(255,0,0),(255,0,0),(0,255,0),(0,255,0),(0,0,255),(0,0,255),(255,255,0),(255,255,0),(0,255,255),(0,255,255),(255,0,255),(255,0,255)]

#Triangle counter
counter=0
cnv.pack()


for i in range(len(cubeMesh)):
    homogenous(cubeMesh[i])               # Adding a homogenous coordinate
    cubeMesh[i] = transpose(cubeMesh[i])  # Changing a row vector to a column vector


changingMesh = cubeMesh.copy()
j=0
def update():
        cnv.delete("all")
        counter=0
        global j
        for i in range(len(cubeMesh)):
            changingMesh[i]=modelToWorld(cubeMesh[i],0,0,0)              #Moving our model to its place on world coordinates
            changingMesh[i]=worldToView(changingMesh[i])               #Moving the world relative to our camera ("moving" the camera)
            changingMesh[i]=viewToClip(changingMesh[i])                #Applying projection
            changingMesh[i] = perspectiveDivision(changingMesh[i])  # Dividing by W to get to normalised device coordinates
            changingMesh[i] = viewportTransformation(changingMesh[i])  # Changing the normalised device coordinates to pixels on the screen
            changingMesh[i] = roundPixel(changingMesh[i])  # Rounding the resulting values to nearest pixel
            Triangle[i%3][0] = int(changingMesh[i][0])
            Triangle[i%3][1] = int(changingMesh[i][1])
            Triangle[i % 3][2] = int(changingMesh[i][2])
            if i%3==2:
                drawTriangle(Triangle)
                counter+=1
        j+=1
        if j == 365:
            j=0
        cnv.after(5,update)

update()
def move(event):
    global xcam
    global ycam
    global zcam
    if event.char=='q':
        zcam+=0.2
    if event.char == 'e':
        zcam-=0.2
    if event.char=='a':
        xcam+=0.2
    if event.char == 'd':
        xcam-=0.2
    if event.char=='w':
        ycam-=0.2
    if event.char == 's':
        ycam+=0.2

def rotateLeft(event):
    global camYangle
    camYangle-=4
def rotateRight(event):
    global camYangle
    camYangle+=4
def rotateUp(event):
    print("hey")
    global camXangle
    camXangle+=4
def rotateDown(event):
    global camXangle
    camXangle-=4

cnv.bind_all('<Key>', move)
cnv.bind_all('<Left>',rotateLeft)
cnv.bind_all('<Right>',rotateRight)
cnv.bind_all('<Up>',rotateUp)
cnv.bind_all('<Down>',rotateDown)


tkinter.mainloop()
导入numpy
输入数学
进口tkinter
#窗口尺寸
宽度=800
高度=800
#空画布
cnv=tkinter.Canvas(bg='white',宽度=宽度,高度=高度)
#三角光栅化
def drawTriangle(三角形):
cnv.创建_线(三角形[0][0]、高度三角形[0][1]、三角形[1][0]、高度三角形[1][1])
cnv.创建_线(三角形[1][0]、高度三角形[1][1]、三角形[2][0]、高度三角形[2][1])
cnv.创建_线(三角形[2][0]、高度三角形[2][1]、三角形[0][0]、高度三角形[0][1])
#添加同质坐标(w)
def同质(顶点):
顶点追加(1)
#将行主顶点转换为列主顶点
def转置(顶点):
返回numpy.array([vertex]).T
#空间转换
#我们的立方体在它的模型空间中。我们想把它放到我们的场景中,同时旋转一点,把它移到离相机更远的地方。
#模型空间->世界空间
#将变换应用于所有顶点
def modelToWorld(顶点,x,y,z):
#旋转角度
x角=数学弧度(x)
杨乐=数学弧度(y)
赞格尔=数学弧度(z)
#旋转矩阵
xRotationMatrix=numpy.array(
[1,0,0,0],[0,math.cos(xangle),-math.sin(xangle),0],[0,math.sin(xangle),math.cos(xangle),0],
[0, 0, 0, 1]])
yRotationMatrix=numpy.array(
[math.cos(yangle),0,math.sin(yangle),0],[0,1,0,0],-math.sin(yangle),0,math.cos(yangle),0],
[0, 0, 0, 1]])
zRotationMatrix=numpy.array(
[math.cos(赞歌),-math.sin(赞歌),0,0],[math.sin(赞歌),math.cos(赞歌),0,0],[0,0,1,0],
[0, 0, 0, 1]])
#沿负Z轴的平移
TranslationMatrix=numpy.array([[1,0,0,0],[0,1,0,0],[0,0,1,6],[0,0,0,1])
#将转换组合成一个模型矩阵
ModelMatrix=numpy.dot(旋转矩阵,X旋转矩阵)
ModelMatrix=numpy.dot(zRotationMatrix,ModelMatrix)
ModelMatrix=numpy.dot(TranslationMatrix,ModelMatrix)
返回numpy.dot(ModelMatrix,顶点)
#现在我们想移动我们的相机
#我们不能移动相机本身,我们需要移动世界。因此,为了使摄像机1装置更靠近立方体,
#我们需要把立方体移近摄像机。请记住,摄影机始终指向负Z轴。
#世界空间->视图空间
缩放数量=0
#视图矩阵
#将变换应用于所有顶点
xcam=0
ycam=0
zcam=0
camXangle=0
camYangle=0
卡姆桑格尔=0
def worldToView(顶点):
CamyRotationMatrix=numpy.array(
[math.cos(math.radians(camYangle)),0,math.sin(math.radians(camYangle)),0],[0,1,0,0],-math.sin(math.radians(camYangle)),0,math.cos(math.radians(camYangle)),0],
[0, 0, 0, 1]])
CamxRotationMatrix=numpy.array(
[1,0,0,0],[0,math.cos(math.radians(camXangle)),-math.sin(math.radians(camXangle)),0],[0,math.sin(math.radians(camXangle)),math.cos(math.radians(camXangle)),0],
[0, 0, 0, 1]])
CamTranslationMatrix=numpy.array([[1,0,0,0+xcam],[0,1,0,0+ycam],[0,0,1,0+zcam],[0,0,0,1]]
CamRotationMatrix=numpy.dot(CamyRotationMatrix,CamxRotationMatrix)
ViewMatrix=numpy.dot(凸轮旋转矩阵、凸轮平移矩阵)
返回numpy.dot(ViewMatrix,顶点)
#现在我们需要应用投影矩阵来创建透视图。
#查看空间->剪辑空间
#投影矩阵
ProjectionMatrix=numpy.array([[0.8,0,0,0,0],[0,0.8,0,0],[0,0,-1.22,-2.22],[0,0,-1,0]])
#ProjectionMatrix=numpy.array([[0.25,0,0,0,0],[0,0.25,0,0],[0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0,0])
def viewToClip(顶点):
返回numpy.dot(投影矩阵,顶点)
#为了将结果坐标转换为NDC,我们需要除以W。
def透视分区(顶点):
对于范围(4)内的j:
顶点[j]=顶点[j]/顶点[3]
返回顶点
#将值从-1转换为屏幕上的单个像素
def视口转换(顶点):
顶点[0]=(顶点[0]*0.5+0.5)*宽度
顶点[1]=(顶点[1]*0.5+0.5)*高度
返回顶点
#将结果值四舍五入
def圆形像素(顶点):
顶点[0]=int(圆形(顶点[0][0]))
顶点[1]=int(圆形(顶点[1][0]))
返回顶点
#立方体三角形的顶点
立方二=[
[1,-1,-1],[1,-1,-1],[1,-1,1],[1,-1,1],[1,-1,1],-1,-1,1],#顶部
[1,-1,-1],[1,1,-1],[1,1,1],[1,-1,-1],[1,1,1],[1,-1,1],#对
[1,1,-1],-1,-1,-1],-1,-1,1],-1,1,-1,-1,1],-1,1,1],#左
[1,1,-1]、-1,1,-1]、-1,1,1]、[1,1,-1]、-1,1,1]、[1,1,1]、#底部
[1,-1,1],[1,-1,1],[1,1,1],-1,-1,1],[1,1,1],-1,1,1],#NEAR
[1,-1,-1]、-1,-1]、-1,1,-1]、[1,-1,-1]、-1,1,-1]、[1,1,-1]#
]
立方目=[
[-2, 0, -2],[2, 0, -2],[-2, 0, 2],
[-2, 0, 2],[2, 0, -2],[2, 0, 2],
[-0.5, 0., -0.5 ],
[-0.5, 1., -0.5 ],
[-0.5, 0, 0.5],
[-0.5, 1, -0.5],
[-0.5, 0., 0.5],