我正在研究图形引擎的渲染到纹理组件。我花了几个小时在 DX 上实现它,它按预期工作,我花了几天时间在 OpenGL 实现上,但它拒绝工作。
当将深度缓冲区渲染到纹理时,我得到了一些预期的结果,但图像充满了奇怪的伪像(颜色目标工作正常)。我试过各种深度和模板位配置、不同的绑定(bind)方法,但我一无所获。
我将发布我的结果以及我拥有的导致“最接近”正确结果的相关代码。
场景是大量的大炮,大炮前面有一个摄像头位置,摄像头前面有一架飞机。飞机的纹理是第二个围绕大炮旋转的相机的渲染结果。我希望飞机大部分是红色的,在物体靠近第二个摄像头的地方有一些较暗的红色区域。
这是我在 DX 中得到的结果(这是我所期望的):[1]: http://i.imgur.com/Zfchzq3.png “好结果”
这是我从 GL 得到的结果:[2]: http://i.imgur.com/vH9u1bq.png “奇怪的结果”
我不知道黑色部分是从哪里来的。通过一些着色器调试,我可以看出未渲染区域仍为 1.0(深度清晰值),非黑色区域接近 1.0 但从未达到(如我所料)。黑色区域是……随机的。
我用来创建纹理的代码是:
glGenTextures(1, &textureID);
dim = GL_TEXTURE_2D;
wth = width;
hgt = height;
iFormat = _glTranslateFormat(fmt, format, type);
glBindTexture(dim, textureID);
glTexStorage2D(dim, 1, iFormat, width, height);
_glTranslateFormat 将原生格式转换为 GL 格式,这将返回 GL_DEPTH_COMPONENT16 atm。我尝试过其他格式,它们给出了更奇怪的结果。 32 和 32F 允许采样值远远超出 0 和 1 的范围(例如高于 1000000000),基于模板也会导致各种问题(即使我更改代码以考虑模板)。
我用来将它绑定(bind)到帧缓冲区的代码是:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, d->_exposeTexture()->_exposeAPI(), 0);
_exposeAPI 返回纹理的 ID。每次代码需要将深度缓冲区绑定(bind)到不同的帧缓冲区时都会发生这种情况(帧缓冲区将事先绑定(bind))。
我已经尝试了多种将渲染目标绑定(bind)到帧缓冲区的方法,但问题似乎永远不会消失。任何帮助将不胜感激。现在,我必须放弃引擎的 OpenGL 组件并使用 DX,直到找到解决此问题的方法。
编辑:根据要求,我添加了负责从纹理中采样的着色器,文件末尾的内容只是调试我玩过的代码。深度纹理作为漫反射纹理出现。
#version 430
struct Light
{
vec4 diffuse;
vec4 specular;
vec4 attenuation;
vec3 spot;
uint nID;
uint type;
};
layout (std140, binding = 9) uniform singleLight
{
Light light;
};
struct BasicFSInput
{
vec4 position;
vec3 normal;
vec2 uv;
vec4 fragPos;
vec3 toLight;
};
layout(binding = 1) uniform sampler2D diff1;
layout(binding = 2) uniform sampler2D amb1;
layout(binding = 3) uniform sampler2D spec1;
layout (location = 0) in BasicFSInput fin;
layout (location = 0) out vec4 color;
layout(std140, binding = 10) uniform material
{
float specular;
float shininess;
};
void BasicFragmentShader()
{
vec4 dTexel = texture(diff1, fin.uv).rgba;
vec4 aTexel = texture(amb1, fin.uv).rgba;
vec4 sTexel = texture(spec1,fin.uv).rgba;
vec3 lightDir = normalize(fin.toLight);
vec3 n = normalize(fin.normal);
float NdotL = max(dot(n, lightDir),0.0);
vec4 col = NdotL * light.diffuse;
vec4 ambContrib = aTexel;
vec4 diffContrib = dTexel * col;
vec3 refl = 2.0 * NdotL * n + lightDir;
float NdotR = max(dot(normalize(refl), normalize(-fin.fragPos.xyz)),0.0);
float specContrib = sTexel * specular * pow(NdotR, shininess);
color = ambContrib + diffContrib + specContrib;/*
if(dTexel.r < -1.0)
color.r = 1.0f;
if(dTexel.r > 1.0)
color.b = 1.0f;
if(dTexel.r == 1.0f)
color.g = 1.0f;*/
//color.r = dTexel.r;
/*if(dTexel.r < 0.5f)
color.b = 1.0f;
if(dTexel.r > 0.5f)
color.r = 1.0f;*/
/*if(dTexel.r < -10000000.0f)
color.g = 1.0f;*/
//color.a = 1.0f;
}
最佳答案
不要那么快放弃 OpenGL :)
您确定要将深度缓冲区渲染到纹理而不是颜色缓冲区到纹理吗?
也许下面的内容可能有所帮助(如果您已经知道这一点,我们深表歉意)。 (它取自 OpenGL Superbible 第 6 版。)
设置帧缓冲区
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
//texture for the colour buffer
glGenTextures(1, &colourTexture);
glBindTexture(GL_TEXTURE_2D, colourTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//texture for the depth buffer
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT32F, width, hwight);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colourTexture, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0);
const GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, drawBuffers);
然后在调用 glDrawArrays/Elements 之前绑定(bind)到帧缓冲区
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
以后要渲染贴图到屏幕时绑定(bind)贴图
glBindTexture(GL_TEXTURE_2D, colourTexture);
渲染纹理时在片段内部需要采样器。
#version 430 core
uniform sampler2D tex;
in VS_OUT
{
vec2 texcoord;
} fs_in;
out vec4 color;
void main(void)
{
color = texture(tex, fs_in.texcoord);
}
关于c++ - 在 OpenGL 中将深度渲染到纹理时出现奇怪的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20930639/