寻找正常的OpenGL

时间:2011-01-06 13:04:36

标签: opengl

我想知道我们是否可以从窗口坐标获得物体表面的法线。 gluUnProject()函数将窗口坐标转换为3D空间中的对象坐标。同样,我需要一个函数,它给出鼠标指针所在表面的法线。如果我们有一个可以给出这个的opengl函数,我会非常高兴。我不想用光线和物体(表面三角形)的交叉来做这个。

4 个答案:

答案 0 :(得分:2)

我不认为这是可能的。为什么opengl会存储所有像素的所有法线?它不需要它,所以你不太可能检索它。我恐怕不会那么容易。

您可以编写一个着色器,绘制编码为rgb的法线,而不是面部颜色。如果您在着色器上重绘场景,它将绘制所有法线。然后,您可以简单地查找所需的颜色并获得正常颜色。

答案 1 :(得分:1)

首先澄清一下:gluUnProject执行OpenGL固定功能管道的反投影。如果涉及着色器,事情会变得复杂。但是,作为gluUnProject的起点,通常会在所需位置检索深度缓冲区值(使用glReadPixels)。读取整个块(比如一个3x3阵列)的深度值并取消投影它们是微不足道的,留下9个点,其中一个位于中心。使用左边和右边的点会产生一个有效的法线(所以理论上一个2x2阵列就足够了),但让我们通过将整个社区纳入账户来过滤它。

根据他们来自的数组,让我们用这种方式对它们进行编号:

1 8 7
2 0 6
3 4 5

你所要做的就是计算定义三角形(0,1,2),(0,2,3),......(0,7,8),(0,8,1)的平面的法线取(也许加权是样本距离的倒数)法线的总和并归一化得到的矢量。瞧,你已经确定了所选点的世界空间法线。要返回到对象空间,请与对象矩阵的转置逆相乘(为什么转置的逆,井法线由模型视图矩阵的反转置转换,请参阅OpenGL编程指南附录以解释原因,并反向那是......好吧,我想你想出来了。)

答案 2 :(得分:0)

如果你有三点,数学并不难。我建议看看OpenGL超级圣经第4版Macintosh Windows代码示例。共享目录中的math3d。*为您提供了执行此操作的代码,搜索m3dFindNormal。

至于存储法线,这取决于你。

答案 3 :(得分:0)

我有几种方法可以做到这一点。

可能性1

用户点击窗口空间,所以现在你有鼠标点击(x,y)的窗口坐标。现在,在X方向上添加一个像素(x + 1 /宽度,y),在y方向上添加一个像素(x,y + 1 /高度),其中宽度和高度是显示器的像素尺寸。在所有这三个向量上使用gluUnProject,然后在对象空间{A,B,C}中有三个点。在对象空间中有三个点后,正常计算相对简单:

A = ObjectCoordinates(x+1/width, y)
B = ObjectCoordinates(x, y)
C = ObjectCoordinates(x, y+1/height)
BA = (A-B)/|A-B|
BC = (C-B)/|C-B|
N = BA cross BC

其中| X |是向量X的大小 正常是N

这可能不会很快,当A,B和C都没有落在同一个三角形上时会出现问题(如果你点击一个真正很远的物体,就会发生这种情况)。但它应该得到一个很好的近似结果。

可能性2

现在下一个可能性,我不是很确定,但是现在这样。创建片段着色器和顶点着色器。您将不得不创建一个两遍渲染系统。第一遍使用这些新创建的着色器,第二遍实际渲染您的场景。这可能会显着减慢程序执行速度,因为每帧必须进行两次完整的场景渲染。

在第一遍中,顶点着色器会将顶点法线传递给片段着色器。然后,将片段(r,g,b)的颜色指定给从顶点着色器(x,y,z)传入的法线坐标。然后,您的第一个渲染将使用这些着色器渲染到纹理。您的第二遍将渲染到帧缓冲区。当用户单击时,您将获得一组窗口空间坐标,您可以将这些坐标转换为(u,v)纹理坐标,以便从第一次渲染渲染创建的纹理中进行采样。

同样,此解决方案会明显变慢,但根据您使用的纹理大小,它很可能会为您提供更准确的数据。

Here是一本关于GLSL OpenGL着色语言的略显过时但免费的书,它描述了如何将这些着色器组合在一起。

Here是一个关于加载和编译着色器的教程。

Here是用于计算法线的伪代码。

干杯, 奈德