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

Unity中如何修改球体碰撞器接触对象区域的材质颜色?

实现Unity中碰撞接触区域局部变色的方法

方法一:自定义Shader + 碰撞位置传递

这是实现实时局部高亮最常用的方案,通过Shader在片元阶段判断像素是否处于碰撞范围内,动态混合颜色。

  • 步骤1:创建自定义Shader
    新建一个Unlit Shader,替换成以下代码,添加碰撞位置、范围、高亮色等可控属性:

    Properties {
        _MainTex ("基础纹理", 2D) = "white" {}
        _CollisionPos ("碰撞中心(世界坐标)", Vector) = (0,0,0,0)
        _CollisionRadius ("碰撞影响半径", Float) = 1.0
        _HighlightColor ("高亮颜色", Color) = (1,0,0,1)
        _HighlightStrength ("高亮强度", Range(0,1)) = 1.0
    }
    
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 100
    
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
    
            #include "UnityCG.cginc"
    
            struct appdata {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
    
            struct v2f {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 worldPos : TEXCOORD1;
            };
    
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float3 _CollisionPos;
            float _CollisionRadius;
            float4 _HighlightColor;
            float _HighlightStrength;
    
            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                return o;
            }
    
            fixed4 frag (v2f i) : SV_Target {
                // 计算当前像素世界位置到碰撞中心的距离
                float dist = length(i.worldPos - _CollisionPos);
                // 平滑过渡高亮范围,避免生硬边缘
                float highlight = smoothstep(_CollisionRadius, _CollisionRadius - 0.1f, dist);
                // 混合原纹理色与高亮色
                fixed4 baseCol = tex2D(_MainTex, i.uv);
                baseCol = lerp(baseCol, _HighlightColor, highlight * _HighlightStrength);
                return baseCol;
            }
            ENDCG
        }
    }
    

    将该Shader赋值给Cube的材质,可在Inspector面板调整高亮色为红色,设置合适的碰撞半径。

  • 步骤2:编写碰撞检测脚本
    在Sphere对象上挂载以下脚本,实时将碰撞信息传递给Cube的Shader:

    using UnityEngine;
    
    public class CollisionMarker : MonoBehaviour
    {
        public float collisionRadius = 1.0f;
        public Material cubeMaterial;
    
        private void OnTriggerStay(Collider other)
        {
            if (other.CompareTag("Cube"))
            {
                // 传递Sphere中心作为碰撞范围中心(也可改用实际碰撞接触点)
                cubeMaterial.SetVector("_CollisionPos", transform.position);
                cubeMaterial.SetFloat("_CollisionRadius", collisionRadius);
            }
        }
    
        private void OnTriggerExit(Collider other)
        {
            if (other.CompareTag("Cube"))
            {
                // 退出碰撞后重置参数,恢复Cube原颜色
                cubeMaterial.SetFloat("_CollisionRadius", 0);
            }
        }
    }
    

    注意:将Sphere的Collider设为Trigger,给Cube添加普通Collider并打上"Cube"标签,脚本中cubeMaterial拖入Cube的材质。

方法二:RenderTexture绘制碰撞痕迹

如果需要实现类似“涂色”的持久化碰撞痕迹效果,可采用RenderTexture作为Cube的纹理,实时绘制碰撞区域:

  • 步骤1:配置RenderTexture
    创建一个RenderTexture(分辨率建议512x512以上),将其赋值给Cube材质的_MainTex属性。

  • 步骤2:编写绘制脚本
    在Sphere上挂载以下脚本,碰撞时在RenderTexture上绘制红色区域:

    using UnityEngine;
    
    public class RTPaintMarker : MonoBehaviour
    {
        public RenderTexture targetRT;
        public Material brushMat; // 使用纯色红色的材质作为画笔
        public float brushSize = 0.2f;
    
        private void OnTriggerStay(Collider other)
        {
            if (other.CompareTag("Cube"))
            {
                // 将Sphere世界坐标转换为Cube本地坐标,再转成UV值
                Vector3 localPos = other.transform.InverseTransformPoint(transform.position);
                Vector2 uv = new Vector2(localPos.x + 0.5f, localPos.y + 0.5f);
                // 适配Cube缩放,调整画笔大小
                float adjustedSize = brushSize / other.transform.localScale.x;
                Rect drawRect = new Rect(uv.x - adjustedSize/2, uv.y - adjustedSize/2, adjustedSize, adjustedSize);
                
                // 绘制到RenderTexture
                RenderTexture.active = targetRT;
                Graphics.DrawTexture(drawRect, brushMat);
                RenderTexture.active = null;
            }
        }
    }
    

    该方法支持多次碰撞叠加颜色痕迹,适合需要保留交互记录的场景。

优化建议

  • 若需要更精确的碰撞接触点,可改用OnCollisionStay方法,通过Collision.contacts获取实际接触位置,替换脚本中的Sphere中心坐标。
  • 方法一的Shader可扩展为支持多碰撞点,通过数组存储多个位置,在片元着色器中循环判断距离。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 16:52:42