鱼C论坛

 找回密码
 立即注册
查看: 591|回复: 3

numpy旋转3d矩阵

[复制链接]
发表于 2024-8-20 22:50:10 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

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

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

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

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

  4. import pygame
  5. import sys
  6. import math
  7. import numpy
  8. import pygameGUI as pgui
  9. from typing import List
  10. from pygame.locals import *


  11. class Sprites3D:
  12.     X, Y, Z = 0, 1, 2

  13.     def __init__(self):
  14.         self.position = [100,
  15.                          100,
  16.                          0,
  17.                          ]

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

  20.     def update(self):
  21.         angle = math.radians(10)
  22.         rz = numpy.array(
  23.             [[math.cos(angle), - math.sin(angle), 0, 0],
  24.              [math.sin(angle), math.cos(angle), 0, 0],
  25.              [0, 0, 1, 0],
  26.              [0, 0, 0, 1],
  27.              ]
  28.         )
  29.         rx = numpy.array(
  30.             [
  31.                 [1, 0, 0, 0],
  32.                 [0, math.cos(angle), -math.sin(angle), 0],
  33.                 [0, math.sin(angle), -math.sin(angle), 0],
  34.                 [0, 0, 0, 1],
  35.             ]
  36.         )
  37.         position = numpy.array([
  38.             [self.position[0]],
  39.             [self.position[1]],
  40.             [self.position[2]],
  41.             [1]
  42.         ])
  43.         position = rz * position
  44.         self.position = [
  45.             position[0][0],
  46.             position[1][0],
  47.             position[2][0],
  48.         ]


  49. # 颜色常量
  50. WHITE = (255, 255, 255)
  51. BLACK = (0, 0, 0)

  52. size = width, height = 800, 600

  53. screen = pygame.display.set_mode(size)

  54. pygame.display.set_caption("title")

  55. clock = pygame.time.Clock()

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

  57. # 是否全屏
  58. fullscreen = False
  59. screen_change = False

  60. # 背景颜色设定
  61. bg_color = WHITE

  62. running = True

  63. # 3d对象
  64. s3d = Sprites3D()

  65. # ui======

  66. guis = pgui.Group()

  67. m = pgui.Message(group=guis, text=str(s3d.position[0]) + "\n" + str(s3d.position[1]) + "\n" + str(s3d.position[2]))

  68. m.set_pos("center", [400, 200])

  69. # =========

  70. while running:

  71.     # 设定帧数
  72.     clock.tick(60)

  73.     # 延时计时器刷新
  74.     if delay == 0:
  75.         delay = 60

  76.     delay -= 1

  77.     # 检测是否全屏
  78.     if fullscreen and screen_change:
  79.         screen = pygame.display.set_mode(size, FULLSCREEN, HWSURFACE)
  80.         screen_change = False
  81.     elif screen_change:
  82.         screen = pygame.display.set_mode(size)
  83.         screen_change = False

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

  89.         # 鼠标
  90.         if event.type == MOUSEBUTTONDOWN:
  91.             pass

  92.         # 按键按下事件
  93.         if event.type == KEYDOWN:
  94.             if event.key == K_ESCAPE:
  95.                 pygame.quit()
  96.                 sys.exit()
  97.                
  98.             # F11切换全屏
  99.             if event.key == K_F11:
  100.                 fullscreen = not fullscreen
  101.                 screen_change = True

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

  105.     # 画背景
  106.     screen.fill(bg_color)

  107.     # 刷新xxx
  108.     m.text = str(s3d.position[0]) + "\n" + str(s3d.position[1]) + "\n" + str(int(s3d.position[2]))
  109.     s3d.update()
  110.     guis.update()

  111.     # 画 xxxx
  112.     guis.draw(screen)
  113.     s3d.draw(screen)
  114.    
  115.     # 刷新界面
  116.     pygame.display.update()


复制代码


@FishC
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-8-20 22:51:34 | 显示全部楼层
鱼油你好,看起来你正尝试用 `pygame` 和 `numpy` 实现一个3D旋转矩阵。不过呢,你这个代码还有不少坑,我们得给它填满才行。

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

