【问题标题】:Unity-How do I check if an object is seen by the Main CameraUnity-如何检查物体是否被主摄像头看到
【发布时间】:2018-03-04 00:47:55
【问题描述】:

我正在做这件事,其中一个物体在平面上移动,并且相机位于它的中心。我得到了它,所以相机会随着鼠标旋转,当主相机看到游戏对象时,它会停止。所以我使用了 onbecamevisible() 和 onbecameinvisible() 函数,但这适用于任何相机,包括场景视图。我怎样才能使物体在仅被游戏主摄像机看到时停止?

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

public class cubeMove : MonoBehaviour,moveObject
{

Camera cam;
public Transform checkedObject;

void Start()
{
    cam = GetComponent<Camera>();
}



void Update()
{
    Vector3 viewPos = cam.WorldToViewportPoint(checkedObject.position);
    if ()
        move();
}

public void move()
{
    transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);
}

}

这是我的相机脚本

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

public class Camera : MonoBehaviour {

public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
public RotationAxes axes = RotationAxes.MouseXAndY;
public float sensitivityX = 15F;
public float sensitivityY = 15F;

public float minimumX = -360F;
public float maximumX = 360F;

public float minimumY = -60F;
public float maximumY = 60F;

float rotationX = 0F;
float rotationY = 0F;

private List<float> rotArrayX = new List<float>();
float rotAverageX = 0F;

private List<float> rotArrayY = new List<float>();
float rotAverageY = 0F;

public float frameCounter = 20;

Quaternion originalRotation;

void Update()
{
    if (axes == RotationAxes.MouseXAndY)
    {
        rotAverageY = 0f;
        rotAverageX = 0f;

        rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
        rotationX += Input.GetAxis("Mouse X") * sensitivityX;

        rotArrayY.Add(rotationY);
        rotArrayX.Add(rotationX);

        if (rotArrayY.Count >= frameCounter)
        {
            rotArrayY.RemoveAt(0);
        }
        if (rotArrayX.Count >= frameCounter)
        {
            rotArrayX.RemoveAt(0);
        }

        for (int j = 0; j < rotArrayY.Count; j++)
        {
            rotAverageY += rotArrayY[j];
        }
        for (int i = 0; i < rotArrayX.Count; i++)
        {
            rotAverageX += rotArrayX[i];
        }

        rotAverageY /= rotArrayY.Count;
        rotAverageX /= rotArrayX.Count;

        rotAverageY = ClampAngle(rotAverageY, minimumY, maximumY);
        rotAverageX = ClampAngle(rotAverageX, minimumX, maximumX);

        Quaternion yQuaternion = Quaternion.AngleAxis(rotAverageY, Vector3.left);
        Quaternion xQuaternion = Quaternion.AngleAxis(rotAverageX, Vector3.up);

        transform.localRotation = originalRotation * xQuaternion * yQuaternion;
    }
    else if (axes == RotationAxes.MouseX)
    {
        rotAverageX = 0f;

        rotationX += Input.GetAxis("Mouse X") * sensitivityX;

        rotArrayX.Add(rotationX);

        if (rotArrayX.Count >= frameCounter)
        {
            rotArrayX.RemoveAt(0);
        }
        for (int i = 0; i < rotArrayX.Count; i++)
        {
            rotAverageX += rotArrayX[i];
        }
        rotAverageX /= rotArrayX.Count;

        rotAverageX = ClampAngle(rotAverageX, minimumX, maximumX);

        Quaternion xQuaternion = Quaternion.AngleAxis(rotAverageX, Vector3.up);
        transform.localRotation = originalRotation * xQuaternion;
    }
    else
    {
        rotAverageY = 0f;

        rotationY += Input.GetAxis("Mouse Y") * sensitivityY;

        rotArrayY.Add(rotationY);

        if (rotArrayY.Count >= frameCounter)
        {
            rotArrayY.RemoveAt(0);
        }
        for (int j = 0; j < rotArrayY.Count; j++)
        {
            rotAverageY += rotArrayY[j];
        }
        rotAverageY /= rotArrayY.Count;

        rotAverageY = ClampAngle(rotAverageY, minimumY, maximumY);

        Quaternion yQuaternion = Quaternion.AngleAxis(rotAverageY, Vector3.left);
        transform.localRotation = originalRotation * yQuaternion;
    }
}

void Start()
{
    Rigidbody rb = GetComponent<Rigidbody>();
    if (rb)
        rb.freezeRotation = true;
    originalRotation = transform.localRotation;
}

public static float ClampAngle(float angle, float min, float max)
{
    angle = angle % 360;
    if ((angle >= -360F) && (angle <= 360F))
    {
        if (angle < -360F)
        {
            angle += 360F;
        }
        if (angle > 360F)
        {
            angle -= 360F;
        }
    }
    return Mathf.Clamp(angle, min, max);
}

}

