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
相关产品推荐
相关产品推荐

