遇到的一个shader问题,实在找不到解决方案了

我已经找了很多资料,但是对shader了解的不够深,所以这个问题一直没有找到排查点

运行环境:chrome
cocos creator版本:3.8.6
问题描述:
我写了一个shader,目的是让他进行一个动态的渲染,图片渲染的效果是水波纹的渐变彩虹色,在编辑器中,他是正常的


但是在浏览器中,他不显示,并且浏览器提示错误
[.WebGL-0x13f40af63800] GL_INVALID_OPERATION: glDrawElements: It is undefined behaviour to have a used but unbound uniform buffer.

这个报错我找了很多解决方案,都没有解决掉,实在不明白是哪里的错,我附上一个全新的项目,请各位大佬帮忙看看
NewProject.zip (34.0 KB)

@jare @Panda 引擎组的能帮忙看看吗?

纹理被动态合图了见面,点击纹理吧packable✓取消掉,经常有人问这个问题要不建议官方把合图默认关闭得了

我试过了,没有用

这个错误发生在 Cocos Creator 3.8.6 中,是因为你在 shader 中使用了 uniform block (Constant),但没有正确绑定对应的 uniform buffer。在 Cocos Creator 的 effect 系统中,uniform block 的处理需要特别注意。

解决方案

方法1:将 uniform block 转换为普通 uniforms(推荐)

修改你的 unlit-fs 部分,将 uniform block 改为普通 uniforms:

CCProgram unlit-fs %{
  precision highp float;
  #include <legacy/output>
  #include <legacy/fog-fs>

  in vec2 v_uv;
  in vec3 v_position;

  uniform sampler2D mainTexture;
  
  // 改为普通 uniforms 而不是 uniform block
  uniform vec4 mainColor;
  uniform float waveSpeed;
  uniform float waveScale;
  uniform float rainbowSpeed;
  uniform float saturation;
  uniform float brightness;

  // ... 保持其他代码不变 ...
}%

然后在 effect 的 properties 部分确保所有属性都已定义(你已经在 properties 中定义了这些属性)。

方法2:正确使用 uniform buffer(如果需要 UBO)

如果你确实需要使用 uniform buffer object (UBO),你需要:

  1. 修改 effect 文件,明确指定 binding point:
uniform Constant {
  vec4 mainColor;
  float waveSpeed;
  float waveScale;
  float rainbowSpeed;
  float saturation;
  float brightness;
} CC_BUFFER_INDEX(0);  // 指定绑定点为 0
  1. 在 TypeScript 代码中确保正确绑定 UBO:
// 在材质初始化时
const mat = this.getComponent(MeshRenderer).material;
mat.initialize({ defines: {} });

// 如果你需要手动更新 UBO
const pass = mat.passes[0];
pass.bindBuffer(0, someUniformBuffer);

额外检查

  1. 确保你的 Cocos Creator 版本完全支持 UBO(3.8.6 应该支持)
  2. 检查是否有任何拼写错误或大小写不一致
  3. 确保所有 uniforms 都在 properties 部分正确定义

为什么会出现这个错误?

在 Cocos Creator 的 effect 系统中,当你使用 uniform block 时,引擎期望你:

  1. 要么通过 properties 系统自动处理(推荐方式)
  2. 要么手动绑定 uniform buffer

你的代码使用了 uniform block 但没有遵循 Cocos Creator 的特定处理方式,导致了 OpenGL 的验证错误。

选择方法1(改为普通 uniforms)是最简单的解决方案,除非你有特定需求必须使用 UBO。

—————— DeepSeek

1赞


首先,我是小白,(希望有懂的大佬可以详细解答一下)
然后,你的effect里使用了这个chunk,咋一看这个是3d的吧,你是用3d的shader改的吗?所以v_position和v_uv可能是不正确的。
我把所有的内容都放到builtin-sprite.effect复制出来的effect下,把v_uv换成里面的uv0,把v_position那行注释掉(不然会报错),就可以在浏览器显示了
最后,这是我的eff:myeff.zip (1.7 KB)

还要勾上材质的USE TEXTURE

首先感谢你的回复,第二这两个解决方案都不行,第一个解决方案,无法通过编译
…/shader/rainbow.effect - unlit-fs:frag - 161: Error EFX2201: vector uniforms must be declared in blocks. ↓↓↓↓↓ EXPAND THIS MESSAGE FOR MORE INFO ↓↓↓↓↓
第一个方案的提示,下面是第二个方案的错误提示
[Assets] …/shader/rainbow.effect - unlit-fs:frag - 168: Error EFX2209: Block declarations must be semicolon-terminated,non-array-typed and instance-name-free. Please check your ‘Constant’ block declaration. ↓↓↓↓↓ EXPAND THIS MESSAGE FOR MORE INFO ↓↓↓↓↓

也就是说这两种写法在cc中都无法通过编译,我之前也用过这个方案,毕竟ai都是推荐这么做,但是没有办法通过,所以没找到究竟是什么地方的问题,归根结底还是对webgl的渲染不够深入了解

