【问题标题】:Why is my texture being rendered black?为什么我的纹理被渲染为黑色?
【发布时间】:2016-04-26 10:53:45
【问题描述】:

我正在使用 LWJGL 3 编写一个 OpenGL 应用程序。我能够很好地渲染纯色,但是当我尝试引入纹理采样器时,我看到的都是黑色。

具体来说,fragment shader中texture(texUnit, DataIn.texCoord)返回的值总是vec4(0, 0, 0, 1)

我什至尝试使用所有 255 手动填充传递给 glTexImage2D 的缓冲区,但我得到了相同的结果。在这一点上我完全被难住了!

初始化:

private void initGL() {

    // Enable depth buffer
    GL11.glEnable(GL11.GL_DEPTH_TEST);

    // Set background colour
    GL11.glClearColor(0.2f, 0.2f, 0.4f, 0.0f);

    // Set viewport to the whole window
    GL11.glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

    // Enable alpha blending (transparency)
    GL11.glEnable(GL11.GL_BLEND);
    GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

    // Enable back-face culling
    GL11.glEnable(GL11.GL_CULL_FACE);
    GL11.glCullFace(GL11.GL_BACK);

    // Use linear filtering for texture scaling
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,
            GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,
            GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);

    // Clamp texture co-ordinates between 0 and 1
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,
            GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,
            GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);

    int errorCode = GL11.glGetError();
    if (errorCode != GL11.GL_NO_ERROR) {
        throw new RuntimeException(
                "OpenGL error " + String.valueOf(errorCode)
                + " during initialisation");
    }
}

纹理加载:

    String filename = "terrain.png";

    // Read image into a ByteBuffer
    IntBuffer w = BufferUtils.createIntBuffer(1);
    IntBuffer h = BufferUtils.createIntBuffer(1);
    IntBuffer comp = BufferUtils.createIntBuffer(1);
    ByteBuffer texelData = 
            STBImage.stbi_load(GFX_DIR + filename, w, h, comp, 4);
    if (texelData == null) {
        throw new RuntimeException("Error loading " + filename + ": " +
                STBImage.stbi_failure_reason());
    }
    int width = w.get();
    int height = h.get();

    // Generate texture ID
    terrainTexId = GL11.glGenTextures();
    // Pass our texture to the shader
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, terrainTexId);
    GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height,
            0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, texelData);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); // Deselect

    int errorCode = GL11.glGetError();
    if (errorCode != GL11.GL_NO_ERROR) {
        throw new RuntimeException(
                "OpenGL error " + String.valueOf(errorCode)
                + " loading texture: " + filename);
    }

渲染:

    // Clear the screen and depth buffer
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

    // Use our shader program
    GL20.glUseProgram(Shaders.programId);

    // Set the projection matrix
    FloatBuffer fb = BufferUtils.createFloatBuffer(16);
    projection.setPerspective(
            camera.getFovY(),
            window.getAspectRatio(), 
            Camera.Z_NEAR,
            Camera.Z_FAR);
    GL20.glUniformMatrix4fv(
            Shaders.projectionLoc, false, projection.get(fb));

    // Set the model-view matrix.
    modelView.setLookAt(
            camera.getPos(),
            camera.getTarget(),
            camera.getUpVector());
    GL20.glUniformMatrix4fv(Shaders.modelViewLoc, false, modelView.get(fb));

    // Bind our texture to texture unit 0
    GL13.glActiveTexture(GL13.GL_TEXTURE0 + 0);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, terrainTexId);
    // Tell the shader to sample from texture unit 0.
    // This is the default anyway.
    GL20.glUniform1i(Shaders.texUnitLoc, 0);

    // Pass the lighting information to the shader
    fb = BufferUtils.createFloatBuffer(3);
    GL20.glUniform3fv(Shaders.lightAmbientColourLoc,
            lighting.getAmbientColour().get(fb));
    GL20.glUniform1f(Shaders.lightAmbientIntensityLoc,
            lighting.getAmbientIntensity());
    GL20.glUniform3fv(Shaders.lightDiffuseColourLoc,
            lighting.getDiffuseColour().get(fb));
    GL20.glUniform3fv(Shaders.lightDiffuseAngleLoc,
            lighting.getDiffuseVector().get(fb));
    GL20.glUniform1f(Shaders.lightDiffuseIntensityLoc,
            lighting.getDiffuseIntensity());

    // Bind to the VAO that has all the information about the vertices
    GL30.glBindVertexArray(terrainSection.getVaoId());
    GL20.glEnableVertexAttribArray(Shaders.PARAM_VERTEX);
    GL20.glEnableVertexAttribArray(Shaders.PARAM_VERTEX_NORMAL);
    GL20.glEnableVertexAttribArray(Shaders.PARAM_MATERIAL_AMBIENT_COLOUR);
    GL20.glEnableVertexAttribArray(Shaders.PARAM_MATERIAL_DIFFUSE_COLOUR);
    GL20.glEnableVertexAttribArray(Shaders.PARAM_TEXTURE_COORDS);

    // Draw the vertices
    GL11.glDrawArrays(
            GL11.GL_TRIANGLES, 0, TerrainSection.NUM_VERTICES_FOR_BUFFERS);

    // Put everything back to default (deselect)
    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
    GL20.glDisableVertexAttribArray(Shaders.PARAM_VERTEX);
    GL20.glDisableVertexAttribArray(Shaders.PARAM_VERTEX_NORMAL);
    GL20.glDisableVertexAttribArray(Shaders.PARAM_MATERIAL_AMBIENT_COLOUR);
    GL20.glDisableVertexAttribArray(Shaders.PARAM_MATERIAL_DIFFUSE_COLOUR);
    GL30.glBindVertexArray(0);
    GL20.glUseProgram(0);

