如何使用 pygame 绘制 3D 形状(没有其他模块)

p99*_*ill 2 python theory 3d pygame shapes

如何使用 pygame 创建和渲染 3D 形状而不使用任何其他模块。我想创建自己的简单 3D 引擎。我可以画一个 3D 盒子,只是不知道如何调整线条的长度和位置,以在旋转盒子时给出 3D 效果。

我很难理解physics旋转物体时的阴影、深度感知和照明

假设我有一个盒子:

class box1():
    x=100
    y=100
    z=100

    size = 150 #length for distance between each point

    point1 = 0,0,0 # top left front
    point2 = 0,0,0 # top right front
    point3 = 0,0,0 # bottom left front
    point4 = 0,0,0 # bottom right front
    point5 = 0,0,0 # top left back
    point6 = 0,0,0 # top right back
    point7 = 0,0,0 # bottom left back
    point8 = 0,0,0 # bottom right back



def set_points():
    x=box1.x
    y=box1.y
    z=box1.z

    size = box1.size

    #this part sets all the points x,y,x co-cords at the correct locations
    #  _____  4____6
    # |\____\  1____2
    # | |    | Middle [x,y,z]
    # |_| `  | 7____8
    #  \|____| 3____4
    #
    # the +50 is just a test to show the 'offset' of the behind points
    box1.point1 = [x-(size/2),y-(size/2),z-(size/2)] # top left front
    box1.point2 = [x+(size/2),y-(size/2),z-(size/2)] # top right front
    box1.point3 = [x-(size/2),y+(size/2),z-(size/2)] # bottom left front
    box1.point4 = [x+(size/2),y+(size/2),z-(size/2)] # bottom right front
    box1.point5 = [x-(size/2)+50,y-(size/2)+50,z+(size/2)] # top left back
    box1.point6 = [x+(size/2)+50,y-(size/2)+50,z+(size/2)] # top right back
    box1.point7 = [x-(size/2)+50,y+(size/2)+50,z+(size/2)] # bottom left back
    box1.point8 = [x+(size/2)+50,y+(size/2)+50,z+(size/2)] # bottom right back


camara_pos = [20,20,20] # I don't know how to make the points based off this
camara_angle = [45,0,0] # or this



while True:
    set_points()
    g.DISPLAYSURF.fill((0,0,0))

    for event in pygame.event.get():
        if event.type == QUIT:
            exit()

    #draws all the lines connecting all the points .
    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point1[0],box1.point1[1]),(box1.point2[0],box1.point2[1]))
    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point3[0],box1.point3[1]),(box1.point4[0],box1.point4[1]))
    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point2[0],box1.point2[1]),(box1.point4[0],box1.point4[1]))
    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point1[0],box1.point1[1]),(box1.point3[0],box1.point3[1]))

    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point5[0],box1.point5[1]),(box1.point6[0],box1.point6[1]))
    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point7[0],box1.point7[1]),(box1.point8[0],box1.point8[1]))
    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point6[0],box1.point6[1]),(box1.point8[0],box1.point8[1]))
    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point5[0],box1.point5[1]),(box1.point7[0],box1.point7[1]))

    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point1[0],box1.point1[1]),(box1.point5[0],box1.point5[1]))
    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point2[0],box1.point2[1]),(box1.point6[0],box1.point6[1]))
    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point3[0],box1.point3[1]),(box1.point7[0],box1.point7[1]))
    pygame.draw.line(g.DISPLAYSURF, (128,128,128), (box1.point4[0],box1.point4[1]),(box1.point8[0],box1.point8[1]))

    pygame.display.update()
Run Code Online (Sandbox Code Playgroud)

高级图

谁能解释一下这个理论吗?谁能告诉我一些代码来计算分数?

Nit*_*och 6

您需要了解的唯一魔法称为“旋转矩阵”

\n\n

如果在这样的矩阵和向量之间执行乘法,就会得到旋转的向量。

\n\n

有了这些信息(即复制维基百科的 3D 旋转矩阵之后),我最终得到了这个好东西:

