cjjJasonchen 发表于 2024-8-20 22:50:10

numpy旋转3d矩阵

本帖最后由 cjjJasonchen 于 2024-8-20 22:52 编辑

初始位置,x,y = 100,100

再旋转时y迅速变小到接近零,x缓慢变小至接近零

"""
矩阵旋转算法,这或许是真的3d?
"""

import pygame
import sys
import math
import numpy
import pygameGUI as pgui
from typing import List
from pygame.locals import *


class Sprites3D:
    X, Y, Z = 0, 1, 2

    def __init__(self):
      self.position = [100,
                         100,
                         0,
                         ]

    def draw(self, screen):
      pygame.draw.circle(screen, (255, 0, 0), , self.position], 10)

    def update(self):
      angle = math.radians(10)
      rz = numpy.array(
            [,
             ,
             ,
             ,
             ]
      )
      rx = numpy.array(
            [
                ,
                ,
                ,
                ,
            ]
      )
      position = numpy.array([
            ],
            ],
            ],
            
      ])
      position = rz * position
      self.position = [
            position,
            position,
            position,
      ]


# 颜色常量
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

size = width, height = 800, 600

screen = pygame.display.set_mode(size)

pygame.display.set_caption("title")

clock = pygame.time.Clock()

delay = 60# 延时计时器(1秒)

# 是否全屏
fullscreen = False
screen_change = False

# 背景颜色设定
bg_color = WHITE

running = True

# 3d对象
s3d = Sprites3D()

# ui======

guis = pgui.Group()

m = pgui.Message(group=guis, text=str(s3d.position) + "\n" + str(s3d.position) + "\n" + str(s3d.position))

m.set_pos("center", )

# =========

while running:

    # 设定帧数
    clock.tick(60)

    # 延时计时器刷新
    if delay == 0:
      delay = 60

    delay -= 1

    # 检测是否全屏
    if fullscreen and screen_change:
      screen = pygame.display.set_mode(size, FULLSCREEN, HWSURFACE)
      screen_change = False
    elif screen_change:
      screen = pygame.display.set_mode(size)
      screen_change = False

    # 事件检测
    for event in pygame.event.get():
      if event.type == QUIT:
            pygame.quit()
            sys.exit()

      # 鼠标
      if event.type == MOUSEBUTTONDOWN:
            pass

      # 按键按下事件
      if event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
               
            # F11切换全屏
            if event.key == K_F11:
                fullscreen = not fullscreen
                screen_change = True

      # 按键抬起事件
      if event.type == KEYUP:
            pass

    # 画背景
    screen.fill(bg_color)

    # 刷新xxx
    m.text = str(s3d.position) + "\n" + str(s3d.position) + "\n" + str(int(s3d.position))
    s3d.update()
    guis.update()

    # 画 xxxx
    guis.draw(screen)
    s3d.draw(screen)
   
    # 刷新界面
    pygame.display.update()




@FishC

FishC 发表于 2024-8-20 22:51:34

鱼油你好,看起来你正尝试用 `pygame` 和 `numpy` 实现一个3D旋转矩阵。不过呢,你这个代码还有不少坑,我们得给它填满才行。

首先,我们需要了解如何在三维空间旋转一个点。3D旋转可以通过旋转矩阵来实现,这些矩阵分别用于绕 x, y, z 轴旋转。假设你每次旋转10度,那我们先来给每个旋转轴创建一个矩阵。

1. 绕 z 轴旋转的矩阵:
    rz = numpy.array([
      ,
      ,
      
    ])

2. 绕 x 轴旋转的矩阵:
    rx = numpy.array([
      ,
      ,
      
    ])
   
这些矩阵会帮助我们实现绕不同轴的旋转,现在让我们来填补剩余的代码,并通过这些矩阵来更新位置。

import pygame
import sys
import math
import numpy
from pygame.locals import *

class Sprites3D:
    X, Y, Z = 0, 1, 2

    def __init__(self, x, y, z):
      self.position = numpy.array()

    def draw(self, screen):
      # 将3D坐标简单地转换为2D坐标
      screen_position = ), int(self.position)]
      pygame.draw.circle(screen, (255, 0, 0), screen_position, 10)

    def update(self):
      angle = math.radians(10)

      rz = numpy.array([
            ,
            ,
            
      ])

      rx = numpy.array([
            ,
            ,
            
      ])

      # 先绕Z轴旋转,再绕X轴旋转
      self.position = rz @ self.position
      self.position = rx @ self.position


# ----- Pygame Setup -----
# 颜色常量
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

size = width, height = 800, 600