你好,感谢你的回复,我看了你的effect,你的意思是要这样对吧?
CCProgram sprite-fs %{
precision highp float;
#include <builtin/internal/embedded-alpha>
#include <builtin/internal/alpha-test>
//local uniforms
#include <builtin/uniforms/cc-local>
//global uniforms
#include <builtin/uniforms/cc-global>
#include <legacy/output>
#include <legacy/fog-fs>

in vec4 color;

// 这里这两个注释掉
// in vec2 v_uv;
// in vec3 v_position;

uniform sampler2D mainTexture;

uniform Constant {
vec4 mainColor;
float waveSpeed;
float waveScale;
float rainbowSpeed;
float saturation;
float brightness;
};
#if USE_TEXTURE
// 然后再编辑器里勾选USE TEXTURE,使用这里定义的uv0
in vec2 uv0;
#pragma builtin(local)
layout(set = 2, binding = 12) uniform sampler2D cc_spriteTexture;
#endif

// 彩虹色彩函数
vec3 rainbow(float t) {
float hue = mod(t, 1.0);
float r, g, b;

if (hue < 1.0/6.0) {
  r = 1.0; g = hue * 6.0; b = 0.0;
} else if (hue < 2.0/6.0) {
  r = (2.0/6.0 - hue) * 6.0; g = 1.0; b = 0.0;
} else if (hue < 3.0/6.0) {
  r = 0.0; g = 1.0; b = (hue - 2.0/6.0) * 6.0;
} else if (hue < 4.0/6.0) {
  r = 0.0; g = (4.0/6.0 - hue) * 6.0; b = 1.0;
} else if (hue < 5.0/6.0) {
  r = (hue - 4.0/6.0) * 6.0; g = 0.0; b = 1.0;
} else {
  r = 1.0; g = 0.0; b = (1.0 - hue) * 6.0;
}

return vec3(r, g, b);

}

// 水波纹函数
float wave(vec2 uv, float time) {
float wave1 = sin(uv.x * waveScale + time * waveSpeed) * 0.5 + 0.5;
float wave2 = sin(uv.y * waveScale * 0.7 + time * waveSpeed * 1.3) * 0.5 + 0.5;
float wave3 = sin((uv.x + uv.y) * waveScale * 0.5 + time * waveSpeed * 0.8) * 0.5 + 0.5;

return (wave1 + wave2 + wave3) / 3.0;

}

vec4 frag () {

// 获取原始纹理颜色
vec4 texColor = texture(mainTexture, uv0);

// 使用内置的cc_time获取时间
float time = cc_time.x;

// 计算水波纹效果
float waveValue = wave(uv0, time);

// 计算彩虹色彩
float rainbowTime = time * rainbowSpeed;
vec3 rainbowColor = rainbow(waveValue + rainbowTime * 0.1);

// 混合原始纹理和彩虹效果
vec3 finalColor = mix(texColor.rgb, rainbowColor, waveValue * 0.8);

// 应用饱和度和亮度调整
float gray2 = dot(finalColor, vec3(0.299, 0.587, 0.114));
finalColor = mix(vec3(gray2), finalColor, saturation);
finalColor *= brightness;


vec4 col = vec4(finalColor, texColor.a) * mainColor;
//CC_APPLY_FOG(col, v_position);
return CCFragOutput(col);

}
}%

是这个意思吧?我吧你的下载下来试了,网页上还是显示不出来,能不能稍微详细点呢?感谢


1.这里已经勾上了USE_TEXTURE


2.代码里也改成了这样

现在还是再编辑器中是可以正常显示,再浏览器中还是报错,我用的是你的effect,你说你再浏览器中可以看到吗??能不能吧你的简单项目传一个呢?我看看是哪里不对?

论坛有帖子说 直接拷贝官方的sprite的shader修改就可以了
我试了下确实。
试试这样呢
// 获取原始纹理颜色
vec4 texColor = vec4(1, 1, 1, 1);
#if USE_TEXTURE
texColor *= CCSampleWithAlphaSeparated(cc_spriteTexture, uv0);
#endif

那个帖子我看了,也试过了,还是不行,不知道他说的是复制的哪个?

是这个吗?
还有你说这个// 获取原始纹理颜色
vec4 texColor = vec4(1, 1, 1, 1);
#if USE_TEXTURE
texColor *= CCSampleWithAlphaSeparated(cc_spriteTexture, uv0);
#endif

是这样吗?还是一样的,网页报错,编辑器可以看到

相关的帖子都看了,包括取消纹理的packable选项都试过了,还是不行,既然编辑器可以,哪一定有哪个地方不对,就是找不到解决方案,所有的ai都问过,提供的方案都是绕来绕去,全是幻觉

用排除法最后定位是引入这两个文件导致的报错:

#include <legacy/local-batch>
#include <legacy/fog-vs>

这两个文件里面层层嵌套了很多模块,没办法给你一个个查看和排查,比较复杂的功能最好还是自己手撸,少用内置模块。

1赞

是的,排除了一圈,确实是这个原因,现在重新用默认的effect来创建,没有发现问题了


但是这也暴露出不熟悉语法和库的缺点,还需努力,感谢各位

在385可以,我当时只下载了385,不知道386改了啥不行了 :joy: