首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OpenGL阴影地图移动版本不起作用

OpenGL阴影地图移动版本不起作用
EN

Stack Overflow用户
提问于 2019-11-28 13:56:22
回答 1查看 447关注 0票数 2

摘要

在将 my OpenGL 3.3 (“桌面”)的游戏引擎移植到OpenGL ES 3.2 ("mobile")时遇到了问题。虽然everything在桌面上工作得很好,但在移动环境中一切都可以工作,但是影子映射

我的问题很简单,:有人能在我共享的代码中发现问题吗,或者指出正确的路径?

上下文

我所有的引擎代码都是从应用层用C

  • Apart编写的(我在桌面上使用glfw,在移动上使用glfm ),代码库是相同的:完全相同的代码是为桌面和mobile.

  • The着色器编译的--除了#版本和精度默认值之类的注入头--在我的引擎中的platforms

  • ,我正在为桌面开发使用NVIDIA 1080,我正在使用全新的ASUS手机和一款旧的LG results.

进行测试,都运行Android 9,根据CPU-Z应用程序都支持OpenGL es3.2,都显示出完全相同的缺陷

截图

我非常简单的光测试级别在桌面上被正确地呈现。在中间的列的右边有一个黄色(不可见)的光,所以阴影应该投射到左边,如下面的桌面屏幕截图所示:

但在手机上却是大错特错:

正如你所看到的,手机上的阴影是“完全错误的”。它应该在左边,就像在桌面上一样,但它却走错了方向,看上去“被砍掉了”。

我自己的想法和行动

我已经非常小心地确保我的所有调用都可以在glDebugMessageCallback es3.2上使用,就像在OpenGL 3.3核心

  • 上一样,我非常小心地确保OpenGL调用没有问题:我使用的是,在任何time
  • Since上都没有错误--它“只工作”在桌面上,我觉得它背后的数学并不是错误的
  • --我的引擎支持远程光影缓存作为性能优化,但是禁用它没有影响,所以这并不是问题的根源。

(希望)相关代码

C中的阴影映射设置

创建立方体映射纹理以保存阴影的代码:

代码语言:javascript
复制
static GLuint r_createShadowmapTexture() {
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
    for (unsigned int i = 0; i < 6; ++i)
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT32F, r_shadowSize, r_shadowSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, GL_GREATER);
    return tex;
}

为影子映射设置框架缓冲区的代码:

代码语言:javascript
复制
glGenFramebuffers(1, &r_shadowDepthMapFBO);
glBindFramebuffer(GL_FRAMEBUFFER, r_shadowDepthMapFBO);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

呈现阴影映射的代码:

代码语言:javascript
复制
static struct {
    vec3 centerOffset, up;
} const g_shadowMapTransforms[6] = {
    { {1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f} },
    { {-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f} },
    { {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f} },
    { {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f} },
    { {0.0f, 0.0f, 1.0f}, {0.0f, -1.0f, 0.0f} },
    { {0.0f, 0.0f, -1.0f}, {0.0f, -1.0f, 0.0f} },
};

static void r_shadowMapPass(const point_light_t* light, GLuint cubemapTexture) {
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    glDepthMask(GL_TRUE);

    glBindFramebuffer(GL_FRAMEBUFFER, r_shadowDepthMapFBO);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, cubemapTexture, 0);

    const float farPlane = min(r_far, light->radius);
    mat4x4 shadowProj;
    mat4x4_perspective(shadowProj, (float)M_PI_2, 1.0f, r_near, farPlane);
    mat4x4 shadowVP[6];
    for (int i = 0; i < 6; ++i) {
        vec3 center;
        vec3_add(center, light->origin, g_shadowMapTransforms[i].centerOffset);
        mat4x4 view;
        mat4x4_look_at(view, (float*)light->origin, center, (float*)g_shadowMapTransforms[i].up);
        mat4x4_mul(shadowVP[i], shadowProj, view);
    }

    rtech_shadowmap_enable();
    rtech_shadowmap_setLightPos((float*)light->origin);
    rtech_shadowmap_setFarPlane(farPlane);
    rtech_shadowmap_setShadowMatrices(shadowVP);
    render_entity_t* re = r_entities;

    glClear(GL_DEPTH_BUFFER_BIT);
    for (uint32_t i = 0; i < r_numEntities; ++i, ++re) {
        if (!re->castsShadow)
            continue;
        rtech_shadowmap_setModelMatrix(re->m);
        if (re->hasSolid) {
            const render_solids_t* const rs = r_solids + re->index;
            for (uint32_t j = 0; j < rs->count; ++j) {
                const uint32_t ao = rs->offset + j;
                r_renderBlock(ao, rs, j);
            }
        } else {
            render_model_t* const rm = &r_models[re->index];
            for (uint32_t j = 0; j < rm->count; ++j)
                r_renderArrayObject(rm->arrayObjects[j], rm->numIndices[j]);
        }
    }

    glDepthMask(GL_FALSE);
}

