Python 3D立方体有4个透视

时间:2013-12-09 18:08:01

标签: python 3d pygame trigonometry

前几天我构建的体积显示几乎与此链接中的相同(http://hackaday.com/2011/01/18/glimpses-of-a-3d-volumetric-display/

它连接到VGA显示器,虽然它很容易在四个金字塔斜坡中的一个上显示图像,但我试图同时和同步地为四个斜坡中的每一个显示四个不同角度的三维图像。我目前正在使用这里发现的3D立方体Pygame示例http://codentronix.com/2011/05/12/rotating-3d-cube-using-python-and-pygame/进行修改以显示多个立方体。

"""
 Simulation of a rotating 3D Cube
 Developed by Leonel Machava <leonelmachava@gmail.com>

 http://codeNtronix.com
"""
import sys, math, pygame
from operator import itemgetter

class Point3D:
    def __init__(self, x = 0, y = 0, z = 0):
        self.x, self.y, self.z = float(x), float(y), float(z)

    def rotateX(self, angle):
        """ Rotates the point around the X axis by the given angle in degrees. """
        rad = angle * math.pi / 180
        cosa = math.cos(rad)
        sina = math.sin(rad)
        y = self.y * cosa - self.z * sina
        z = self.y * sina + self.z * cosa
        return Point3D(self.x, y, z)

    def rotateY(self, angle):
        """ Rotates the point around the Y axis by the given angle in degrees. """
        rad = angle * math.pi / 180
        cosa = math.cos(rad)
        sina = math.sin(rad)
        z = self.z * cosa - self.x * sina
        x = self.z * sina + self.x * cosa
        return Point3D(x, self.y, z)

    def rotateZ(self, angle):
        """ Rotates the point around the Z axis by the given angle in degrees. """
        rad = angle * math.pi / 180
        cosa = math.cos(rad)
        sina = math.sin(rad)
        x = self.x * cosa - self.y * sina
        y = self.x * sina + self.y * cosa
        return Point3D(x, y, self.z)

    def project(self, win_width, win_height, fov, viewer_distance, offsetX=0, offsetY=0):
        """ Transforms this 3D point to 2D using a perspective projection. """
        factor = fov / (viewer_distance + self.z)
        x = self.x * factor + win_width / 2
        y = -self.y * factor + win_height / 2
        return Point3D(x + offsetX, y + offsetY, self.z)

class Simulation:
    def __init__(self, win_width = 640, win_height = 480):
        pygame.init()

        self.screen = pygame.display.set_mode((win_width, win_height))
        pygame.display.set_caption("Simulation of a rotating 3D Cube (http://codeNtronix.com)")

        self.clock = pygame.time.Clock()

        self.vertices = [
            Point3D(-1,1,-1),
            Point3D(1,1,-1),
            Point3D(1,-1,-1),
            Point3D(-1,-1,-1),
            Point3D(-1,1,1),
            Point3D(1,1,1),
            Point3D(1,-1,1),
            Point3D(-1,-1,1)
        ]

        # Define the vertices that compose each of the 6 faces. These numbers are
        # indices to the vertices list defined above.
        self.faces  = [(0,1,2,3),(1,5,6,2),(5,4,7,6),(4,0,3,7),(0,4,5,1),(3,2,6,7)]

        # Define colors for each face
        self.colors = [(255,0,255),(255,0,0),(0,255,0),(0,0,255),(0,255,255),(255,255,0)]

        self.angle = 0

    def run(self):
        """ Main Loop """
        while 1:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()

            self.clock.tick(50)
            self.screen.fill((0,32,0))

            # It will hold transformed vertices.
            t1 = []
            t2 = []

            for v in self.vertices:
                # Rotate the point around X axis, then around Y axis, and finally around Z axis.
                r = v.rotateX(self.angle).rotateY(self.angle).rotateZ(self.angle)
                #r = v.rotateX(self.angle).rotateY(self.angle).rotateZ(self.angle)
                # Transform the point from 3D to 2D
                p = r.project(self.screen.get_width(), self.screen.get_height(), 256, 4, offsetY=-150)
                # Put the point in the list of transformed vertices
                t1.append(p)

            for v in self.vertices:
                # Rotate the point around X axis, then around Y axis, and finally around Z axis.
                r = v.rotateX(self.angle + 180).rotateY(self.angle).rotateZ(self.angle + 180)
                #r = v.rotateX(self.angle).rotateY(self.angle).rotateZ(self.angle)
                # Transform the point from 3D to 2D
                p = r.project(self.screen.get_width(), self.screen.get_height(), 256, 4, offsetY=150)
                # Put the point in the list of transformed vertices
                t2.append(p)

            # Calculate the average Z values of each face.
            avg_z1 = []
            avg_z2 = []
            i = 0
            for f in self.faces:
                z = (t1[f[0]].z + t1[f[1]].z + t1[f[2]].z + t1[f[3]].z) / 4.0
                avg_z1.append([i,z])
                z = (t2[f[0]].z + t2[f[1]].z + t2[f[2]].z + t2[f[3]].z) / 4.0
                avg_z2.append([i,z])
                i = i + 1

            # Draw the faces using the Painter's algorithm:
            # Distant faces are drawn before the closer ones.
            for tmp in sorted(avg_z1,key=itemgetter(1),reverse=True):
                face_index = tmp[0]
                f = self.faces[face_index]
                pointlist = [(t1[f[0]].x, t1[f[0]].y), (t1[f[1]].x, t1[f[1]].y),
                             (t1[f[1]].x, t1[f[1]].y), (t1[f[2]].x, t1[f[2]].y),
                             (t1[f[2]].x, t1[f[2]].y), (t1[f[3]].x, t1[f[3]].y),
                             (t1[f[3]].x, t1[f[3]].y), (t1[f[0]].x, t1[f[0]].y)]
                pygame.draw.polygon(self.screen,self.colors[face_index],pointlist)
            for tmp in sorted(avg_z2,key=itemgetter(1),reverse=True):
                face_index = tmp[0]
                f = self.faces[face_index]
                pointlist = [(t2[f[0]].x, t2[f[0]].y), (t2[f[1]].x, t2[f[1]].y),
                             (t2[f[1]].x, t2[f[1]].y), (t2[f[2]].x, t2[f[2]].y),
                             (t2[f[2]].x, t2[f[2]].y), (t2[f[3]].x, t2[f[3]].y),
                             (t2[f[3]].x, t2[f[3]].y), (t2[f[0]].x, t2[f[0]].y)]
                pygame.draw.polygon(self.screen,self.colors[face_index],pointlist)


            self.angle += 1

            pygame.display.flip()

if __name__ == "__main__":
    Simulation().run()

然而,我在绕着从四个侧面投影立方体所需的3D投影和旋转周围时遇到一些麻烦。我在这里使用数学的正确路径,还是我需要做的不仅仅是投影函数的角度偏移?

0 个答案:

没有答案