查看: 6406|回复: 19

如何用Shader得到物体的世界坐标

[复制链接]

该用户从未签到

发表于 2008-5-27 12:51:09 | 显示全部楼层 |阅读模式
最近群里面有个朋友问我关于如何得到OpenGL世界坐标的问题,当时我还弄错了,误以为gl_ModelViewMatrix*gl_Vertex就是世界坐标。因最近也突然遇到了世界坐标的问题,所以花了一些时间来研究这个问题,网上也有人问,但或许没有答案,或许是错的。
其实,OpenGL的转换管道直接将gl_Vertex,也就是物体坐标,用gl_ModelViewMatrix相乘,得到的是眼坐标。如果将gl_ModelViewMatirx拆分为gl_ModelMatrix和gl_ViewMatrix,那么问题就好解决了。但事实上没有提供。要清楚OpenGL其实没有世界坐标系,世界坐标系是应用程序的概念。其实可以将OpenGL的摄像机看作是固定的,其坐标系就是眼坐标系,移动摄像机和移动物体的位置是一个相反的转换,对于观察者来说根本不知道是摄像机在动,还是物体在动(想想大卫的大变自由女神像的魔术吧,呵呵)
说回来,最终的变换是这样的:
eyePos=viewMatrix * modelMatrix * modelVertex
在OpenGL里面viewMatrix和modelMatrix合并了,因为OpenGL里面并没有设置摄像机的参数,所以OpenGL并不知道viewMatrix到底是什么。viewMatrix是用户自己定义的,所以如果能够得到这个viewMatrix并能得到其逆矩阵,就可以得到worldPos:
worldPos=viewMatrixInv * viewMatrix * modelMatrix * modelVertex
传统的OpenGL程序里面,你得自己计算这个viewMatrixInv,还好OSG的Camera提供了一个getViewMatrixInverse()方法,通过这个方法我们就可以轻松的获得viewMatrixInv,然后传递给Vertex Shader(用一个Uniform就可以),然后进行这个计算就可以了。
记得每一帧都需要Update这个viewMatrixInv,只需要一个updateCallBack就可以了。
好了,看几个图,我用3DSMAX创建了两个盒子,为了便于观察,模型的顶点值限制在0-1之间,然后用osgExp导出,没有选中Flatten Static Transform这样就不会把模型定点转换成世界坐标系的顶点。
源代码中可以改变gl_FragColor=的值来修改为相应的坐标系的值显示。
世界坐标系的最终输出,可见颜色连续变换的。
眼坐标系的图,可见屏幕中间偏左的部分是黑的。因为其值是负的。平移拖动盒子可见相应像素着色不变。
物体坐标系的图,可见两个盒子的颜色一样,因为其值是相同的。

源代码也附后,可以运行着看看,虽然程序简单,但用到的时候再也不用苦苦思考了,呵呵。

世界坐标系

世界坐标系

眼坐标系

眼坐标系

物体本地坐标系

物体本地坐标系

RenderWorldCoordinate.tar

50 KB, 下载次数: 490, 下载积分: 威望 1

源代码

该用户从未签到

发表于 2008-6-12 08:31:47 | 显示全部楼层

该用户从未签到

发表于 2008-6-12 09:12:11 | 显示全部楼层
好帖,学习了~~~

该用户从未签到

发表于 2008-7-1 21:17:55 | 显示全部楼层
谢谢

该用户从未签到

发表于 2008-8-1 12:38:52 | 显示全部楼层
定定

该用户从未签到

发表于 2009-9-4 10:50:45 | 显示全部楼层
谢谢,收藏了……

该用户从未签到

发表于 2010-9-8 10:51:10 | 显示全部楼层
对lz提出一点质疑,呵呵~

看了顶点着色器,部分代码如下
  1. gl_Position=ftransform();
  2. eyePos=gl_Position;                //眼坐标
复制代码
可以肯定eyePos(gl_Position)不是眼睛空间下的物体坐标,而是眼睛空间下的物体在摄像机平面投影坐标
  1. gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
复制代码
把摄像机认为固定点,而把物体变换到摄像机所在的世界坐标系下,应该是
  1. eyePos = gl_ModelViewMatrix * gl_Vertex;
复制代码
诚如lz所说,OpenGL模型观察矩阵是同一个矩阵,对摄像机或物体的变换,都被右乘到同一个矩阵。所以,对摄像机与物体的变换本质是一样的。而物体在世界坐标系(摄像机所在的世界坐标系)的坐标就是lz“误认为”的
  1. gl_ModelViewMatrix*gl_Vertex
复制代码

该用户从未签到