在桌面上,我在所有着色器(顶点、几何图形和片段)前缀如下:

代码语言:javascript
复制
#version 330 core

在移动设备上,我在所有着色器前加上以下前缀:

代码语言:javascript
复制
#version 320 es
precision highp float;
precision highp int;
precision highp sampler2D;
precision highp samplerCubeShadow;

阴影地图顶点着色器:

代码语言:javascript
复制
layout (location = 0) in vec3 aPos;

uniform mat4 gModel;

void main()
{
    gl_Position = gModel * vec4(aPos, 1.0);
}

阴影地图几何着色器:

代码语言:javascript
复制
layout (triangles) in;
layout (triangle_strip, max_vertices=18) out;

uniform mat4 gShadowMatrices[6];

out vec4 FragPos; // FragPos from GS (output per emitvertex)

void main()
{
    for(int face = 0; face < 6; ++face)
    {
        gl_Layer = face; // built-in variable that specifies to which face we render.
        for(int i = 0; i < 3; ++i) // for each triangle's vertices
        {
            FragPos = gl_in[i].gl_Position;
            gl_Position = gShadowMatrices[face] * FragPos;
            EmitVertex();
        }
        EndPrimitive();
    }
}

阴影地图片段着色器:

代码语言:javascript
复制
in vec4 FragPos;

uniform vec3 gLightPos;
uniform float gFarPlane;

void main()
{
    // get distance between fragment and light source
    float lightDistance = length(FragPos.xyz - gLightPos);

    // map to [0;1] range by dividing by gFarPlane
    lightDistance = lightDistance / gFarPlane;

    // write this as modified depth
    gl_FragDepth = lightDistance;
}

实际使用影子地图的点光传递的摘录:

代码语言:javascript
复制
...
uniform samplerCubeShadow gShadowCubeMap;
uniform float gFarPlane;
...

float ShadowCalcSinglePass(vec3 fragPos, vec3 lightPos) {
    vec3 fragToLight = fragPos - lightPos;
    float currentDepth = (length(fragToLight) - (0.005 * gFarPlane)) / gFarPlane;
    return texture(gShadowCubeMap, vec4(fragToLight, currentDepth));
}

我知道这是一个非常开放的问题,涉及到很多代码。我试图提供必要的相关信息,我可以分享更多,如果需要或要求!

更新1

根据@MichaelKenzel的建议,我尝试将影子地图呈现到屏幕上。如下图所示,这在桌面上非常有效。然而,在手机上,这显示了一个“全红色”阴影地图,它(因为我的着色器做1.0样例)纹理()函数是为每个像素返回0。然而,从上面的“错误”图像上可以看到,在某个地方存在阴影,因此这似乎是从深度缓冲区以这种方式读取数据的一个问题。注意事项:下面的图像来自一个与上面的测试级别不同的测试级别,一个具有更复杂的阴影

代码语言:javascript
复制
in vec2 TexCoord0;

uniform samplerCube gTexture;
uniform int gSide;

out vec4 FragColor;

void main()
{
    vec3 vec;
    switch (gSide) {
    case 0:     vec = vec3(1.0, TexCoord0.xy); break;
    case 1:     vec = vec3(-1.0, TexCoord0.xy); break;
    case 2:     vec = vec3(TexCoord0.x, 1.0, TexCoord0.y); break;
    case 3:     vec = vec3(TexCoord0.x, -1.0, TexCoord0.y); break;
    case 4:     vec = vec3(TexCoord0.xy, 1.0); break;
    case 5:     vec = vec3(TexCoord0.xy, -1.0); break;
    default:    vec = vec3(1.0, 0.0, 0.0); break;
    }

    FragColor = vec4(vec3(1.0, 0.0, 0.0) * (1.0 - texture(gTexture, vec).r), /*alpha*/ 1.0);
}

