基于LibGDX Shader实现视差效果遇白屏问题求助
解决直接用ShaderProgram渲染Mesh实现视差效果的白屏问题
我当年第一次脱离SpriteBatch直接用Shader渲染Mesh的时候也踩过这些坑,白屏简直是家常便饭。结合你的情况,大概率是遗漏了直接渲染Mesh时的几个基础要点,咱们一步步排查:
1. 先确认Shader本身没编译/链接错误
很多时候白屏的根源是Shader代码写错了,但你没察觉。一定要在创建ShaderProgram后做检查:
parallaxShader = new ShaderProgram(vertexShaderCode, fragmentShaderCode); if (!parallaxShader.isCompiled()) { Gdx.app.error("Shader", "Vertex shader compile error: " + parallaxShader.getVertexShaderLog()); } if (!parallaxShader.isLinked()) { Gdx.app.error("Shader", "Program link error: " + parallaxShader.getProgramLog()); }
要是日志里有错误,先把Shader的语法问题解决,比如变量名不匹配、GLSL版本不兼容(比如你用了GLSL 300但LibGDX默认是100)。
2. 确保全屏Quad的顶点数据和Shader属性对应
视差效果需要顶点的UV坐标来采样纹理,所以你的全屏Mesh必须包含位置和UV这两个顶点属性,而且要和Shader里的attribute变量名完全一致。比如Shader里写的是attribute vec2 a_position和attribute vec2 a_uv,那创建Mesh时就要对应:
private Mesh createFullscreenQuad() { Mesh mesh = new Mesh(true, 4, 6, new VertexAttribute(VertexAttributes.Usage.Position, 2, "a_position"), new VertexAttribute(VertexAttributes.Usage.TextureCoordinates, 2, "a_uv")); // 顶点数据:x,y, u,v float[] vertices = { -1f, -1f, 0f, 0f, 1f, -1f, 1f, 0f, 1f, 1f, 1f, 1f, -1f, 1f, 0f, 1f }; short[] indices = {0, 1, 2, 0, 2, 3}; // 用三角面渲染全屏 mesh.setVertices(vertices); mesh.setIndices(indices); return mesh; }
要是顶点属性的名字或者分量数和Shader不匹配,Shader就拿不到正确的数据,自然会显示白屏。
3. 渲染时的Shader绑定与Uniform设置不能漏
脱离SpriteBatch后,所有的Uniform都得手动设置,包括纹理:
public void render() { // 先清屏,不然可能残留上一帧的内容 Gdx.gl.glClearColor(0f, 0f, 0f, 1f); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // 启用Shader parallaxShader.begin(); // 设置纹理Uniform:注意纹理单元要对应 parallaxShader.setUniformi("u_mainTexture", 0); Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0); yourMainTexture.bind(); // 你的视差基础纹理 // 视差效果需要的深度纹理也要设置 parallaxShader.setUniformi("u_depthTexture", 1); Gdx.gl.glActiveTexture(GL20.GL_TEXTURE1); yourDepthTexture.bind(); // 你的深度图纹理 // 其他视差参数,比如位移强度、视角位置等 parallaxShader.setUniformf("u_parallaxStrength", 0.15f); parallaxShader.setUniformf("u_viewPos", camera.position.x, camera.position.y); // 渲染Mesh:注意图元类型要和你的索引/顶点数据匹配 fullscreenQuad.render(parallaxShader, GL20.GL_TRIANGLES); // 一定要关闭Shader parallaxShader.end(); }
这里最容易忘的是纹理单元的激活,比如你设置了u_depthTexture对应单元1,但没调用glActiveTexture(GL_TEXTURE1)就绑定纹理,Shader就会采样到错误的纹理(甚至是空的),导致白屏。
4. 检查OpenGL状态设置
有时候其他代码修改了GL状态,影响渲染:
- 如果你的视差效果不需要深度测试,可以关闭:
Gdx.gl.glDisable(GL20.GL_DEPTH_TEST); - 如果纹理带透明,要开启混合:
Gdx.gl.glEnable(GL20.GL_BLEND); Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); - 确保纹理的Wrap模式和过滤设置正确,比如重复纹理要设置
yourTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
最后检查Shader逻辑
如果上面都没问题,那可能是视差计算的逻辑导致全白:
- 比如片元Shader里深度采样的值不对,导致位移后的UV超出纹理范围,采样到透明或白色;
- 或者视差强度设置过大,导致UV完全偏离纹理;
- 可以先把视差逻辑注释掉,直接采样基础纹理,如果能显示,就说明视差计算部分有问题。
内容的提问来源于stack exchange,提问作者Eugene S
相关产品推荐
相关产品推荐

