c++ - 混合光的问题

标签 c++ opengl 3d lighting blending

在过去的几天里,我一直致力于使用前向渲染系统进行一些照明。到目前为止,还不错,但是当我将要渲染的网格从全局中心 (0, 0, 0) 移开或旋转它时,所有灯光(环境光除外)开始“闪烁”(但仅限于此)远离 (0, 0, 0)) 的网格。当我有第二个网格时,它的位置是全局中心,灯光通常作用在那个网格上)。

可能值得一提的是,我只能在 Release模式下运行,因为在 Debug模式下运行会给我一个奇怪的异常。我相信这与 SFML 库有关...

这是我用定向光照亮物体时的样子(请注意,带有灰色砖纹理的网格没有显示出这种奇怪的效果):
https://www.dropbox.com/s/yt3ozxyeg8e6psa/Screenshot%20%284%29.png?dl=0

还有聚光灯:
https://www.dropbox.com/s/1yk2j0yg4fca6pz/Screenshot%20%285%29.png?dl=0

我使用 GLEW 1.10.0 加载 OpenGL 函数,使用 SFML 2.1 加载窗口内容。我的 IDE 是 Visual Studio 2013 Ultimate,我在装有最新 Nvidia 图形驱动程序的 Windows 8.1 上运行。


这是进行混合的代码:

void RenderingEngine::Render(GameObject* gameObject)
{
    Clear();
    m_baseLights.clear();
    gameObject->AddToRenderingEngine(this);
    gameObject->Render(this, *m_ambientShader);

    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE);
    glDepthMask(GL_FALSE);
    glDepthFunc(GL_EQUAL);

    for (uInt i = 0; i < m_baseLights.size(); i++)
        gameObject->Render(this, *m_baseLights[i]->GetShader());

    glDepthFunc(GL_LESS);
    glDepthMask(GL_TRUE);
    glDisable(GL_BLEND);
}


这里有几个其他重要的方法:

void GameObject::Render(RenderingEngine* renderingEngine, const Shader& shader)
{
    for (uInt i = 0; i < m_children.size(); i++)
        m_children[i]->Render(renderingEngine, shader);

    for (uInt i = 0; i < m_components.size(); i++)
        // NOTE: This is where MeshRenderer::Render(...) etc. get called
        m_components[i]->Render(renderingEngine, shader);
}



// NOTE: MeshRenderer inherits GameComponent
void MeshRenderer::Render(RenderingEngine* renderingEngine, const Shader& shader)
{
    shader.Bind();
    shader.UpdateUniforms(*renderingEngine, m_material, GetParentObject().GetTransform());
    m_mesh.Draw();
}



void Shader::Bind() const
{
    glUseProgram(m_program);
}



// NOTE: SpotShader is one of many classes that inherits Shader and implements its pure virtual method UpdateUniforms(...)
void SpotShader::UpdateUniforms(const RenderingEngine& renderingEngine, const Material& material, const Transform& transform) const
{
    material.GetTexture()->Bind(0);

    SetUniformMat4f("viewProjection", renderingEngine.GetMainCamera().GetViewProjection());
    SetUniformMat4f("transform", transform.GetTransform());
    SetUniformSpotLight("spotLight", *m_spotLight);
    SetUniformf("specularIntensity", material.GetSpecularIntensity());
    SetUniformf("specularExponent", material.GetSpecularExponent());
    SetUniformVec3f("cameraPosition", renderingEngine.GetMainCamera().GetParentObject().GetTransform().GetTranslation());
}



void Mesh::Draw() const
{
    glBindVertexArray(m_vertexArrayObject);
    glDrawElements(GL_TRIANGLES, m_drawCount, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

最佳答案

有时会出现这种情况,但这个问题的真正答案在 Edit2 部分。

我不久前在我的应用程序中注意到了类似的效果。我相信这与 GPU 上的数字精度有关。你离 0,0,0 越远,这个错误就越大。解决这个问题的一种方法是缩小世界。如果例如。在你的世界里,1 米的值(value)是 1.0,你可以将它缩小到 0.1。然而,这不是真正的解决方案,只是一种解决方法。

还有一件事。我记得在我的案例中,这个错误仅在通过 Visual Studio 运行应用程序时出现。尝试从 .exe 运行它,看看问题是否仍然存在。由于它不存在于我的游戏的发行版本中,我只是忽略了它并假设它一定与显卡的 Debug模式有关。


编辑:

好吧,我又想到一件事。你为什么使用 GL_EQUAL 而不是 GL_LEQUAL?我知道您认为既然您两次绘制同一个模型,它的位置应该是相同的,但您对此有绝对的把握吗?在这种情况下,没有充分的理由更喜欢 GL_EQUAL 而不是 GL_LEQUAL。尝试更改它,看看是否有帮助。远离 0,0,0 可以解释它,因为 0,0,0 是唯一没有对模型应用任何转换的地方。每个转换都可能导致不精确,这可能是 Z 检验失败的原因。

编辑2:

这个建议可能会让事情变得更好,但不会完全解决问题。这只是一个猜测,但让我告诉您 gameObject->Render 函数中发生了什么。你 PUSH 一个矩阵,绘制然后 POP 矩阵,对吧?现在你认为你现在有完全相同的转变?你不知道!几乎一样。要使事情正常进行,您需要重新设计您的程序。不要在绘制同一对象之间推送/弹出任何矩阵,你应该善于使用 GL_EQUAL 比较。

编辑3:

我的最终建议是:再次确保您使用的变换矩阵在每个过程中都完全相同。如果您找不到它可能不同的原因,请使用这个简单的 hack-around。使用作为统一传递给着色器的小偏移值。在每次通过时稍微增加这个值(试验应该是什么。我认为一些非常小的东西会产生问题)。然后,当您通过变换和 View 投影变换每个顶点时,从 Z 坐标中减去此偏移量。这样一来,每盏灯都会先于前一盏灯绘制。

编辑4: 另一个问题(恰好是这里的情况)是 GLSL 和 C++ 执行矩阵乘法可能略有不同,因此在着色器和 C++ 中执行相同的操作可能会产生不同的效果,从而导致伪影。

关于c++ - 混合光的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25547853/

相关文章:

opengl - GLSL 中的 HLSL cbuffer 等效项

ios - 在 iOS 上显示 3D 模型对象的注释

JavaScript Three.js 3D引擎: how to make object bigger by 20%?

matlab - 随着时间的推移绘制 3d 位置数据

c++ - 用什么代替 C++ Qt 上的 glob?

c++ - 如何将 OpenMP 和 MPI 导入大型 CLion CMake 项目?

opengl - OpenGL 是否钳制每个纹理阶段的输出?

c++ - 字符串索引的数据结构?

c++ - 当用户在 tableView 中使用键盘箭头更改行时如何发出信号?

c++ - Terrain GeoMipMapping LOD - 消除裂缝