OpenGL中的视差映射故障

4

alt text alt text

当我将切向量转移到顶点着色器后,反转它得到的结果如下:

alt text alt text

“阴影”在错误的位置。

(只有当我通过Y轴旋转它时才有效,因此最后的图像似乎呈现了一个良好的视差映射立方体)

我确定这不是切向量或纹理坐标问题

因为:

我使用完全相同的切线计算函数完全相同的立方体位置、法线和纹理坐标数据,与工作演示中一样。毕竟,我将包含位置/纹理坐标/法线/切向量数据的数组导出到.txt文件中,然后看到了我期望的内容(我期望的是与工作演示中相同的pos/tex/norm数据,包括我从工作演示中成功导出的计算切线)。

下一个参数是,我将我的着色器代码复制到工作演示中,它仍然有效。另一个是,我尝试了多种方法来渲染这个立方体。我尝试过使用glVertexAttribPointer的VBO,尝试过将切向量保存为其他纹理坐标的VBO(与演示中一样),尝试过使用glVertexAttrib4f的DisplayList。结果是……完全相同。

高度图正确加载,我尝试将其设置为漫反射贴图,看起来还不错。 glGetError()没有报错,着色器编译日志也是如此。

可能是相机或初始化状态的问题。

也许发布初始化代码会有所帮助。

void CDepthBase::OpenGLSet() {

    glEnable( GL_TEXTURE_2D );
    glShadeModel( GL_SMOOTH );
    glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
    glClearDepth( 1.0f );
 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glDepthFunc( GL_LEQUAL );
    glEnable(GL_DEPTH_TEST);



    glBlendFunc( GL_ONE, GL_ONE );
    GLfloat ratio;

    glViewport(0, 0, ResolutionWidth, ResolutionHeight);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, ResolutionWidth / (float)ResolutionHeight, 0.1f, 900.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    if (GLEW_OK != glewInit()) {
        MBX("Failed to init GLEW.", "Error");
    }
    if (glewIsSupported("GL_ARB_vertex_buffer_object")) {
        VBO_supported = true;


    } else VBO_supported = false;

 glHint( GL_FOG_HINT, GL_DONT_CARE );      
    glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
 glShadeModel(GL_SMOOTH);

    glAlphaFunc(GL_ALWAYS, 0);
}

顺便说一下,我正在使用带有扩展功能的GL Extension Wrangler。

着色器代码和日志(此导出文件包含直接传递给glShaderSource的代码):

Vertex shader was successfully compiled to run on hardware.


Fragment shader was successfully compiled to run on hardware.

Fragment shader(s) linked, vertex shader(s) linked. 


------------------------------------------------------------------------------------------


 varying vec3 lightDir;                                          
 varying vec3 viewDir;
 attribute vec4 tangent;
 void main() 
 { 
 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
 gl_TexCoord[0] = gl_MultiTexCoord0;
 vec3 vertexPos = vec3(gl_ModelViewMatrix * gl_Vertex);
 vec3 tn = tangent.xyz;             
 vec3 n = normalize(gl_NormalMatrix * gl_Normal);
 vec3 t = normalize(gl_NormalMatrix * tangent.xyz);
 vec3 b = cross(t, n) * -tangent.w;
 mat3 tbnMatrix = mat3(t.x, b.x, n.x,
                       t.y, b.y, n.y,
                       t.z, b.z, n.z);
 lightDir = (gl_LightSource[0].position.xyz - vertexPos) / 100.0;
 lightDir = tbnMatrix * lightDir;
 viewDir = -vertexPos;
 viewDir = tbnMatrix * viewDir;
 } 

-----------------------------------------------------------------------------------------
 varying vec3 lightDir;                                          
 varying vec3 viewDir;
 uniform sampler2D diffuseMap;
 uniform sampler2D normalMap;
 uniform sampler2D heightMap;
 uniform float scale;
 uniform float bias;
 void main() 
 { 
 vec3 v = normalize(viewDir);
 vec2 TexCoord = gl_TexCoord[0].st;
{
 float height = texture2D(heightMap, gl_TexCoord[0].st).r;
 height = height * scale + bias;
 TexCoord = gl_TexCoord[0].st + (height * v.xy); 
}
 vec3 l = lightDir;
 float atten = max(0.0, 1.0 - dot(l, l));
 l = normalize(l);
 vec3 n = normalize(texture2D(normalMap, TexCoord).rgb * 2.0 - 1.0);
 vec3 h = normalize(l + v);
 float nDotL = max(0.0, dot(n, l));
 float nDotH = max(0.0, dot(n, h));
 float power = (nDotL == 0.0) ? 0.0 : pow(nDotH, gl_FrontMaterial.shininess);
 vec4 ambient = gl_FrontLightProduct[0].ambient * atten;
 vec4 diffuse = gl_FrontLightProduct[0].diffuse * nDotL * atten;
 vec4 specular = gl_FrontLightProduct[0].specular * power * atten;
 vec4 color = gl_FrontLightModelProduct.sceneColor + ambient + diffuse + specular;color *= texture2D(diffuseMap,TexCoord);
 gl_FragColor = color ;
 } 

