3.8.7的Effect不同平台渲染结果不同问题

背景:目的是想要在屏幕中展现一个球并且自转,球的表面模拟地球,噪声图
effect的内容是

Effect

// Effect Syntax Guide: https://docs.cocos.com/creator/manual/zh/shader/index.html

CCEffect %{
techniques:

  • name: opaque
    passes:
    • vert: vs:vert
      frag: unlit-fs:frag
      properties: &props
      mainColor: { value: [0.2, 0.4, 0.9, 1], editor: { type: color } }
      params: { value: [0.5, 0, 1, 0.6] }
      planetType : {value: [0.2, 0]}
      lightDir: { value: [0.5, 0.5, 1, 0] }
      blendState:
      targets:
      • blend: true
        blendSrc: src_alpha
        blendDst: one_minus_src_alpha
        blendSrcAlpha: src_alpha
        blendDstAlpha: one_minus_src_alpha
  • name: transparent
    passes:
    • vert: general-vs:vert # builtin header
      frag: unlit-fs:frag
      blendState:
      targets:
      • blend: true
        blendSrc: src_alpha
        blendDst: one_minus_src_alpha
        blendSrcAlpha: src_alpha
        blendDstAlpha: one_minus_src_alpha
        properties: *props
        }%

CCProgram vs %{
precision highp float;
#include

in vec3 a_position;
in vec2 a_texCoord;

// 传给片元的 uv ([0,1])
out vec2 v_uv;
// 局部位置
out vec3 v_pos;

vec4 vert() {
v_uv = a_texCoord;
v_pos = a_position;
return cc_matViewProj * vec4(a_position, 1.0);
}
}%

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

in vec2 v_uv;
in vec3 v_pos;

uniform Constant {
// rgba
vec4 mainColor;
// xyz = 光方向, w unused
vec4 lightDir;

// params.x = seed, params.y = scale, params.z = rim intensity, params.w = speed
vec4 params;
vec2 planetType;

};

// 简单哈希 + 平滑噪声(和你原来类似)

