不再看时停止勾勒对象?

Stop outlining object when no longer looking at it?

我正在尝试制作一个拾取系统,我认为在您查看它时在它周围画一个轮廓会很酷。我面临的问题是当您不再查看我需要禁用轮廓的对象时。我最终做了一个奇怪的解决方案,并希望得到一些帮助来改进它。

public class PlayerCamera : MonoBehaviour
{
    public Transform playerBody;
    public Transform cameraHolder;

    public float sensitivity;
    public float currentY;

    void Update()
    {
        MoveCamera();
        LookingAtObject();
    }

    Outline objectOutline;
    void LookingAtObject()
    {
        if(Physics.Raycast(cameraHolder.transform.position, cameraHolder.transform.forward, out var hit, Mathf.Infinity))
        {
            var obj = hit.collider.gameObject;
            var outline = obj.GetComponent<Outline>();

            if (obj && outline)
            {
                objectOutline = hit.transform.GetComponent<Outline>();
                if (objectOutline)
                    objectOutline.OutlineWidth = 7;
            }
            else if (objectOutline)
                objectOutline.OutlineWidth = 0;
        }   
    }
}

您可以将轮廓对象存储在变量中,每当您击中不同的轮廓对象或什么也没击中时,将轮廓设置回零。

Outline objectOutline;

void LookingAtObject()
{
    if (Physics.Raycast(...))
    {
        var outline = hit.collider.GetComponent<Outline>();

        // Make sure the hit object is not the same one we already outlined
        //
        if (outline != objectOutline)
        {
            // Remove the outline from our previously viewed object
            //
            if (objectOutline != null)
            {
                objectOutline.OutlineWidth = 0;
            }
            
            // Store the new outline object
            //
            objectOutline = outline;

            // Since outline could be null, we need to check null before outlining
            //
            if (objectOutline != null)
            {
                objectOutline.OutlineWidth = 7;
            }
        }
    }

    // If we have an object we outlined and we didnt hit anything, 
    // remove the outline and reset the variable
    //
    else if (objectOutline != null)
    {
        objectOutline.OutlineWidth = 0;
        objectOutline = null;
    }
}

你需要两个事件来解决这个问题。输入帧和光线输出帧。此代码通过记录前一个 raycastHit 帧并将其与当前命中进行比较来检测哪个 raycast 事件,并相应地设置轮廓。

private RaycastHit lastHit;
void Update()
{
    var ray = Camera.main.ScreenPointToRay(Input.mousePosition);

    Physics.Raycast(ray, out var hit);
    //Physics.Raycast(cameraHolder.transform.position, cameraHolder.transform.forward, out var hit, Mathf.Infinity);

    if (hit.transform != lastHit.transform)
    {
        if (hit.transform) // when raycast Begin
        {
            var outline = hit.transform.GetComponent<Outline>();

            outline.OutlineWidth = 7;
        }
        else if (lastHit.transform) // when raycast out
        {
            var outline = lastHit.transform.GetComponent<Outline>();
            outline.OutlineWidth = 0;
        }
    }
    
    lastHit = hit;
}

Hint: I commented on your raycast code for testing. If you want to change the raycast code as before.