在opengl中从模型中获取可见的XYZ坐标和法线
Acquire visible XYZ-coordinates and normals from model in opengl
我正在屏幕上呈现一个对象。我需要在顶点着色器中为每个像素计算的可见XYZ坐标和法线,以便进行进一步计算。
有可能获得这些价值吗?
我能想到的最接近的是使用屏幕外渲染(如何在OpenGL上渲染屏幕外?)来分别渲染每个坐标(我必须渲染6次,效率不高)。为此,我必须将浮点值拆分为字节值。有可能使用类似的东西吗
(value & 0x0000FF00) >> 8)
在顶点着色器中?
编辑:我的问题不清楚。
附加信息:我想检索每个像素的XYZ世界坐标和相应的法线,例如。(例如X=-0.2,Y=0.5,Z=1.3;NX=-0.1,NY=0.8,NZ=0.1)
到目前为止,我的管道与"鲍里斯"在回答中发布的内容非常相似。
您要做的是渲染到所谓的几何缓冲区。这是延迟渲染中的一个常见步骤,因此我强烈建议您查看DR教程,看看它是如何完成的。谷歌发现了很多,但这一条出现在opengl.org的新闻部分:http://ogldev.atspace.co.uk/www/tutorial35/tutorial35.html
为了在CPU上选择信息,您确实必须使用帧缓冲区对象(FBO)在纹理上渲染。通过使用多个GL_COLOR_ATTACHMENTi
,可以将多个纹理图像附加到单个FBO,并在片段着色器中同时绘制。这被称为多重渲染目标(MRT)。根据datenwolf和维基百科的说法,一个典型的用途似乎是延迟着色(我个人从未这样做过,但我做了MRT,用于GPU选择)。
顶点着色器:
首先,需要将信息从顶点着色器传递到片段着色器。
#version 330
uniform mat4 pvmMatrix;
in vec3 position;
in vec3 normal;
out vec3 fragPosition;
out vec3 fragNormal;
void main()
{
fragPosition = position;
fragNormal = normal;
gl_Position = pvmMatrix * vec4(position, 1.0);
}
片段着色器
然后,可以通过指定不同的输出在片段着色器中渲染此信息。
#version 330
in vec3 fragPosition;
in vec3 fragNormal;
layout(location=0)out vec3 mrtPosition;
layout(location=1)out vec3 mrtNormal;
void main()
{
mrtPosition = fragPosition;
mrtNormal = fragNormal;
}
layout(location=0)
指定渲染目标将是GL_COLOR_ATTACHMENT0
(location=1
用于GL_COLOR_ATTACHMENT1
,依此类推)。变量的名称无关紧要。
创建FBO
在C++代码中,您必须设置一个具有多个渲染目标的FBO。为了简洁起见,我不会给出任何FBO的常见之处,请使用第一个链接。这里重要的是:
生成多个纹理:
// The texture for the position
GLuint texPosition;
glGenTextures(1, &texPosition);
glBindTexture(GL_TEXTURE_2D, texPosition);
// [...] do the glTexParameterf(...) that suits your needs
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGB32F, // this should match your fragment shader output.
// I used vec3, hence a 3-componont 32bits float
// You can use something else for different information
viewportWidth, viewportHeight, 0,
GL_RGB, GL_FLOAT, // Again, this should match
0);
// the texture for the normal
GLuint texNormal;
glGenTextures(1, &texNormal);
// [...] same as above
注意如何使用不同的数据类型来存储要存储在纹理上的信息。这里,我在片段着色器中使用了vec3
,因此我必须使用GL_RGB32F
来创建纹理。在这里查看您可以使用的类型的详尽列表(例如,我使用unsigned int来执行GPU拾取)
将这些纹理附加到FBO的不同颜色附件:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, texPosition, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
GL_TEXTURE_2D, texNormal, 0);
当然,你可能想添加一个深度附件,以及所有其他你会用FBO做的"经典"事情。
绘图
下一步,您必须使用FBO绘制场景。
// set rendering destination to FBO
glBindFramebuffer(GL_FRAMEBUFFER, myFBO);
// Set which GL_COLOR_ATTACHMENTi are the targets of the fragment shader
GLenum buffers_to_render[] = {GL_COLOR_ATTACHMENT0,GL_COLOR_ATTACHMENT1};
glDrawBuffers(2,buffers_to_render); // `2` because there are two buffers
// Draw your scene
drawScene();
在这一点上,您正在寻找的所有信息都以纹理的形式存储在GPU上,并以适当的格式存储(三个32位浮动组件,无需像您的问题中那样转换为字节值)。
检索CPU上的数据
最后,可以使用glRead...
方法将纹理中的数据从GPU返回到CPU。
float * positions = new float[3*width*height];
float * normals = new float[3*width*height];
glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbind the FBO for writing (and reading)
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_); // bind the FBO for reading
glReadBuffer(GL_COLOR_ATTACHMENT0); // set which attachment to read from
glReadPixels(0, 0, width, height, // read the pixels
GL_RGB, GL_FLOAT, // use the right format here also
positions);
glReadBuffer(GL_COLOR_ATTACHMENT1); // repeat for the normals
glReadPixels(0, 0, width, height,
GL_RGB, GL_FLOAT,
normals);
你应该很好去:-)
如果在顶点着色器中使用这些值设置不同的变量,那么在片段着色器中,您将为每个像素插值这些值。
请注意,在OpenGL 4.3中,输入和输出变量被使用,而不是变化。
- QGraphicsPolygonItem在拖动时未更新QPolygonF坐标
- 在C++中使用GDAL可以将图像的像素坐标转换为lat,long吗
- UE4-如何在给定4个屏幕坐标的情况下缩放纹理或材质
- _T("xyz")是什么意思?
- OpenGL 4.3 错误地将第 4 个纹理坐标映射到与第 3 个纹理坐标相同的位置
- 比较两个节点坐标的最佳方法是什么?
- 在 OpenGL 中将笛卡尔世界坐标转换为球面局部坐标
- SDL2 调整窗口大小后如何缩放鼠标坐标?
- 如何在C++中获取坐标?
- 如何将 x.y 坐标的值存储在不同的数组中
- 如何将鼠标坐标转换为"mm"
- 重心坐标并不总是有效(3d)
- 尝试渲染像素坐标时,简单线条渲染失败
- 如何在XYZ播放器平面中找出前向坐标
- 给定两组 xyz 坐标和一个 sag (a) 的值,我可以在 OpenGL 中的这些点之间绘制一个悬链线
- xyz 坐标来自 reprojectImageTo3D opencv
- 如何在C++中从Kinect中获取XYZ坐标
- 在opengl中从模型中获取可见的XYZ坐标和法线
- 如何改变XYZ坐标到另一个2D系统
- 代码到图形XYZ坐标