\n\n
import pygame\nfrom numpy import array\nfrom math import cos, sin\n\n\n######################\n#                    #\n#    math section    #\n#                    #\n######################\n\nX, Y, Z = 0, 1, 2\n\n\ndef rotation_matrix(\xce\xb1, \xce\xb2, \xce\xb3):\n    """\n    rotation matrix of \xce\xb1, \xce\xb2, \xce\xb3 radians around x, y, z axes (respectively)\n    """\n    s\xce\xb1, c\xce\xb1 = sin(\xce\xb1), cos(\xce\xb1)\n    s\xce\xb2, c\xce\xb2 = sin(\xce\xb2), cos(\xce\xb2)\n    s\xce\xb3, c\xce\xb3 = sin(\xce\xb3), cos(\xce\xb3)\n    return (\n        (c\xce\xb2*c\xce\xb3, -c\xce\xb2*s\xce\xb3, s\xce\xb2),\n        (c\xce\xb1*s\xce\xb3 + s\xce\xb1*s\xce\xb2*c\xce\xb3, c\xce\xb1*c\xce\xb3 - s\xce\xb3*s\xce\xb1*s\xce\xb2, -c\xce\xb2*s\xce\xb1),\n        (s\xce\xb3*s\xce\xb1 - c\xce\xb1*s\xce\xb2*c\xce\xb3, c\xce\xb1*s\xce\xb3*s\xce\xb2 + s\xce\xb1*c\xce\xb3, c\xce\xb1*c\xce\xb2)\n    )\n\n\nclass Physical:\n    def __init__(self, vertices, edges):\n        """\n        a 3D object that can rotate around the three axes\n        :param vertices: a tuple of points (each has 3 coordinates)\n        :param edges: a tuple of pairs (each pair is a set containing 2 vertices\' indexes)\n        """\n        self.__vertices = array(vertices)\n        self.__edges = tuple(edges)\n        self.__rotation = [0, 0, 0]  # radians around each axis\n\n    def rotate(self, axis, \xce\xb8):\n        self.__rotation[axis] += \xce\xb8\n\n    @property\n    def lines(self):\n        location = self.__vertices.dot(rotation_matrix(*self.__rotation))  # an index->location mapping\n        return ((location[v1], location[v2]) for v1, v2 in self.__edges)\n\n\n######################\n#                    #\n#    gui section     #\n#                    #\n######################\n\n\nBLACK, RED = (0, 0, 0), (255, 128, 128)\n\n\nclass Paint:\n    def __init__(self, shape, keys_handler):\n        self.__shape = shape\n        self.__keys_handler = keys_handler\n        self.__size = 450, 450\n        self.__clock = pygame.time.Clock()\n        self.__screen = pygame.display.set_mode(self.__size)\n        self.__mainloop()\n\n    def __fit(self, vec):\n        """\n        ignore the z-element (creating a very cheap projection), and scale x, y to the coordinates of the screen\n        """\n        # notice that len(self.__size) is 2, hence zip(vec, self.__size) ignores the vector\'s last coordinate\n        return [round(70 * coordinate + frame / 2) for coordinate, frame in zip(vec, self.__size)]\n\n    def __handle_events(self):\n        for event in pygame.event.get():\n            if event.type == pygame.QUIT:\n                exit()\n        self.__keys_handler(pygame.key.get_pressed())\n\n    def __draw_shape(self, thickness=4):\n        for start, end in self.__shape.lines:\n            pygame.draw.line(self.__screen, RED, self.__fit(start), self.__fit(end), thickness)\n\n    def __mainloop(self):\n        while True:\n            self.__handle_events()\n            self.__screen.fill(BLACK)\n            self.__draw_shape()\n            pygame.display.flip()\n            self.__clock.tick(40)\n\n\n######################\n#                    #\n#     main start     #\n#                    #\n######################\n\n\ndef main():\n    from pygame import K_q, K_w, K_a, K_s, K_z, K_x\n\n    cube = Physical(  # 0         1            2            3           4            5            6            7\n        vertices=((1, 1, 1), (1, 1, -1), (1, -1, 1), (1, -1, -1), (-1, 1, 1), (-1, 1, -1), (-1, -1, 1), (-1, -1, -1)),\n        edges=({0, 1}, {0, 2}, {2, 3}, {1, 3},\n               {4, 5}, {4, 6}, {6, 7}, {5, 7},\n               {0, 4}, {1, 5}, {2, 6}, {3, 7})\n    )\n\n    counter_clockwise = 0.05  # radians\n    clockwise = -counter_clockwise\n\n    params = {\n        K_q: (X, clockwise),\n        K_w: (X, counter_clockwise),\n        K_a: (Y, clockwise),\n        K_s: (Y, counter_clockwise),\n        K_z: (Z, clockwise),\n        K_x: (Z, counter_clockwise),\n    }\n\n    def keys_handler(keys):\n        for key in params:\n            if keys[key]:\n                cube.rotate(*params[key])\n\n    pygame.init()\n    pygame.display.set_caption(\'Control -   q,w : X    a,s : Y    z,x : Z\')\n    Paint(cube, keys_handler)\n\nif __name__ == \'__main__\':\n    main()\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,我确实使用 NumPy 模块进行矩阵乘法(并使用数学进行三角函数);我假设“没有其他模块”是指“没有任何 3D 库”。\n无论如何,您可以实现自己的矩阵乘法函数并使用泰勒级数计算 sin\\cos,但这是完全没有必要的。

\n