球体移动

public class sphereMove : MonoBehaviour,moveObject {

public float delta = 1.5f;  
public float speed = 2.0f;
private Vector3 startPos;

public UnityEngine.Camera cam;
public Transform checkedObject;
bool isMoving;

void Start()
{
    isMoving = true;
    cam = Camera.main;

}

void Update()
{

    Vector3 viewPos = cam.WorldToViewportPoint(checkedObject.position);
    if (viewPos.x > 0 && viewPos.x <= 1 && viewPos.y >= 0 && viewPos.y <= 1 && viewPos.z > 0)
        isMoving = false;
    else
        isMoving = true;

    if (isMoving)
        move();
}
public void move()
{
    Vector3 v = startPos;
    v.x += delta * Mathf.Sin(Time.time * speed);
    transform.position = v;
}

}

【问题讨论】:

  • 您是否认为您的对象在相机范围内时被相机“看到”或者它实际上在屏幕上看到(这意味着没有被任何其他项目隐藏)?
  • 现在,随便看看屏幕上的内容
  • 当一个物体在相机的视野中时,你想做一些事情,但是哪个相机?是你制作的类还是 Unity 内置的 Camera 组件?
  • 层次结构中的主摄像机我为其编写了脚本
  • @user8048595 如前所述,将Camera cam 更改为UnityEngine.Camera cam 以使其正常工作。或者更改您的相机脚本的名称。因为现在你的脚本正试图在 你的脚本中找到WorldToViewportPoint,而不是 Unity 的。

标签: c# unity3d camera gameobject


【解决方案1】:

建议的方法不适用于您的情况,因为您创建了一个名为 Camera 的类,它与 UnityCamera 组件的名称完全相同。

我建议您使用community wiki 中的方法。它非常简单易懂,可让您检查每个摄像头的可见性。


您可以为Camera 组件创建一个扩展类:

public static class CameraEx
{
    public static bool IsObjectVisible(this UnityEngine.Camera @this, Renderer renderer)
    {
        return GeometryUtility.TestPlanesAABB(GeometryUtility.CalculateFrustumPlanes(@this), renderer.bounds);
    }
}

你可以像这样从每个对象分别调用它:

// UnityEngine.Camera cam1;
// UnityEngine.Camera cam2;

void Update()
{
    bool isVisibleForCamera1 = cam1.IsObjectVisible(GetComponent<MeshRenderer>());
    bool isVisibleForCamera2 = cam2.IsObjectVisible(GetCoponent<SpriteRenderer>());
}

在这里您可以找到有关 GeometryUtility 的完整文档

【讨论】:

    【解决方案2】:

    您可以使用Camera.WorldToViewport 函数,使用您的主相机调用它并在参数中提供您正在检查的对象的位置。如果结果向量的 x 和 y 坐标值介于 0 和 1 之间,并且 z 值大于 0,则意味着您的相机可以看到对象的中心。

    UnityEngine.Camera cam;
    bool isMoving;
    
    void Start()
    {
        cam = UnityEngine.Camera.main;
        isMoving = true;
    }
    
    void Update()
    {
        Vector3 viewPos = cam.WorldToViewportPoint(checkedObject.position);
        if (viewPos.x >= 0 && viewPos.x <= 1 && viewPos.y >= 0 && viewPos.y <= 1 && viewPos.z > 0)
        {
            // Your object is in the range of the camera, you can apply your behaviour
            isMoving = false;
        }
        else
            isMoving = true;
    
        if(isMoving)
            Move();
    }
    

    【讨论】:

    • 但是另一个物体可以用这个挡住视线,相机仍然会“看到”它
    • 出现错误提示相机不包含 WorldToViewportPoint 的定义。
    • @user8048595 你有一个叫Camera的脚本吗?如果是这种情况,您的程序将使用该脚本而不是 UnityEngine.Camera 脚本,因此您将无法找到该函数。如果是这种情况,只需将 Camera 声明为 UnityEngine.Camera。
    • Remove ",moveObject" 放在MonoBehaviour 之后我什至不知道你为什么在那里。另外,不要将您的脚本命名为 Camera。在编辑器和 Visual Studio 中重命名它。
    • 我在练习策略模式。现在不重要
    猜你喜欢
    • 2013-08-12
    • 2010-12-28
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    • 2021-01-27
    • 1970-01-01
    • 2023-02-26
    • 1970-01-01
    相关资源
    最近更新 更多