float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
}
float noise(vec2 p) {
vec2 i = floor§;
vec2 f = fract§;
float a = hash(i);
float b = hash(i + vec2(1.0, 0.0));
float c = hash(i + vec2(0.0, 1.0));
float d = hash(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

// 2D 分形噪声(多频)
float fbm(vec2 p) {
float v = 0.0;
float amp = 0.5;
float freq = 1.0;
for (int i = 0; i < 5; i++) {
v += amp * noise(p * freq);
freq *= 2.0;
amp *= 0.5;
}
return v;
}

// 绕 Y 轴旋转法线
mat3 rotY(float a) {
float s = sin(a);
float c = cos(a);
return mat3(
c, 0.0, -s,
0.0, 1.0, 0.0,
s, 0.0, c
);
}

vec4 frag() {
// 将传入 uv 从 [0,1] -> [-1,1]
vec2 uv = v_uv * 2.0 - 1.0;

// 圆内判断:如果超出圆形范围,就丢弃或透明
float r = length(uv);
if (r > 0.9) {
  // 返回透明(确保材质混合开启),或者返回背景色(不透明)
  // return vec4(0.0); // 如果想完全透明
  // 这里用 alpha = 0 保证不会看到方块(编辑器/运行时需确保混合模式支持透明)
  return vec4(0.0);
  // return vec4(0.0, 0.0, 0.0, 0.0);
}

// 构造球面上的法线(未旋转)
float z = sqrt(max(0.0, 1.0 - r * r));
vec3 n = normalize(vec3(uv.x, uv.y, z)); // 原始球面法线
float seed = params.x;

// 计算绕 Y 轴的旋转角(左右自转),使用传下来的时间
float rotSpeed = params.w; // 可调:正为向右看似向左转
float angle = cc_time.x * rotSpeed + seed * 10.0; // params.x 作为 seed/偏移
vec3 n_rot = rotY(angle) * n; // 旋转后的法线

// 将旋转后的法线转换成经纬度坐标 (spherical UV)
// lon: atan2(x, z) -> [-PI, PI], map to [0,1]
// lat: asin(y) -> [-PI/2, PI/2], map to [0,1]
float lon = atan(n_rot.x, n_rot.z);           // 注意参数顺序,保证从 -PI..PI
float lat = asin(clamp(n_rot.y, -1.0, 1.0)); // -PI/2..PI/2

vec2 sphUV = vec2(lon / (2.0 * 3.14159265) + 0.5, lat / 3.14159265 + 0.5);

// 用球面 UV 做噪声采样(这样地形会随经度滚动)
float baseScale = mix(2.0, 6.0, clamp(params.y, 0.0, 1.0)); // 控制地形总体尺度
float terrain = fbm(sphUV * baseScale * 3.0);
float detail  = fbm(sphUV * baseScale * 20.0) * 0.12;
float height = terrain * 0.8 + detail;

// ----------- 新增气候参数 -----------
float latitude = abs(sphUV.y - 0.5) * 2.0;
float temperature = 1.0 - latitude - height * 0.3;
float humidity = fbm(sphUV * baseScale * 1.5 + seed * 3.14);

// ----------- 根据 planetType 调整全球气候 -----------
float type = planetType.x;
temperature = mix(temperature, 1.0 - type, 0.6); // planetType 越大,温度偏高
humidity    = mix(humidity, 1.0 - abs(type - 0.3) * 2.0, 0.5); // 沙漠更干、森林更湿
float volcanicBias = smoothstep(0.6, 0.8, type);
float volcanic = fbm(sphUV * 8.0 + seed * 7.77) * (0.5 + volcanicBias * 1.5);

// ----------- 地貌分类逻辑 -----------
vec3 color;

if (height < 0.42) {
color = vec3(0.02, 0.12, 0.4); // 深海
}
else if (height < 0.45) {
    color = vec3(0.05, 0.25, 0.6); // 浅海
}
else {
    if (type < 0.15) {
        // 冰原星球主色调
        if (height > 0.5)
            color = mix(vec3(0.9, 0.95, 1.0), vec3(0.7, 0.8, 0.9), height);
        else
            color = vec3(0.6, 0.7, 0.8);
    }
    else if (type < 0.35) {
        // 森林星球
        color = mix(vec3(0.05, 0.4, 0.1), vec3(0.3, 0.5, 0.2), height);
    }
    else if (type < 0.6) {
        // 沙漠星球
        color = mix(vec3(0.9, 0.8, 0.5), vec3(0.7, 0.6, 0.3), height);
    }
    else if (type < 0.85) {
        // 火山星球
        float lava = smoothstep(0.65, 0.8, volcanic);
        color = mix(vec3(0.2, 0.1, 0.05), vec3(0.8, 0.2, 0.05), lava);
    }
    else {
        // 海洋星球
        color = mix(vec3(0.02, 0.3, 0.6), vec3(0.1, 0.6, 0.7), height);
    }
}

// 平滑过渡,避免硬边界
color = pow(color, vec3(1.1)); // 微调亮度对比

// 大气边缘(rim)效果(可增添立体感)
float rim = pow(1.0 - max(0.0, dot(n_rot, vec3(0.0, 0.0, 1.0))), 2.0);
color += rim * params.z * 0.3;

// alpha:圆形边缘平滑
float alpha = smoothstep(1.0, 0.98, 1.0 - r); // 稍微调整边缘宽度

// 输出乘以主颜色
vec3 outColor = color * mainColor.rgb;
float outAlpha = alpha * mainColor.a;

return vec4(outColor, outAlpha);

}
}%

预览:

模拟器展现正常,但是web端看不见,而且js动态加载(复制节点再添加)也没有效果

整个demo是demo1.zip (3.4 MB)

有无大佬联系,可有偿

又是web端看不见,是不是把动态合图开了

动态合图 | Cocos Creator

web会默认开启

一般这种情况都是因为材质所使用到的图片被设置为 packable 了,需要取消勾选。
具体原因见: 4.3 动态纹理合批的影响

图片这个我选的系统图片,显示的是effect生成的噪声图

在脚本文件,类的作用域外面指明禁用动态合图就行了。

脚本导入阶段就能扫描到并执行禁止动态合图,动态合图会导致资源在内存中顶点偏移。uv坐标全部对应不上。

大佬,你是锇滴神,谢谢

谢谢大佬 :handshake:

你的 SpriteFrame 用的是内置的图片,内置图片都是启用 packable 的,如果你并不需要用到它可以换成自己的图片并关闭 packable

1赞