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

如何通过相机射线检测单独逐个修改区域对象颜色?

双相机扫描单区域渐变变红问题解决

问题根源

  1. 原ChangeColour协程遍历所有zones材质数组,调用一次就会把所有区域变红,没有针对射线命中的单个对象处理
  2. 射线检测后未提取命中对象的对应材质,直接操作整个材质数组
  3. Update每帧调用StartFadeToRed,重复启动多个协程导致颜色逻辑混乱
  4. 第一人称相机的射线检测未判断命中对象是否为"Zone"标签,可能误触发非目标对象

修正后的完整代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ZoneController : MonoBehaviour
{
    private Camera frontViewCamera;
    private Camera topDownCamera;

    public float speed = 0.05f;
    private Color startColor = Color.white;
    private Color endColor = Color.red;

    // 防止重复启动渐变协程
    private bool isFading = false;

    void Start()
    {
        frontViewCamera = GameObject.FindGameObjectWithTag("FrontFaceCam").GetComponent<Camera>();
        topDownCamera = GameObject.FindGameObjectWithTag("TopDownCam").GetComponent<Camera>();

        // 初始化所有Zone对象为白色
        foreach (var zoneRenderer in FindObjectsOfType<MeshRenderer>())
        {
            if (zoneRenderer.CompareTag("Zone"))
            {
                zoneRenderer.material.color = startColor;
            }
        }
    }

    /// <summary>
    /// 仅对目标材质执行红变渐变
    /// </summary>
    /// <param name="targetMaterial">要渐变的材质</param>
    private IEnumerator ChangeColour(Material targetMaterial)
    {
        isFading = true;
        float tick = 0f;
        // 重置目标材质初始颜色为白色
        targetMaterial.color = startColor;

        // 用tick进度判断,避免浮点数精度导致循环无法终止
        while (tick < 1f)
        {
            tick += Time.deltaTime * speed;
            targetMaterial.color = Color.Lerp(startColor, endColor, tick);
            yield return null;
        }
        // 确保最终颜色准确设置为红色
        targetMaterial.color = endColor;
        isFading = false;
    }

    private void StartFadeToRed()
    {
        // 已有渐变在运行时直接返回,避免冲突
        if (isFading) return;

        Camera activeCamera = frontViewCamera.enabled ? frontViewCamera : topDownCamera;
        Ray ray = activeCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));

        if (Physics.Raycast(ray, out RaycastHit hit) && hit.collider.CompareTag("Zone"))
        {
            Debug.DrawRay(ray.origin, ray.direction * 10, Color.red);
            // 获取命中对象的MeshRenderer材质
            Material targetMat = hit.collider.GetComponent<MeshRenderer>().material;
            StartCoroutine(ChangeColour(targetMat));
        }
    }

    void Update()
    {
        StartFadeToRed();
    }
}

关键修改说明

  • 移除静态材质数组:改为通过Zone标签动态查找所有目标对象,无需手动维护数组,扩展性更强;如果需要固定目标集合,可保留zones数组但修改协程逻辑
  • 协程改为单目标处理:ChangeColour接收单个材质参数,只对射线命中的对象执行渐变,解决所有区域同时变红的问题
  • 添加渐变锁:isFading变量避免Update每帧重复启动协程,防止多个渐变逻辑冲突
  • 统一相机处理逻辑:自动识别当前激活的相机,简化射线检测代码,同时确保两种相机都只响应Zone标签对象
  • 优化渐变终止条件:用tick < 1f替代颜色相等判断,规避浮点数精度误差导致的循环死锁

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 16:50:37