顶点着色器:

#version 330

uniform mat4 projection;
uniform mat4 modelView;
uniform vec3 lightAmbientColour;
uniform float lightAmbientIntensity;
uniform vec3 lightDiffuseAngle;
uniform vec3 lightDiffuseColour;
uniform float lightDiffuseIntensity;

layout(location = 0) in vec3 vertex;
layout(location = 1) in vec3 vertexNormal;
layout(location = 2) in vec3 materialAmbientColour;
layout(location = 3) in vec3 materialDiffuseColour;
layout(location = 4) in vec2 texCoord;

out Data {
    vec4 colour;
    vec2 texCoord;
} DataOut;

void main(void) {
    gl_Position = projection * modelView * vec4(vertex, 1.0);

    vec3 ambientComponent = lightAmbientIntensity * 
            (lightAmbientColour * materialAmbientColour);
    ambientComponent = clamp(ambientComponent, 0.0, 1.0);

    // The dot product gives us a measure of how "aligned" 2 vectors are,
    // between 0 and 1. If the light direction and the vertex normal are
    // well-aligned, the vertex should appear more brightly-lit.
    float dotProduct = dot(lightDiffuseAngle, vertexNormal);
    if (dotProduct < 0){
        dotProduct = 0;
    }
    vec3 diffuseComponent = lightDiffuseIntensity * dotProduct * 
            (lightDiffuseColour * materialDiffuseColour);
    diffuseComponent = clamp(diffuseComponent, 0.0, 1.0);

    vec3 colourResult = max(diffuseComponent, ambientComponent);
    DataOut.colour = vec4(colourResult, 1.0);
    DataOut.texCoord = texCoord;
}

片段着色器:

#version 330

uniform sampler2D texUnit;

in Data {
    vec4 colour;
    vec2 texCoord;
} DataIn;

out vec4 fragColour;

void main() {

    if (DataIn.colour.w == 0.0){
        // Discard transparent fragments, so they don't affect the depth buffer
        discard;
    }

    vec4 texColour = texture(texUnit, DataIn.texCoord);
    fragColour = DataIn.colour * texColour;
}

【问题讨论】:

  • 我看不到您的采样器对象(glBindSampler、glGenSamplers 等)。我在源代码中错过了吗?
  • 尝试添加 glGenerateMipmap(GL_TEXTURE_2D); glTexImage2d 之后
  • 显然采样器是我目前没有使用的新功能,但我会研究它们。我也没有使用 mipmap,因为我认为我不需要它们,但听起来它们可能也是一个好主意。

标签: java opengl glsl shader lwjgl


【解决方案1】:

你应该:

  • 暂时避免混合
  • glTexParameteri 移动到纹理加载/初始化中,因为它是纹理的一部分。或者使用采样器
  • 在纹理加载中在glBindTexture 之前调用glActiveTexture
  • 检查Shaders.texUnitLoc != -1
  • 在渲染中避免:
    • 绑定/解绑vao并添加glVertexAttribPointer
    • 调用 glEnableVertexAttribArrayglBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);,因为它们是 vao 的一部分
  • GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); 绑定 vao 时,将导致绑定 vao 中的 ebo/ibo 取消绑定
  • 如果您不使用任何索引 (glDrawArrays),则无需取消绑定任何 ebo/ibo
  • 既然你打电话给所有这些enableVertexAttribArray,你也应该打电话给glDisableVertexAttribArray(Shaders.PARAM_TEXTURE_COORDS);
  • 在您的着色器中定义相同的语义,例如:

    • #define VERTEX 0
    • #define VERTEX_NORMAL 1
    • #define MATERIAL_AMBIENT_COLOUR 2
    • #define MATERIAL_DIFFUSE_COLOUR 3
    • #define TEXTURE_COORDS 4

    并将它们相应地分配给各种locations

  • 检查纹理坐标
  • 暂时避免丢弃
  • 暂时写纯色fragColour = texColour

【讨论】:

  • 谢谢!问题是 glTexParameteri 在程序开始时只被调用一次 - 我没有意识到这是一个每个纹理设置。对 GL_ELEMENT_ARRAY_BUFFER 的引用是我在试验索引数组时遗留下来的。感谢所有提示,并且发现了!
  • 我很高兴你解决了 :) Ps: 还要记得设置基础和最大级别纹理,例如 here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 2013-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多