注释
我正在手动进行 3D 渲染(不使用任何 3d 库)并且 python 在这方面不是很快。 |
这是有原因的吗?我想有针对 python 的经过良好测试的 OpenGL 绑定,或者类似的东西…… |
是的,bCNC 没有使用 OpenGL,它使用了最少的外部依赖。 |
我知道,但这有合理的理由吗?这种“不是在这里发明”的方法并不总是那么明智。特别是当它不仅缺乏基本的旋转功能,而且你显然会遇到性能问题(超时渲染)等…… 顺便说一句,我已经为大约一百个程序制作了 linux 包,所以我知道外部依赖项是多么烦人。但有时使用少量外部库是有意义的。特别是当它们广泛流行并且已经打包时。这是关于某种平衡。你不想要 100 个外部库的依赖地狱,但是使用像 opengl 这样常见的东西进行 3d 渲染是有道理的…… |
如果您能帮助将 OpenGL 添加为渲染,我将非常高兴。 |
你知道哪些方法需要移植到OpenGL吗? |
只是偶然发现了这个:https |
在我看来,Tkinter 是编写 GL 应用程序的糟糕选择。我们必须重新发明一些基础知识才能让它发挥作用。 |
基本上,在不放弃 Tkinter 的情况下拥有 OpenGL 的唯一方法是使用一些有 10 年历史的名为 Togl 的库,这是 b*tch 来安装和分发。这样的皮塔饼。 http://pyopengl.sourceforge.net/pydoc/OpenGL.Tk.html说:
|
https://stackoverflow.com/questions/8584272/using-pygame-features-in-tkinter import Tkinter as tk
import os
w, h = 500, 200
# Add a couple widgets. We're going to put pygame in `embed`.
root = tk.Tk()
embed = tk.Frame(root, width=w, height=h)
embed.pack()
text = tk.Button(root, text='Blah.')
text.pack()
# Tell pygame's SDL window which window ID to use
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
# The wxPython wiki says you might need the following line on Windows
# (http://wiki.wxpython.org/IntegratingPyGame).
#os.environ['SDL_VIDEODRIVER'] = 'windib'
# Show the window so it's assigned an ID.
root.update()
# Usual pygame initialization
import pygame as pg
pg.display.init()
screen = pg.display.set_mode((w,h))
pos = 0
while 1:
# Do some pygame stuff
screen.fill(pg.Color(0,0,0))
pos = (pos + 1) % screen.get_width()
pg.draw.circle(screen, pg.Color(255,255,255), (pos,100), 30)
# Update the pygame display
pg.display.flip()
# Update the Tk display
root.update()
|
这使用鼠标进行实时 tkinter 画布旋转,在我看来似乎并不太慢: https://github.com/ActiveState/code/tree/master/recipes/Python/578876_Rotatable_Tetrahedron #!/usr/bin/env python
# coding: UTF-8
#
## @package _12_tet
#
# Draws a 3D tetrahedron and allows a user to rotate it
# (mouse left button and wheel).
#
# The Tetrahedron is represented by a 3 x 4 matrix.
# Each column represents a 3D vertex.
#
# note: a m x n matrix is represented by a list of lines:
# [[l_1] [l_2] .. [l_m]].
# m = len(mat), n = len(mat[0]), mat(i,j) = mat[i][j]
#
# @author Paulo Roma
# @since 01/05/2014
# @see http://www.orimosenzon.com/wiki/index.php/Python_samples
# @see http://mathworld.wolfram.com/RotationMatrix.html
try:
from tkinter import * # python 3
except ImportError:
from Tkinter import * # python 2
from math import *
def createZeroMat(m,n):
"""Return a matrix (m x n) filled with zeros."""
ret = [0] * m
for i in range(m):
ret[i] = [0] * n
return ret
def matMul(mat1, mat2):
"""Return mat1 x mat2 (mat1 multiplied by mat2)."""
m = len(mat1)
n = len(mat2[0])
common = len(mat2)
ret = createZeroMat(m,n)
if len(mat1[0]) == len(mat2):
for i in range(m):
for j in range(n):
for k in range(common):
ret[i][j] += mat1[i][k] * mat2[k][j]
return ret
def matTrans(mat):
"""Return mat (n x m) transposed (m x n)."""
m = len(mat[0])
n = len(mat)
ret = createZeroMat(m,n)
for i in range(m):
for j in range(n):
ret[i][j] = mat[j][i]
return ret
def translate(x,y,dx,dy):
"""Translate vector(x,y) by (dx,dy)."""
return x+dx, y+dy
def drawTet(tet,col):
"""Draw a tetrahedron."""
w = canvas.winfo_width()/2
h = canvas.winfo_height()/2
canvas.delete(ALL) # delete all edges
nv = len(tet[0]) # number of vertices in tet (4)
# draw the 6 edges of the tetrahedron
for p1 in range(nv):
for p2 in range(p1+1,nv):
canvas.create_line(translate(tet[0][p1], tet[1][p1], w, h),
translate(tet[0][p2], tet[1][p2], w, h), fill = col)
def init():
"""Initialize global variables."""
global ROT_X, ROT_Y, ROT_Z
global eps, EPS, tet
global lastX, lastY, tetColor, bgColor
tet = matTrans([[0,-100,0],[-100,100,0],[100,100,0],[0,0,200]])
# counter-clockwise rotation about the X axis
ROT_X = lambda x: matTrans([[1,0,0], [0,cos(x),-sin(x)], [0,sin(x),cos(x)] ])
# counter-clockwise rotation about the Y axis
ROT_Y = lambda y: matTrans([[cos(y),0,sin(y)], [0,1,0], [-sin(y),0,cos(y)]])
# counter-clockwise rotation about the Z axis
ROT_Z = lambda z: matTrans([[cos(z),sin(z),0], [-sin(z),cos(z),0], [0,0,1]])
eps = lambda d: pi/300 if (d>0) else -pi/300
EPS = lambda d: d*pi/300
lastX = 0
lastY = 0
tetColor = 'black'
bgColor = 'white'
def cbClicked(event):
"""Save current mouse position."""
global lastX, lastY
lastX = event.x
lastY = event.y
def cbMottion(event):
"""Map mouse displacements in Y direction to rotations about X axis,
and mouse displacements in X direction to rotations about Y axis."""
global tet
# Y coordinate is upside down
dx = lastY - event.y
tet = matMul(ROT_X(EPS(-dx)),tet)
dy = lastX - event.x
tet = matMul(ROT_Y(EPS(dy)),tet)
drawTet(tet,tetColor)
cbClicked(event)
def wheelUp(event):
"""Map mouse wheel up displacements to rotations about Z axis."""
global tet
tet = matMul(ROT_Z(EPS(1)),tet)
drawTet(tet,tetColor)
def wheelDown(event):
"""Map mouse wheel down displacements to rotations about Z axis."""
global tet
tet = matMul(ROT_Z(EPS(-1)),tet)
drawTet(tet,tetColor)
def wheel(event):
"""Map mouse wheel displacements to rotations about Z axis."""
global tet
tet = matMul(ROT_Z(EPS(event.delta/120)),tet)
drawTet(tet,tetColor)
def resize(event):
"""Redraw the tetrahedron, in case of a window change due to user resizing it."""
drawTet(tet,tetColor)
def main():
global canvas
root = Tk()
root.title('Tetrahedron')
root.geometry('+0+0')
init()
canvas = Canvas(root, width=400, height=400, background=bgColor)
canvas.pack(fill=BOTH,expand=YES)
canvas.bind("<Button-1>", cbClicked)
canvas.bind("<B1-Motion>", cbMottion)
canvas.bind("<Configure>", resize)
from platform import uname
os = uname()[0]
if ( os == "Linux" ):
canvas.bind('<Button-4>', wheelUp) # X11
canvas.bind('<Button-5>', wheelDown)
elif ( os == "Darwin" ):
canvas.bind('<MouseWheel>', wheel) # MacOS
else:
canvas.bind_all('<MouseWheel>', wheel) # windows
drawTet(tet,tetColor)
mainloop()
if __name__=='__main__':
sys.exit(main())
|
刚刚尝试向该代码添加更多 3D 线。在处理 10000 条 3D 线时,它似乎相当快,我会说它运行多达 3000 条线时几乎可以平稳运行。但是仍然……没有办法获得抗锯齿:-( |
另一种解决方案可能是将 bCNC 重写为 GTK3 (PyGTK) 或 wxWidgets (wxPython),它们比 Tkinter 更新并且与 OpenGL 没有问题。但这至少是劳动密集型的。 |
看起来很有前途!! |
能够通过鼠标拖动自由旋转 3D 视图真的很有用。预定义的 ISO1-3 视图有点做这个工作,但它有助于查看轻微移动的对象,以便更快地掌握它们的形状。