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

Unity动态设置Shader的_Fill属性后,实例化水体对象材质值未更新问题求助

问题分析与解决方案

看起来你踩了Unity预制体和材质引用的常见坑!核心问题在于你先修改了预制体的材质,再实例化对象,而且可能对Unity中material和sharedMaterial的区别理解有误。让我一步步帮你理清:

1. 你的代码为什么不生效?

你当前的逻辑是:修改waterPfGameObject(预制体)的材质,然后实例化这个预制体。但这里有两个关键问题:

  • 直接修改预制体的属性会导致后续循环覆盖前面的设置(比如第一个循环把预制体材质改成_Fill=0.5,第二个循环改成0.3,所有实例最终都会用最后一次的设置)。
  • 你检查sharedMaterial的方式不对:sharedMaterial指向的是预制体共享的原始材质,而你给预制体赋值的是material(会创建一个材质实例),所以这个检查结果并不能反映实例化后对象的真实材质状态。

2. 正确的实现方式

你应该先实例化水体对象,再对每个实例单独设置材质,而不是去修改预制体本身。调整代码如下:

修改循环逻辑

foreach (var cistern in _cisInfo) //生成水箱
{
    //...计算下一个水箱和水体的生成位置、缩放比例及填充值
    Instantiate(cisternPrefabGameObject, _upcomingSpawnPosition, _rotationToSpawn);
    
    // 先实例化水体对象(基于原始预制体)
    GameObject water = Instantiate(waterPfGameObject, _upcomingWaterSpawnPosition, _rotationToSpawn);
    // 再对这个实例设置水位材质
    LiquifyObject(water, fillValue);
}

修正LiquifyObject函数

去掉不必要的ref参数(你不需要修改GameObject的引用,只需要修改它的组件),确保操作的是实例的MeshRenderer:

void LiquifyObject(GameObject waterInstance, float fillValue)
{
    MeshRenderer renderer = waterInstance.GetComponent<MeshRenderer>();
    if (renderer == null)
    {
        Debug.LogError("水体对象缺少MeshRenderer组件!");
        return;
    }

    // 创建一个独立的材质实例(基于你的waterShader)
    Material customMat = new Material(waterShader);
    customMat.SetFloat("_Fill", fillValue);
    
    // 赋值给实例的material(不是sharedMaterial,避免共享材质被修改)
    renderer.material = customMat;
}

3. 额外的排查点

如果调整后还是不生效,检查你的Shader是否正确配置:

  • 确保_Fill属性在Shader的Properties块中声明:
    Properties
    {
        // 其他属性...
        _Fill ("水位高度", Float) = -0.25
    }
    
  • 确保在Shader的CG代码块中声明了该变量,这样才能在着色器中访问:
    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
    
        // 必须声明这个变量才能接收SetFloat的值
        float _Fill;
    
        // 你的顶点/片段着色器代码...
        ENDCG
    }
    

4. 为什么原来的检查结果看起来正确?

你用sharedMaterial.GetFloat("_Fill")检查的是预制体的共享材质,而你给预制体赋值的是material(会创建一个独立的材质实例),所以这个检查结果其实是原始预制体的默认值,而不是你设置的新材质值。正确的检查方式应该是在设置完renderer.material后,用renderer.material.GetFloat("_Fill")来验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 18:29:07