screen = pygame.display.set_mode(size)
pygame.display.set_caption("3D Rotation")

clock = pygame.time.Clock()

# 3D对象
s3d = Sprites3D(100, 100, 100)

running = True

while running:
    for event in pygame.event.get():
      if event.type == pygame.QUIT:
            running = False

    screen.fill(WHITE)
    s3d.update()
    s3d.draw(screen)
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
sys.exit()

这样,我们现在每帧都以10度的速度先绕 Z 轴再绕 X 轴旋转一个点。赶紧运行看看效果吧。当然,创建3D的视觉效果仅靠 x 和 y 平面上的点画个圆难显神奇,有世界变换和相机同步才是真实的。后续你可以考虑引入更多的3D图形学概念来尝试更复杂的构建!

任何问题随时来问,我随时给你解答哈!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cjjJasonchen 发表于 2024-8-20 22:53:18

已经解决了,是因为numpy数组使用的乘法和矩阵不一样,矩阵乘法要使用dot()

FishC 发表于 2024-8-20 22:54:39

cjjJasonchen 发表于 2024-08-20 22:53
已经解决了,是因为numpy数组使用的乘法和矩阵不一样 ...

聪明的鱼油,原来是这样!用 `dot()` 进行矩阵乘法确实是正确的做法。正好你提到这个问题,下面我简单讲讲如何正确实现一个 3D 旋转矩阵,这样下次遇到类似的问题就不会犯难了。

首先,我们用 `numpy` 实现 3D 旋转矩阵。这里简单介绍一下绕 x、y、z 轴的旋转矩阵:

1. 绕 x 轴旋转的矩阵:
   \[
   R_x(\theta) = \begin{bmatrix}
   1 & 0 & 0 \\
   0 & \cos(\theta) & -\sin(\theta) \\
   0 & \sin(\theta) & \cos(\theta)
   \end{bmatrix}
   \]

2. 绕 y 轴旋转的矩阵:
   \[
   R_y(\theta) = \begin{bmatrix}
   \cos(\theta) & 0 & \sin(\theta) \\
   0 & 1 & 0 \\
   -\sin(\theta) & 0 & \cos(\theta)
   \end{bmatrix}
   \]

3. 绕 z 轴旋转的矩阵:
   \[
   R_z(\theta) = \begin{bmatrix}
   \cos(\theta) & -\sin(\theta) & 0 \\
   \sin(\theta) & \cos(\theta) & 0 \\
   0 & 0 & 1
   \end{bmatrix}
   \]

假设你想同时绕这三个轴进行旋转,你可以通过组合这些旋转矩阵来实现。下面是一个简单的实现:

import numpy as np
import math

def get_rotation_matrix_x(angle):
    """返回绕x轴旋转的矩阵"""
    return np.array([
      ,
      ,
      
    ])

def get_rotation_matrix_y(angle):
    """返回绕y轴旋转的矩阵"""
    return np.array([
      ,
      ,
      [-math.sin(angle), 0, math.cos(angle)]
    ])

def get_rotation_matrix_z(angle):
    """返回绕z轴旋转的矩阵"""
    return np.array([
      ,
      ,
      
    ])

# 测试的角度
angle = math.radians(10)

# 初始位置
position = np.array()

rx = get_rotation_matrix_x(angle)
ry = get_rotation_matrix_y(angle)
rz = get_rotation_matrix_z(angle)

# 将旋转矩阵组合
rotation_matrix = rz.dot(ry).dot(rx)

# 对位置进行旋转变换
rotated_position = rotation_matrix.dot(position)

print("初始位置:", position)
print("旋转后的位置:", rotated_position)

记得在你的 `Sprites3D` 类里面利用这些方法就可以实现你想要的3D旋转效果了,也要记得用 `dot()` 来进行矩阵运算:

# 在你的 Sprites3D 类中的 update 方法中使用
def update(self):
    angle = math.radians(10)# 旋转角度
    rx = get_rotation_matrix_x(angle)
    ry = get_rotation_matrix_y(angle)
    rz = get_rotation_matrix_z(angle)
   
    # 将旋转矩阵组合
    rotation_matrix = rz.dot(ry).dot(rx)
   
    # 对位置进行旋转变换
    position = np.array(, self.position, 0])# 示例3D坐标
    rotated_position = rotation_matrix.dot(position)
   
    self.position = , rotated_position]

这样你的程序应该就能正确地进行3D旋转了!希望这对你有帮助,而且在写代码的过程中还不忘开开玩笑,比如“旋转红点变成了旋转丸子”。继续加油吧,祝你编程愉快!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: numpy旋转3d矩阵