3.8三平面映射贴图,用于解决缩放模型导致的贴图拉伸问题

制作过程中突发奇想,让AI帮忙写的,也是把论坛当书签用了

CCEffect %{
  techniques:
  - name: opaque
    passes:
    - vert: triplanar-vs:vert
      frag: triplanar-fs:frag
      depthStencilState:
        depthTest: true
        depthWrite: true
      blendState:
        targets:
        - blend: false
      properties:
        mainTexture: { value: white }
        tiling: { value: [4.0, 4.0, 4.0, 1.0], editor: { type: vector } }
        sharpness: { value: 4.0, editor: { slider: true, min: 1, max: 10 } }
        offset: { value: [0.0, 0.0, 0.0, 0.0], editor: { type: vector } }

  - name: transparent
    passes:
    - vert: triplanar-vs:vert
      frag: triplanar-fs:frag
      depthStencilState:
        depthTest: true
        depthWrite: false
      blendState:
        targets:
        - blend: true
          blendSrc: src_alpha
          blendDst: one_minus_src_alpha
      properties:
        mainTexture: { value: white }
        tiling: { value: [4.0, 4.0, 4.0, 1.0] }
        sharpness: { value: 4.0 }
        offset: { value: [0.0, 0.0, 0.0, 0.0] }
}%

CCProgram triplanar-vs %{
  precision highp float;
  #include <cc-global>
  #include <cc-local>

  in vec3 a_position;
  in vec3 a_normal;

  out vec3 v_position;
  out vec3 v_normal;

  vec4 vert () {
    // 计算世界空间位置和法线
    vec4 worldPos = cc_matWorld * vec4(a_position, 1.0);
    v_position = worldPos.xyz;
    v_normal = normalize((cc_matWorldIT * vec4(a_normal, 0.0)).xyz);

    return cc_matViewProj * worldPos;
  }
}%

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

  uniform sampler2D mainTexture;

  // 关键修正:调整UBO内变量的声明顺序,将所有的vec4类型变量放在一起
  uniform TriplanarParams {
    vec4 tiling;    // vec4 类型变量
    vec4 offset;    // vec4 类型变量,现在紧挨着另一个vec4声明
    float sharpness; // float 类型变量,现在被移到了所有vec4之后
  };

  in vec3 v_position;
  in vec3 v_normal;

  vec4 frag () {
    // 使用世界坐标减去偏移量,确保贴图跟随物体移动
    vec3 worldPosWithOffset = v_position - offset.xyz;
    
    // 计算三个平面的纹理坐标(基于偏移后的世界坐标)
    vec2 uvXZ = worldPosWithOffset.xz / tiling.x;
    vec2 uvXY = worldPosWithOffset.xy / tiling.y;
    vec2 uvZY = worldPosWithOffset.zy / tiling.z;

    // 采样纹理
    vec4 colXZ = texture(mainTexture, uvXZ);
    vec4 colXY = texture(mainTexture, uvXY);
    vec4 colZY = texture(mainTexture, uvZY);

    // 基于法线计算混合权重
    vec3 weights = pow(abs(v_normal), vec3(sharpness));
    weights = weights / (weights.x + weights.y + weights.z);

    // 混合颜色
    vec4 finalColor = colXZ * weights.y + colXY * weights.z + colZY * weights.x;

    return CCFragOutput(finalColor);
  }
}%

如果需要模型在移动的过程中贴图跟着模型移动而不是停留在原地,可以使用此方法

	protected update(deltaTime: number) {
		// 获取物体世界坐标
		const worldPos = this.node.worldPosition;
		// 设置材质的offset参数
		if (this.material) {
			this.material.setProperty("offset", new Vec4(worldPos.x, worldPos.y, worldPos.z, 0));
		}
	}
1赞