You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用LWJGL正确绘制半透明/透明纹理?

OpenGL透明纹理渲染异常问题

初始问题描述

花费大量时间实现屏幕端透明纹理绘制,但代码运行效果始终不符合预期:仅完全不透明的纹理可正常绘制,透明区域会被红色填充,无法实现透明效果。

疑问:使用paint.net绘制透明区域,该操作是否正确?

问题更新(附更新后代码)

目前完全透明的区域已正常显示,但半透明像素位置存在红色轮廓,需要让半透明区域也正常实现透明渲染;另外存在疑问:为何设置glClearColor的alpha参数不会产生任何效果。
半透明区域红色轮廓问题示例
当前glClearColor设置为红色、alpha值设为0,代码如下:

GL11.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);

纹理加载代码(slick-util实现)

PNGDecoder decoder = null;
try {
    decoder = new PNGDecoder(new FileInputStream(Main.projectPath + path));
} catch (FileNotFoundException e1) {
    e1.printStackTrace();
} catch (IOException e1) {
    e1.printStackTrace();
}

ByteBuffer buffer = ByteBuffer.allocateDirect(4 * decoder.getWidth() * decoder.getHeight());

try {
    decoder.decode(buffer, decoder.getWidth() * 4, PNGDecoder.RGBA);
} catch (IOException e) {
    e.printStackTrace();
}

buffer.flip();

int id = GL13.glGenTextures();

GL13.glBindTexture(GL13.GL_TEXTURE_2D, id);

GL13.glPixelStorei(GL13.GL_UNPACK_ALIGNMENT, 1);

GL13.glTexParameterf(GL13.GL_TEXTURE_2D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_NEAREST);
GL13.glTexParameterf(GL13.GL_TEXTURE_2D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_NEAREST);

width = decoder.getWidth();
height = decoder.getHeight();
GL13.glTexImage2D(GL13.GL_TEXTURE_2D, 0, GL13.GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL13.GL_RGBA, GL13.GL_UNSIGNED_BYTE, buffer);

GL30.glGenerateMipmap(GL13.GL_TEXTURE_2D);

GL13.glTexParameteri(GL13.GL_TEXTURE_2D, GL13.GL_TEXTURE_WRAP_S, GL13.GL_RGBA);
GL13.glTexParameteri(GL13.GL_TEXTURE_2D, GL13.GL_TEXTURE_WRAP_T, GL13.GL_RGBA);
GL13.glTexParameteri(GL13.GL_TEXTURE_2D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_NEAREST_MIPMAP_NEAREST);
GL13.glTexParameteri(GL13.GL_TEXTURE_2D, GL13.GL_TEXTURE_MAG_FILTER,GL13.GL_NEAREST);

this.texture = new Texture(id);
this.textureID =  id;

纹理渲染代码

public void renderMesh(Mesh mesh) {
    GL30.glBindVertexArray(mesh.getVAO());
    GL30.glEnableVertexAttribArray(0);
    GL30.glEnableVertexAttribArray(1);
    GL30.glEnableVertexAttribArray(2);
    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, mesh.getIBO());
    GL13.glActiveTexture(GL13.GL_TEXTURE0);
    GL13.glBindTexture(GL11.GL_TEXTURE_2D, mesh.getMaterial().getTextureID());
    shader.bind();
    GL11.glDrawElements(GL11.GL_TRIANGLES, mesh.getIndices().length, GL11.GL_UNSIGNED_INT, 0);
    shader.unbind();
    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
    GL30.glDisableVertexAttribArray(0);
    GL30.glDisableVertexAttribArray(1);
    GL30.glDisableVertexAttribArray(2);
    GL30.glBindVertexArray(0);
}

需求:定位上述代码中存在的错误,实现正常的透明/半透明纹理渲染效果。

补充初始化与着色器代码

初始化代码

window = GLFW.glfwCreateWindow(width, height, title, isFullscreen ? GLFW.glfwGetPrimaryMonitor() : 0, 0);

if (window == 0) {
    System.err.println("ERROR: Window wasn't created");
    return;
}

GLFWVidMode videoMode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());
windowPosX[0] = (videoMode.width() - width) / 2;
windowPosY[0] = (videoMode.height() - height) / 2;
GLFW.glfwSetWindowPos(window, windowPosX[0], windowPosY[0]);
GLFW.glfwMakeContextCurrent(window);
GL.createCapabilities();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glMatrixMode(GL11.GL_TEXTURE);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glPushMatrix();   

createCallbacks();

GLFW.glfwShowWindow(window);

GLFW.glfwSwapInterval(1);

顶点着色器代码

#version 460 core

in vec3 position;
in vec4 color;
in vec2 textureCoord;

out vec4 passColor;
out vec2 passTextureCoord;

void main() {
    gl_Position = vec4(position, 1.0);
    passColor = color;
    passTextureCoord = textureCoord;
}

片段着色器代码

#version 330 core
out vec4 FragColor;

in vec2 passTextureCoord;

uniform sampler2D texture1;

void main()
{             
    vec4 texColor = texture(texture1, passTextureCoord);
    if(texColor.a < 0.1)
        discard;
    FragColor = texColor;
}

问题修复方案

  • paint.net绘制透明区域的操作完全正确,只要导出为带alpha通道的PNG格式即可正常被OpenGL加载使用。
  • 半透明区域红色轮廓核心原因是纹理环绕参数配置错误:代码中将GL_TEXTURE_WRAP_S、GL_TEXTURE_WRAP_T的参数值错误传入了GL_RGBA,这是像素格式枚举值,不是合法的纹理环绕模式,会导致纹理边缘采样时取到错误像素,透出清除色红色。将这两行代码修改为:
GL13.glTexParameteri(GL13.GL_TEXTURE_2D, GL13.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP_TO_EDGE);
GL13.glTexParameteri(GL13.GL_TEXTURE_2D, GL13.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP_TO_EDGE);
  • glClearColor的alpha参数不生效是正常现象:默认窗口的帧缓冲区直接输出RGB值到显示器,alpha通道不会参与桌面窗口的透明混合,只有渲染到自定义离屏FBO、需要做后期混合处理时,清除色的alpha值才会产生实际作用。
  • 冗余代码清理:初始化代码中glMatrixMode、glEnable(GL_TEXTURE_2D)、glPushMatrix、glEnable(GL_ALPHA_TEST)都是旧版固定管线API,在核心模式OpenGL下没有任何作用,可以直接删除,避免产生不必要的状态干扰。
  • 半透明渲染注意事项:开启深度测试时渲染半透明物体,需要按照物体离相机从远到近的顺序绘制,否则半透明面片会被深度测试拦截,出现显示异常。

内容的提问来源于stack exchange,提问作者instance

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 07:54:24