【问题标题】:Shading issue in opengl glslopengl glsl中的阴影问题
【发布时间】:2013-07-12 09:52:52
【问题描述】:

我正在加载并尝试应用一些着色(为简单起见通过固定管道+着色器组合)的 3d obj(wavefront) 模型显示错误。

现在我认为我可以发现一些问题。 轻微的问题:似乎不是一成不变的。当我通过变换旋转对象时,它似乎在旋转。我正在使用 gluLookAt+gluPerspective 来设置我的视图矩阵,我已经读过如果你在应用 gluLookAt 之前在 opengl 中应用灯光,理论上你的灯光保持静态。这似乎不是这里的情况。

问题 2 是模型被着色的方式。它有点波涛汹涌而不是平滑,我什至不确定为什么会出现这种环形效果。 我已经在 ShaderMaker 中加载了我的网格并应用了我的顶点+片段着色器,一切都绘制得很完美。好像我在我的绘图程序中做错了什么。

我的顶点着色器:

#version 120

varying vec3 N;
varying vec3 v;
void main(void)  
{    
   v = vec3(gl_ModelViewMatrix * gl_Vertex);      
   N = normalize(gl_NormalMatrix * gl_Normal);
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;  
}

我的片段着色器:

#version 120

varying vec3 N;
varying vec3 v;
#define MAX_LIGHTS 2
void main (void)  
{  
   vec4 finalColour;

        vec4 amb;
        amb = vec4(0.2,0.2,0.2,1.0);

        vec4 diff;
        diff = vec4(1.0,1.0,1.0,1.0);

       vec3 L = normalize(gl_LightSource[0].position.xyz - v);  
       vec3 E = normalize(v);
       vec3 R = normalize(reflect(L,-N));  
       //vec4 Iamb = gl_FrontLightProduct[i].ambient;    
        vec4 Iamb = amb;

        //vec4 Idiff = gl_FrontLightProduct[i].diffuse * max(dot(N,L), 0.0);
       vec4 Idiff = diff * max(dot(N,L), 0.0);

        Idiff = clamp(Idiff, 0.0, 1.0);    
       vec4 Ispec = gl_FrontLightProduct[0].specular
                    * pow(max(dot(R,E),0.0),0.0*gl_FrontMaterial.shininess);
       Ispec = clamp(Ispec, 0.0, 1.0);
       finalColour += Iamb + Idiff;

   gl_FragColor = gl_FrontLightModelProduct.sceneColor + finalColour;
}

EDIT ::添加了我的绘图程序。

 [[self openGLContext] makeCurrentContext];
    [sM useProgram];


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glClearColor(0.0f,0.0f,0.0f,1.0f);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    float aspect = (float)1024 / (float)576;

    gluPerspective(15.0, aspect, 1.0, 15.0);

    glMatrixMode(GL_MODELVIEW);
    float lpos[4] = {0.0,2.0,0.0,1.0};
    glLoadIdentity();
    glLightfv(GL_LIGHT0, GL_POSITION, lpos);

    gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);


    glTranslatef(0.0f, 0.0f, 0.0f);
    glScalef(0.5f, 0.5f, 0.5f);

    glRotatef(self.rotValue, 1.0f, 1.0f, 0.0f);



    glEnableClientState(GL_VERTEX_ARRAY);  
    glEnableClientState(GL_NORMAL_ARRAY);
    NSLog(@"%i", self.W);

    if(self.W == NO)
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    } 
    if (self.W == YES)
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    }
    glColor3f(1.0f,0.0f,0.0f);
    glBindBuffer(GL_ARRAY_BUFFER, vBo[0]);
    glVertexPointer(3, GL_FLOAT, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vBo[1]);
    glNormalPointer(GL_FLOAT, 0, 0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vBo[2]);
    glDrawElements(GL_TRIANGLES, object.indicesCount, GL_UNSIGNED_INT, 0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);





    GLenum err = glGetError();
    if (err != GL_NO_ERROR)
        NSLog(@"glGetError(): %i", (int)err);

    [[self openGLContext] flushBuffer];

我的着色器实际上是从在线资源借来的。我自己做了,但我想确保我使用的是有经验的人提供的可靠的。在我解决这个问题之前,我不打算保留它们。

【问题讨论】:

  • 我不认为这个特殊的着色器是“可靠的”。您需要在片段着色器中标准化法线,而不是在顶点着色器中。顶点法线是顶点的矢量属性,因此它们在三角形上线性插值。而且这种插值的结果已经不正常了。着色器代码很乱,变量的名字很糟糕。我不确定在这里做什么。我猜你想让 你的 着色器工作,你为什么要发布别人的代码? (顺便为 gif 点赞)
  • 我要做的第一件事是验证法线是否正确。在顶点中执行N = gl_Normal;,在片段着色器中执行gl_FragColor = normalize(N)*0.5+0.5;,以可视化对象空间法线。或者使用gl_FragColor = normalize(+-N),因为映射到 RGB 的可读性更强。
  • 事情是(我在上面提到的)我尝试了 ShaderMaker 和 Opengl Shader Builder(osx) 中的着色器,它们似乎都工作正常。它们产生完美的平滑阴影。所以我继续假设着色器工作正常。当我回到我的工作站并就结果回复你时,我会实施你的建议。关于着色器中混乱的部分;哦,那是我对值进行了一些试验的结果。道歉。
  • 啊哈!现在我明白了,我的错。好吧,我认为您的绘图代码看起来不错。灯光的位置在眼睛空间中,所以是的,它不应该受到视图矩阵或对象旋转的影响。
  • 好的,这有助于了解。它实际上是一个我不知道的 glsl 调试机制。这是 vec4(normalize(N),1.0)*0.5+0.5 (oi42.tinypic.com/ouuse0.jpg) 的结果。 vec4(normalize(+N),1.0) / vec4(normalize(-N) 以不同的颜色输出相同的模式。我不知道如何解释结果。

标签: opengl glsl lighting


【解决方案1】:

我想我找到了问题所在。尚未实施解决方案,但我很确定问题就在那里。这个问题也和我的问题很相关:

Understanding normals indices with Wavefront Obj

问题在于我处理核心数据的方式(来自 obj 文件)。我天真地相信在我解析它们时将它们直接传递给 OpenGL(通过 VBO)会起作用。 这里有一点幽默来伴随我的错误。 我希望我的链接不违反指导规则。 特别感谢 Andreas 帮助我追踪问题。 link

更新:已实施解决方案,我的模型现在可以使用正确的阴影进行渲染。

我使用顶点和法线面将波前数据(顶点+法线)重新排列成新的向量。我也从 glDrawElements 切换到 glDrawArrays 因为 glDrawElements 不支持为正常和 uv 向量发送不同的索引。尽管此解决方案增加了加载时间和占用空间(因为重复的顶点不会从缓冲区中删除),但它可以正常工作并满足我的需求。

【讨论】:

  • 哦,我必须记住那个模因,经典的误解。 ;)
  • 简短的回答是,正如 rioki 在我提供的问题的链接中提到的那样,obj 格式针对存储而不是渲染进行了优化。
  • 啊,所以 OBJ 为顶点法线使用了一组不同的索引,但 OpenGL 没有。在 OBJ 中,面定义为“f i0/j0/k0 i1/j1/k1 ... in/jn/kn”,其中 i 是顶点索引,j 是纹理坐标索引,k 是法线索引。很高兴知道。
猜你喜欢
  • 2015-02-04
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 1970-01-01
  • 2014-01-16
  • 1970-01-01
  • 2014-12-11
  • 2015-01-17
相关资源
最近更新 更多