使用vtkCamera显式投影变换矩阵和prop3D可见性

2024-10-06 15:18:57 发布

您现在位置:Python中文网/ 问答频道 /正文

从本质上说,我想使用VTK引擎来渲染一个场景,同时使用预先计算的投影矩阵和模型视图变换矩阵,统称为“复合投影变换矩阵”。你知道吗

为此,我们有vtkCamera.SetUseExplicitProjectionTransformMatrix,但我无法使用它使我的视图道具或演员可见。我猜这与vtkRenderer如何使用边界框预先选择可见的参与者有关,但在本例中,近剪裁范围和远剪裁范围被烘焙到单个矩阵中,因此渲染器甚至无法猜到这一点。在下面的示例代码中,我还补偿了摄影机的初始modelviewtransform矩阵(它是从单位矩阵稍微转换过来的),以便摄影机按照我想要的方式计算其复合投影。你知道吗

import vtk

class Renderer:
    def __init__( self ):
        self.layer0 = vtk.vtkRenderer()
        self.layer0.SetLayer(0)
        self.renWin = vtk.vtkRenderWindow()
        self.renWin.AddRenderer(self.layer0)
        self.iren = vtk.vtkRenderWindowInteractor()
        self.iren.SetRenderWindow(self.renWin)
        self.iren.Initialize()      
    def Render( self ):
        self.iren.Render()
    def AddActor( self, actor ):
        self.layer0.AddActor( actor )
    def Start(self):
        self.iren.Start()

def CreateActor( polydata ):
    mapper = vtk.vtkPolyDataMapper()
    mapper.SetInputData( polydata )
    mapper.SetScalarVisibility( 0 )
    actor = vtk.vtkActor()
    actor.SetMapper( mapper )
    return actor

def OBJReader( name ):
    reader = vtk.vtkOBJReader()
    reader.SetFileName( name )
    reader.Update()
    return reader.GetOutput()

# Suzanne by Blender.org
suzanne = OBJReader( 'D:/data/suzanne.obj' )

size = (900,600)

# Create a VTK renderwindow
r = Renderer()
r.renWin.SetSize(size[0],size[1])
r.AddActor( CreateActor(suzanne) )
# Use vtkRenderWindowInteractor to select the camera view
# Then exit the window by pressing 'x'
r.Start()

# Store the current composite projection transform matrix
# i.e., the product of the projection and the modelview matrix
# into X
c = r.layer0.GetActiveCamera()
n, f = c.GetClippingRange()
aspect = size[0]/size[1]
X = c.GetCompositeProjectionTransformMatrix( aspect, n, f )

# Create another VTK renderwindow
r2 = Renderer()
r2.renWin.SetSize(size[0],size[1])
r2.AddActor( CreateActor(suzanne) )

# but this time, construct the camera by using a precomputed
# projection matrix
c2 = vtk.vtkCamera()
if 1:
    # assert that the modelview matrix will be identity matrix
    M = vtk.vtkMatrix4x4()
    M.DeepCopy( c2.GetModelViewTransformMatrix() )
    print( M ) # its not!
    M.Invert() # so invert
    # and concatenate
    Y = vtk.vtkMatrix4x4()
    # Y*M = X*inv(M)*M = X
    vtk.vtkMatrix4x4.Multiply4x4( X, M, Y )

    c2.SetUseExplicitProjectionTransformMatrix(1)
    c2.SetExplicitProjectionTransformMatrix( Y )

    # these should be now the same (in case of explicit, aspect, n and f are ignored)
    print( c2.GetCompositeProjectionTransformMatrix( 1, 0, 0 ) )
    print( X )


else:
    #this works clearly
    c2.DeepCopy( c )

r2.layer0.SetActiveCamera( c2 )
r2.Render()
r2.Start()

Tags: theselfsizedef矩阵startmatrixactor
2条回答

我不确定我是否理解这个问题,因为代码似乎可以很好地与我的网格。。你知道吗

也许可以尝试添加c.ResetCameraClippingRange()可能有用的地方。你知道吗

还可以考虑使用vtkplotterhelper模块轻松地创建/加载vtk对象。例如:

from vtkplotter import *

vp = Plotter()
suzanne = load('D:/data/suzanne.obj') # returns a vtkActor
print(vp.camera.GetModelViewTransformMatrix())
vp.show(suzanne, resetcam=False)

经过测试,我得出结论,一个人应该使用vtkExternalOpenGLCamera

This class extends vtkOpenGLCamera by introducing API wherein the camera matrices can be set explicitly by the application.

复合投影变换矩阵X虽然不容易使用,但它的裁剪范围必须改变

# copy X into numpy matrix for comfort
P = np.zeros( (4,4),dtype=np.double)
for y in range(4):
    for x in range(4):
        P[y][x]=X.GetElement(y,x)
# P maps valid z-values to [n,f] so change that by
# z <- 2.0 * ( z - n )/(f-n) -1.0
# to fit values into the default clipping range [-1,1]
A = np.eye(4,dtype=np.double)
A[2][3]=-n
B = np.eye(4, dtype=np.double)
B[2][2]=2.0/(f-n)
C = np.eye(4, dtype=np.double)
C[2][3]=-1.0
P = np.matmul(C,np.matmul(B,np.matmul(A,P)) )

# then use vtkExternalOpenGLCamera
c2 = vtk.vtkExternalOpenGLCamera()
c2.SetViewTransformMatrix( np.reshape( np.eye(4,dtype=np.double),[-1,1]) )
c2.SetProjectionTransformMatrix( np.reshape( np.transpose(P),[-1,1]) )
r2.layer0.SetActiveCamera( c2 )
r2.Render()

值得注意的是,下面的矩阵P也适用于上面提到的modelview矩阵变换hack:

c2 = vtk.vtkCamera()

# P is now back to vtk.vtkMatrix4x4 type

# assert that the modelview matrix will be identity matrix
Mx = vtk.vtkMatrix4x4()
Mx.DeepCopy( c2.GetModelViewTransformMatrix() )
print( Mx ) # its not!
Mx.Invert() # so invert
# Y*M = X*inv(M)*M = X
vtk.vtkMatrix4x4.Multiply4x4( P, Mx, P )

c2.SetUseExplicitProjectionTransformMatrix(1)
c2.SetExplicitProjectionTransformMatrix( P )

但结果不太好。。。你知道吗

尽管VTK的默认摄影机灯光模型不适用于烘焙复合变换,但如果将投影矩阵和模型视图矩阵分别放入vtkExternalOpenGLCamera中,则它确实有效。你知道吗

相关问题 更多 >