因为结果与常量值交换时相同,所以Uniforms正常工作。编译着色器:

void __Shader::import(){
    if(imported) __Shader::~__Shader();

        v = glCreateShader(GL_VERTEX_SHADER);
        f = glCreateShader(GL_FRAGMENT_SHADER); 


        glShaderSource(v, 1, (const GLchar **)&vsrc.cstr,NULL);
        glShaderSource(f, 1, (const GLchar **)&fsrc.cstr,NULL);

        glCompileShader(v);
        glCompileShader(f);

        p = glCreateProgram();

        glAttachShader(p,v);
        glAttachShader(p,f);

        if(_flags & NORMAL_MAPPING) 
            glBindAttribLocation(p, ATTRIB_TANGENT, "tangent");

        glLinkProgram(p);

        if(_flags & DIFFUSE_MAPPING) 
            diffuseUni.loc = glGetUniformLocation(p, "diffuseMap");
        if(_flags & NORMAL_MAPPING) 
            normalUni.loc = glGetUniformLocation(p, "normalMap");
        if(_flags & PARALLAX_MAPPING) 
            heightUni.loc = glGetUniformLocation(p, "heightMap");
        if(_flags & SPECULAR_MAPPING) 
            specularUni.loc = glGetUniformLocation(p, "specularMap");

        imported = true;
}

在VBO中设置属性:

    if(tangents.size() > 0){
        buffered |= 3;
        glGenBuffers(1, &VBO_tangent);
        glBindBuffer(GL_ARRAY_BUFFER, VBO_tangent);
        glBufferData(GL_ARRAY_BUFFER, tangents.size()*sizeof(tangent), tangents.get_ptr(), GL_STATIC_DRAW);
    }

// and in draw:

if(buffered & 3) {

        glBindBuffer(GL_ARRAY_BUFFER, VBO_tangent);    
        glVertexAttribPointer(__Shader::ATTRIB_TANGENT, 4, GL_FLOAT, GL_FALSE, 0, 0);   
        glEnableVertexAttribArray(__Shader::ATTRIB_TANGENT);  
    }

and a small note

for(int i = 0; i < responders.size(); ++i)
if(strstr(responders[i].idea, "tangent problem"))
responders[i].please_dont_talk();

只需告诉我您对导致这些不良结果的其他想法即可。

3
请将后两个问题中的信息添加到第一个问题中,并关闭后两个问题。一个问题只需要一个问题。如果您这样做,我会查看它。 - GManNickG
好的,我做到了。这些都是所需的所有信息。 - Pythagoras of Samos
好的,我打算将另外两个(一个)作为重复问题关闭。 - GManNickG
看起来你的着色器代码在这个问题中缺失,如果有任何更改,我会让你编辑它。你能否也发布设置着色器变量的代码? - GManNickG
我现在已经编辑过了,不应该再需要任何代码了。 - Pythagoras of Samos
2
@Glorian: 如果你说示范可以运行,试着逐行将示范代码修改到你的代码中。当它停止运行时,看看你改变了什么。 - Yakov Galka
1个回答

5

哇,问题已经解决了。问题出在加载纹理文件上,尽管我没有看到任何漫反射贴图上的问题,甚至是漫反射+法线贴图。我使用的是SDL的IMG_Load,也许我用错了方式,但对我来说它没用。可能是法线贴图出了问题。

错误的纹理导入代码:

if(imported || filenamez.length() < 1) return;
    SDL_Surface* surface = 0;


        surface = IMG_Load(filenamez.c_str());

    if (surface) { 
        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    bool endianess = filenamez.substr(filenamez.length()-4) == ".jpg";
        glTexImage2D(GL_TEXTURE_2D, 0, 3, surface->w, surface->h, 0, 
            (endianess ? GL_RGB : GL_BGR), GL_UNSIGNED_BYTE, surface->pixels);

    }

注意!

我现在正在使用从我之前提到的dhpoware演示中获取的基于HBITMAP的纹理加载。它运行良好。

平静。

经过2-3天的艰苦调试,让我感到有点欣喜若狂。

哦,我差点忘了,最终结果:

alt text

非常好,看起来很不错。很高兴你解决了问题,抱歉我没有明确地回复你。早些时候我看了你的东西,没有发现任何问题。我只是记得要回来再仔细看一遍,结果你自己解决了。 :) - GManNickG
我遇到了完全相同的问题...只不过我使用的是一种不同的语言,它有自己的图像加载器。你知道你所使用的加载器的确切区别吗?是否有更改着色器以弥补这一点的方法?我已经尝试了每个变量的实验,但当更改时它们似乎都会使情况变得更糟... - ClickerMonkey
找到了!我之前尝试过这个方法,但是还有其他问题。当你根据法线贴图计算法线时,需要取反y值。像这样:vec3 n = normalize(texture2D(normalMap, newTexCoord).rgb * 2.0 - 1.0); n.y = -n.y;修复完毕! - ClickerMonkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接