不变尺度几何
Invariant scale geometry
我正在编写一个网格编辑器,我在其中使用操纵器更改网格的顶点。任务是渲染具有恒定尺寸的操纵器,这些尺寸在更改相机和视口参数时不会改变。投影矩阵是透视的。对于如何实现不变比例几何的想法,我将不胜感激。
如果我没看错,您想渲染一些标记(例如顶点拖动编辑区域),对于它们渲染到的任何深度都具有相同的视觉大小。
有两种方法:
随深度缩放
计算相机视图的垂直距离(简单的点积)并缩放标记大小,使其具有相同的视觉大小不变的深度。
所以如果P0
是你的相机位置,Z
是你的相机视角方向单位向量(通常是Z轴)。然后对于任何位置 P
像这样计算比例:
depth = dot(P-P0,Z)
现在,比例取决于在某些指定 depth0
处想要的视觉效果 size0
。现在使用我们想要的三角形相似度:
size/dept = size0/depth0
size = size0*depth/depth0
所以用 size
或比例 depth/depth0
渲染你的标记。如果使用缩放,你需要围绕你的目标位置缩放 P
否则你的标记会移动到两侧(所以平移,缩放,平移回来)。
计算屏幕位置并使用非透视渲染
因此,您以与图形管道相同的方式转换目标坐标,直到获得屏幕 x,y
位置。记住它,并且通过这将使您的标记只使用它而不是真实位置。对于此渲染过程,要么使用一些恒定深度(与相机的距离),要么使用非透视图矩阵。
有关详细信息,请参阅
[Edit1] 像素大小
您需要为此使用 FOVx,FOVy
投影角度和 view/screen 分辨率 (xs,ys)。这意味着如果深度为 znear
且坐标为角度的一半,则投影坐标将转到屏幕边缘:
tan(FOVx/2) = (xs/2)*pixelx/znear
tan(FOVy/2) = (ys/2)*pixely/znear
---------------------------------
pixelx = 2*znear*tan(FOVx/2)/xs
pixely = 2*znear*tan(FOVy/2)/ys
其中 pixelx,pixely
是表示深度 znear
处视觉上单个像素的大小(每轴)。如果展位大小相同(因此像素是正方形),您便拥有了所需的一切。如果它们不相等(像素不是正方形),那么您需要在屏幕轴对齐坐标中渲染标记,因此方法 #2 更适合这种情况。
因此,如果您选择 depth0=znear
,那么您可以将 size0
设置为 n*pixelx
and/or n*pixely
以获得 n
的视觉大小像素。或者使用任何 dept0
并将计算重写为:
pixelx = 2*depth0*tan(FOVx/2)/xs
pixely = 2*depth0*tan(FOVy/2)/ys
补充一下:
size0x = size_in_pixels*(2*depth0*tan(FOVx/2)/xs)
size0y = size_in_pixels*(2*depth0*tan(FOVy/2)/ys)
-------------------------------------------------
sizex = size_in_pixels*(2*depth0*tan(FOVx/2)/xs)*(depth/depth0)
sizey = size_in_pixels*(2*depth0*tan(FOVy/2)/ys)*(depth/depth0)
---------------------------------------------------------------
sizex = size_in_pixels*(2*tan(FOVx/2)/xs)*(depth)
sizey = size_in_pixels*(2*tan(FOVy/2)/ys)*(depth)
---------------------------------------------------------------
sizex = size_in_pixels*2*depth*tan(FOVx/2)/xs
sizey = size_in_pixels*2*depth*tan(FOVy/2)/ys
我正在编写一个网格编辑器,我在其中使用操纵器更改网格的顶点。任务是渲染具有恒定尺寸的操纵器,这些尺寸在更改相机和视口参数时不会改变。投影矩阵是透视的。对于如何实现不变比例几何的想法,我将不胜感激。
如果我没看错,您想渲染一些标记(例如顶点拖动编辑区域),对于它们渲染到的任何深度都具有相同的视觉大小。
有两种方法:
随深度缩放
计算相机视图的垂直距离(简单的点积)并缩放标记大小,使其具有相同的视觉大小不变的深度。
所以如果
P0
是你的相机位置,Z
是你的相机视角方向单位向量(通常是Z轴)。然后对于任何位置P
像这样计算比例:depth = dot(P-P0,Z)
现在,比例取决于在某些指定
depth0
处想要的视觉效果size0
。现在使用我们想要的三角形相似度:size/dept = size0/depth0 size = size0*depth/depth0
所以用
size
或比例depth/depth0
渲染你的标记。如果使用缩放,你需要围绕你的目标位置缩放P
否则你的标记会移动到两侧(所以平移,缩放,平移回来)。计算屏幕位置并使用非透视渲染
因此,您以与图形管道相同的方式转换目标坐标,直到获得屏幕
x,y
位置。记住它,并且通过这将使您的标记只使用它而不是真实位置。对于此渲染过程,要么使用一些恒定深度(与相机的距离),要么使用非透视图矩阵。
有关详细信息,请参阅
[Edit1] 像素大小
您需要为此使用 FOVx,FOVy
投影角度和 view/screen 分辨率 (xs,ys)。这意味着如果深度为 znear
且坐标为角度的一半,则投影坐标将转到屏幕边缘:
tan(FOVx/2) = (xs/2)*pixelx/znear
tan(FOVy/2) = (ys/2)*pixely/znear
---------------------------------
pixelx = 2*znear*tan(FOVx/2)/xs
pixely = 2*znear*tan(FOVy/2)/ys
其中 pixelx,pixely
是表示深度 znear
处视觉上单个像素的大小(每轴)。如果展位大小相同(因此像素是正方形),您便拥有了所需的一切。如果它们不相等(像素不是正方形),那么您需要在屏幕轴对齐坐标中渲染标记,因此方法 #2 更适合这种情况。
因此,如果您选择 depth0=znear
,那么您可以将 size0
设置为 n*pixelx
and/or n*pixely
以获得 n
的视觉大小像素。或者使用任何 dept0
并将计算重写为:
pixelx = 2*depth0*tan(FOVx/2)/xs
pixely = 2*depth0*tan(FOVy/2)/ys
补充一下:
size0x = size_in_pixels*(2*depth0*tan(FOVx/2)/xs)
size0y = size_in_pixels*(2*depth0*tan(FOVy/2)/ys)
-------------------------------------------------
sizex = size_in_pixels*(2*depth0*tan(FOVx/2)/xs)*(depth/depth0)
sizey = size_in_pixels*(2*depth0*tan(FOVy/2)/ys)*(depth/depth0)
---------------------------------------------------------------
sizex = size_in_pixels*(2*tan(FOVx/2)/xs)*(depth)
sizey = size_in_pixels*(2*tan(FOVy/2)/ys)*(depth)
---------------------------------------------------------------
sizex = size_in_pixels*2*depth*tan(FOVx/2)/xs
sizey = size_in_pixels*2*depth*tan(FOVy/2)/ys