呈现影子映射的代码--调试四元图:

代码语言:javascript
复制
void r_debugPassShadowMap2() {
    if (!r_shadowmapDebug.initialized) {
        r_shadowmapDebug.initialized = true;

        const float margin = 16;
        const float mapWidth = (r_windowWidth - (margin * 7.f)) / 6.f;
        mat4x4 t, s;
        mat4x4_translate(t, 1, 1, 0); // quad verts range from -1x-1x0 to 1x1x0
        mat4x4_identity(s);
        s[0][0] = s[1][1] = s[2][2] = mapWidth / 2;
        mat4x4 m;
        mat4x4_mul(m, s, t);

        mat4x4 p;
        mat4x4_ortho(p, 0, (float)r_windowWidth, (float)r_windowHeight, 0, -1, 1);

        for (uint32_t i = 0; i < 6; ++i) {
            mat4x4 v;
            mat4x4_translate(v, margin + (margin + mapWidth) * i, margin, 0);
            mat4x4 mv;
            mat4x4_mul(mv, v, m);
            mat4x4_mul(r_shadowmapDebug.sideWVP[i], p, mv);
        }
    }

    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);
    glDisable(GL_BLEND);
    rtech_shadowmapdebug_enable();
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, r_shadowmapDebug.texture);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_NONE);
    for (uint32_t i = 0; i < 6; ++i) {
        rtech_shadowmapdebug_setWVP(r_shadowmapDebug.sideWVP[i]);
        rtech_shadowmapdebug_setSide(i);
        glBindVertexArray(r_quadAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
    }
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
}

更新2-第一次部分修复

由于@MorrisonChang的链接,我尝试了一些不同的东西,这带来了巨大的不同:我将GL_TEXTURE_MAG_FILTER和GL_TEXTURE_MIN_FILTER设置为GL_LINEAR,以获得阴影地图的纹理。当我把它改为GL_NEAREST时,我突然在手机上得到了更多的结果!然而,如下图所示,由于某种原因,它只呈现在一张脸上,而不是全部6张脸!但至少我又向前走了一步!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-11-29 08:47:09

我找到了答案,(对我来说)这是令人费解的,但我发现它是根据规格。当我改变了我的几何图形着色器之后,我立刻让它工作起来:

代码语言:javascript
复制
void main()
{
    for(int face = 0; face < 6; ++face)
    {
        gl_Layer = face; // built-in variable that specifies to which face we render.
        for(int i = 0; i < 3; ++i) // for each triangle's vertices
        {
            FragPos = gl_in[i].gl_Position;
            gl_Position = gShadowMatrices[face] * FragPos;
            EmitVertex();
        }
        EndPrimitive();
    }
}

对此:

代码语言:javascript
复制
void emitFace(mat4 m) {
    for(int i = 0; i < 3; ++i)
    {
        FragPos = gl_in[i].gl_Position;
        gl_Position = m * FragPos;
        EmitVertex();
    }
    EndPrimitive();
}

void main()
{
    gl_Layer = 0;
    emitFace(gShadowMatrices[0]);

    gl_Layer = 1;
    emitFace(gShadowMatrices[1]);

    gl_Layer = 2;
    emitFace(gShadowMatrices[2]);

    gl_Layer = 3;
    emitFace(gShadowMatrices[3]);

    gl_Layer = 4;
    emitFace(gShadowMatrices[4]);

    gl_Layer = 5;
    emitFace(gShadowMatrices[5]);
}

显然,通过for循环变量分配给gl_Layer是在OpenGL ES中不起作用的事情!

在这一页上,https://www.khronos.org/registry/OpenGL-Refpages/es3/html/gl_Layer.xhtml写着

如果着色器静态地为gl_Layer分配值,则启用分层呈现模式。

它还说:

如果几何级不对gl_Layer进行静态分配,则片段阶段中的输入gl_Layer将为零。

但它并没有说“您不应该为gl_Layer分配一个非静态值”,编译器也根本没有发出警告!

在OpenGL核心中,规范实际上说的是完全相同的东西:https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/gl_Layer.xhtml

但是,无论如何,我的NVIDIA驱动程序都支持动态分配给gl_Layer,因为这样做,我从来没有意识到它是错误的.

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59090503

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档