1. 绕 z 轴旋转的矩阵:
   
  1. rz = numpy.array([
  2.         [math.cos(angle), -math.sin(angle), 0],
  3.         [math.sin(angle),  math.cos(angle), 0],
  4.         [0,               0,              1]
  5.     ])
复制代码


2. 绕 x 轴旋转的矩阵:
   
  1. rx = numpy.array([
  2.         [1,              0,               0],
  3.         [0, math.cos(angle), -math.sin(angle)],
  4.         [0, math.sin(angle),  math.cos(angle)]
  5.     ])
复制代码

   
这些矩阵会帮助我们实现绕不同轴的旋转,现在让我们来填补剩余的代码,并通过这些矩阵来更新位置。

  1. import pygame
  2. import sys
  3. import math
  4. import numpy
  5. from pygame.locals import *

  6. class Sprites3D:
  7.     X, Y, Z = 0, 1, 2

  8.     def __init__(self, x, y, z):
  9.         self.position = numpy.array([x, y, z])

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

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

  16.         rz = numpy.array([
  17.             [math.cos(angle), -math.sin(angle), 0],
  18.             [math.sin(angle),  math.cos(angle), 0],
  19.             [0,               0,               1]
  20.         ])

  21.         rx = numpy.array([
  22.             [1,              0,               0],
  23.             [0, math.cos(angle), -math.sin(angle)],
  24.             [0, math.sin(angle),  math.cos(angle)]
  25.         ])

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


  29. # ----- Pygame Setup -----
  30. # 颜色常量
  31. WHITE = (255, 255, 255)
  32. BLACK = (0, 0, 0)

  33. size = width, height = 800, 600

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

  36. clock = pygame.time.Clock()

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

  39. running = True

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

  44.     screen.fill(WHITE)
  45.     s3d.update()
  46.     s3d.draw(screen)
  47.     pygame.display.flip()
  48.     clock.tick(60)

  49. pygame.quit()
  50. sys.exit()
复制代码


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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-8-20 22:53:18 | 显示全部楼层
已经解决了,是因为numpy数组使用的乘法和矩阵不一样,矩阵乘法要使用dot()
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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}
   \]

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

  1. import numpy as np
  2. import math

  3. def get_rotation_matrix_x(angle):
  4.     """返回绕x轴旋转的矩阵"""
  5.     return np.array([
  6.         [1, 0, 0],
  7.         [0, math.cos(angle), -math.sin(angle)],
  8.         [0, math.sin(angle), math.cos(angle)]
  9.     ])

  10. def get_rotation_matrix_y(angle):
  11.     """返回绕y轴旋转的矩阵"""
  12.     return np.array([
  13.         [math.cos(angle), 0, math.sin(angle)],
  14.         [0, 1, 0],
  15.         [-math.sin(angle), 0, math.cos(angle)]
  16.     ])

  17. def get_rotation_matrix_z(angle):
  18.     """返回绕z轴旋转的矩阵"""
  19.     return np.array([
  20.         [math.cos(angle), -math.sin(angle), 0],
  21.         [math.sin(angle), math.cos(angle), 0],
  22.         [0, 0, 1]
  23.     ])

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

  26. # 初始位置
  27. position = np.array([100, 100, 100])

  28. rx = get_rotation_matrix_x(angle)
  29. ry = get_rotation_matrix_y(angle)
  30. rz = get_rotation_matrix_z(angle)

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

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

  35. print("初始位置:", position)
  36. print("旋转后的位置:", rotated_position)
复制代码


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

  1. # 在你的 Sprites3D 类中的 update 方法中使用
  2. def update(self):
  3.     angle = math.radians(10)  # 旋转角度
  4.     rx = get_rotation_matrix_x(angle)
  5.     ry = get_rotation_matrix_y(angle)
  6.     rz = get_rotation_matrix_z(angle)
  7.    
  8.     # 将旋转矩阵组合
  9.     rotation_matrix = rz.dot(ry).dot(rx)
  10.    
  11.     # 对位置进行旋转变换
  12.     position = np.array([self.position[0], self.position[1], 0])  # 示例3D坐标
  13.     rotated_position = rotation_matrix.dot(position)
  14.    
  15.     self.position = [rotated_position[0], rotated_position[1]]
复制代码


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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-5-11 18:30

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表