发表于 2010-9-8 12:41:22 | 显示全部楼层
OpenGL的转换管道直接将gl_Vertex,也就是物体坐标,用gl_ModelViewMatrix相乘,得到的是眼坐标
楼主的意思我想并没有错,他用的并不是gl_ModelViewProjectionMatrix,而是gl_ModelViewMatrix。

不过楼上的分析也值得一读,呵呵

该用户从未签到

发表于 2010-9-8 13:57:57 | 显示全部楼层
呵呵,也许是吧~

但是我看到顶点着色器中的代码就是那样的啊?

楼主的意思可能是,摄像机本身有变换矩阵,物体也有变换矩阵。物体的“世界坐标”是指物体经过物体的变换矩阵作用后的坐标,而与摄像机的变换矩阵没关系。

该用户从未签到

发表于 2010-9-8 14:53:09 | 显示全部楼层
物体的世界坐标其实就是
  1. gl_ModelMatrix * gl_Vertex
复制代码
但是这里的gl_ModelMatrix可能是不存在的,因为OpenGL只定义了一个统一的ModelView矩阵。如果我们能在GLSL中得到相机观察矩阵的逆矩阵viewMatrixInv,那么求取世界坐标就变得可能了,即:
  1. viewMatrixInv * gl_ModelViewMatrix * gl_Vertex
复制代码
楼主应该是在讲解如何得到这个viewMatrixInv,当然具体的代码我并没有细看~~

该用户从未签到

发表于 2010-9-8 15:45:04 | 显示全部楼层
呵呵,是的。估计楼主就是这个意思,只是
  1. gl_Position=ftransform();
  2. eyePos=gl_Position;                //眼坐标
复制代码
比较坐标时有点问题

gl_ModelMatrix还真没有

该用户从未签到

发表于 2010-9-10 23:16:39 | 显示全部楼层
唉,这个问题也需要讨论吗?  ModelMatrix和ViewMatrix根本就是一回事,只是为了思考问题时方便才人为的加以区分的,本就是一回事。凡是ViewMatrix做得到ModelMatrix也做得到。

该用户从未签到

发表于 2010-9-10 23:41:08 | 显示全部楼层
要在Shader中得到物体的世界坐标其实很简单,在应用程序中计算好相机的ViewMatrix,然后求逆。将这个矩阵,比如起名叫InverseViewMatrix,传给shader。
在shader中:gl_ModelViewMatrix = gl_ViewMatrix  *  gl_ModelMatrix ;
在等式左右两边同乘以InverseViewMatrix
InverseViewMatrix * gl_ModelViewMatrix = InverseViewMatrix * gl_ViewMatrix  *  gl_ModelMatrix ;
得到:
InverseViewMatrix  * gl_ModelViewMatrix = gl_ModelMatrix;
在上边的等式中InverseViewMatrix 在应用程序中已经计算得到了,gl_ModelViewMatrix ,在shader中自带。
这样就得到了gl_ModelMatrix;
物体的世界坐标WorldPos = gl_ModelMatrix * gl_Vertex ;

高手可能发现为什么不直接在应用程序中计算gl_ModelMatrix,那是因为场景中物体很多,每个物体都有不同的gl_ModelMatrix,而摄像机的数量相对较少,InverseViewMatrix 也就较少,可以减少计算量。

该用户从未签到

发表于 2010-9-12 22:47:37 | 显示全部楼层
楼上的方法和楼主事实上一致。我个人认为这个问题还是很值得讨论的,在我了解来看,国内有相当一部分初学的开发者和爱好者并不十分理解坐标系和坐标系间转换的概念,如果能通过讨论和资源整理来帮助大家理清思路的话,显然大有裨益——

该用户从未签到

发表于 2010-9-13 11:19:36 | 显示全部楼层
这类问题需要开发者有较好的线性代数基础,还需要良好的空间想象力。确实很多长时间使用OpenGL的人都会犯迷糊。
个人觉得学习下纯软件渲染会很好的解决这个问题,以及与之相关的问题。

该用户从未签到

发表于 2010-9-13 16:26:07 | 显示全部楼层
楼上所谓纯软件渲染是指用GLSL代替固定管道渲染么?

该用户从未签到

发表于 2010-9-13 16:58:59 | 显示全部楼层
不是,指的是用自己的代码代替OpenGL。传统计算机图形学都会有这方面的知识。
比如CS里的software模式就是用的纯软件渲染方式。
一句话就是自己实现OpenGL的功能,用自己的方式,自己的函数,当然可以参考OpenGL的构架、处理管线。

该用户从未签到

发表于 2010-9-13 17:01:48 | 显示全部楼层
如果自己实现一遍图形处理管线的话,就不会在这些问题上犯迷糊了。

该用户从未签到

发表于 2010-9-13 17:38:26 | 显示全部楼层
GLSL也是自己实现图形处理管线的~~
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表