基于体素场景的摄像机穿模处理

基于上一篇一种基于体素的射线检测
使用射线处理第三人称摄像头穿模问题

基于体素的第三人称摄像机拉近简单处理

摄像机移动至碰撞点处

简单的从角色身上发射一条射线到摄像机,中途遇到碰撞就把摄像机移动至该碰撞点

    public void UpdateDistance(float defaultDistance)
    {
        Vector3 from = player.position;
        Vector3 to = cameraRoot.position;
        Vector3 forward = (to - from).normalized;

        Debug.DrawLine(from, to, Color.red);

        if (BlockPhysics.Raycast(BlockWorld.CurWorld, from, forward, (to - from).magnitude, out hitInfo))
        {
            distance = cameraRoot.InverseTransformPoint(hitInfo.point).z;
        }
        else
        {
            distance = 0;
        }

        curDistance = Mathf.Lerp(curDistance, distance, speed * Time.fixedDeltaTime);
        curDistance = Mathf.Clamp(curDistance, 0, defaultDistance);
        transform.localPosition = Vector3.forward * curDistance;
    }

可以明显看到摄像机一半在外面,一半在墙里面体验感非常差
基于体素场景的摄像机穿模处理_第1张图片
可以通过检测摄像机近裁剪面的4个顶点是否在方块或体素内
如果有一个顶点产生碰撞,那么就把摄像机向前移动

    float GetDistance(float distance)
    {
        int i = 0;
        int loop = 666;
        virtualCamera.localPosition = Vector3.forward * distance;
        var wrold = BlockWorld.CurWorld;
        while (loop-- > 0)
        {
            UpdateNearClipPlane();
            for (i = 0; i < 4; i++)
            {
                if (wrold.HasBlockCollider(Vector3Int.RoundToInt(corners[i])) || wrold.HasVoxelCollider(corners[i]))
                {
                    break;
                }
            }
            if (i == 4)
                break;
            distance += 0.25f;
            virtualCamera.localPosition = Vector3.forward * distance;
        }

        return distance;
    }

通过前移规避穿模问题
基于体素场景的摄像机穿模处理_第2张图片
当然如果夹角非常小或者在一个狭窄的通道内,并不推荐拉近摄像头。
基于体素场景的摄像机穿模处理_第3张图片
因为拉近已经不能解决问题。这种情况下推荐摄像机观察中心直接固定在方块中心。
从方块中心出发就不用担心角色过于靠近墙壁导致的拉近修复无效

完整代码

using UnityEngine;

public class CameraOffset : MonoBehaviour
{
    public float minSpeed = 5;
    public float maxSpeed = 50;
    Transform cameraRoot;
    Transform player;
    float distance;
    float curDistance;
    RaycastHit hitInfo;

    Camera mainCamera;
    Transform virtualCamera;
    Vector3[] corners = new Vector3[4];
    float width;
    float height;
    float speed ;
    private void Start()
    {
        cameraRoot = transform.parent;
        player = GameObject.FindGameObjectWithTag("Player").transform;
        player = player.transform.Find("cameraFollow");
        mainCamera = Camera.main;
        virtualCamera = new GameObject("virtualCamera").transform;
        virtualCamera.transform.SetParent(mainCamera.transform.parent);
        virtualCamera.localPosition = Vector3.zero;
        virtualCamera.localRotation = Quaternion.identity;
        virtualCamera.localScale = Vector3.zero;

        float halfFOV = (mainCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad;
        float aspect = mainCamera.aspect;

        height = mainCamera.nearClipPlane * Mathf.Tan(halfFOV);
        width = height * aspect;
        speed = maxSpeed;
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(hitInfo.point, 0.1f);
    }

    public void UpdateDistance(float defaultDistance)
    {
        Vector3 from = player.position;
        Vector3 to = cameraRoot.position;
        Vector3 forward = (to - from).normalized;

        Debug.DrawLine(from, to, Color.red);

        if (BlockPhysics.Raycast(BlockWorld.CurWorld, from, forward, (to - from).magnitude, out hitInfo))
        {
            distance = GetDistance(cameraRoot.InverseTransformPoint(hitInfo.point).z);
        }
        else
        {
            distance = 0;
        }

        if(distance > curDistance)
            speed = maxSpeed;
        else
            speed = minSpeed;

        curDistance = Mathf.Lerp(curDistance, distance, speed * Time.fixedDeltaTime);
        curDistance = Mathf.Clamp(curDistance, 0, defaultDistance);
        transform.localPosition = Vector3.forward * curDistance;
    }

    float GetDistance(float distance)
    {
        int i = 0;
        int loop = 666;
        virtualCamera.localPosition = Vector3.forward * distance;
        var wrold = BlockWorld.CurWorld;
        while (loop-- > 0)
        {
            UpdateNearClipPlane();
            for (i = 0; i < 4; i++)
            {
                if (wrold.HasBlockCollider(Vector3Int.RoundToInt(corners[i])) || wrold.HasVoxelCollider(corners[i]))
                {
                    break;
                }
            }
            if (i == 4)
                break;
            distance += 0.25f;
            virtualCamera.localPosition = Vector3.forward * distance;
        }

        return distance;
    }

    void UpdateNearClipPlane()
    {
        corners[0] = virtualCamera.position - (virtualCamera.right * width);
        corners[0] += virtualCamera.up * height;
        corners[0] += virtualCamera.forward * mainCamera.nearClipPlane;

        corners[1] = virtualCamera.position + (virtualCamera.right * width);
        corners[1] += virtualCamera.up * height;
        corners[1] += virtualCamera.forward * mainCamera.nearClipPlane;

        corners[2] = virtualCamera.position - (virtualCamera.right * width);
        corners[2] -= virtualCamera.up * height;
        corners[2] += virtualCamera.forward * mainCamera.nearClipPlane;

        corners[3] = virtualCamera.position + (virtualCamera.right * width);
        corners[3] -= virtualCamera.up * height;
        corners[3] += virtualCamera.forward * mainCamera.nearClipPlane;

    }
}


你可能感兴趣的:(unity3d,unity,射线检测,第三人称摄像机,穿模)