Unity3D

来自CGTWiki
跳转至:导航搜索

简介

本页面展示了一些常用的漫游脚本代码

入门教程(需翻墙)

  1. 快速入门
  2. 千锋Unity游戏开发教程
  3. UGUI

常用网站

支持ActiveX的插件版本

Unity5.3.8

  1. 官网下载5.3.8版本unity
  2. 使用破解工具破解 文件:Unity破解工具.zip
  3. 破解工具使用流程 破解教程

1. 下载UnityWebPlayerFull32-5.3.8.f2.exe和UnityWebPlayerFull64-5.3.8.f1.exe进行安装, 一定要两个都要安装

2. 创建环境变量 UNITY_DISABLE_PLUGIN_UPDATES,其值为yes(非常重要)

链接:https://pan.baidu.com/s/1Zhgq9EwKZlVhtmCplpTsnw 
提取码:gmt9 
链接:https://pan.baidu.com/s/1IIqveQkueDfSJYeWsAlNOw 
提取码:tqqz 

用户名:xsj123@bupt.edu.cn 密码:ShWp8C198409128358

常用插件汇总

具有双目视差的校园漫游场景:双目校园场景

Enviro - Sky and Weather:Sky and Weather v2.3.1.unitypackage

DOTween Pro v1.0.165:DOTween Pro v1.0.165.unitypackage

AVProVideo: UnityPlugin-AVProVideo-Latest-Trial.unitypackage

Easy Touch 5:Easy Touch 5 Touchscreen Virtual Controls 5.0.17.unitypackage

UMP: UMP PLAYER(支持海康rtsp解码)

VR、双目:VR、双目、bupt

大屏双目立体插件:双目立体插件

地形插件:Real World Terrain

unity加载osgb倾斜摄影模型:Unity-OSG

unity加载osgb倾斜摄影模型(unity5.3.8版本,不带光场相机):Unity-OSG

插件

plugin分为两种:托管与非托管插件

托管插件

就是.NET编写的工具,运行于.NET平台(包括mono)的代码库,可以是脚本文件,也可以本身是DLL。NGUI源码就放在该文件夹下面的。

非托管插件

原生代码编写的库,比如第三方sdk,一般是dll、so、jar等等。 该文件夹下的东西会在standard compiler时编译(最先编译),以保证在其它地方使用时能找到。

底层非托管渲染插件[1]

加载与卸载

首先需要include库,这些库在项目文件中都可以找到,或者可以参考项目中RenderingPlugin.cpp的引入处理方式。

#include "IUnityInterface.h"
#include "IUnityGraphics.h"

在导入库之后,首先需要定义的是UnityPluginLoad和UnityPluginUnload方法,这些是为了处理主要的unity事件,它的基本格式也是一直的,几乎不需要改动,按照官方文件或者范例中的方式即可。

  • 先申明一些需要的变量,和一个callback函数。
// 这是事件的callback函数,会在下面定义
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType);

// the unity interface unity的交互界面
static IUnityInterfaces* s_UnityInterfaces = NULL;
// the graphics device 图像渲染的设备
static IUnityGraphics* s_Graphics = NULL;
  • 定义load方法
extern "C" void	UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
	s_UnityInterfaces = unityInterfaces;
	// to access generic graphics device functionality 
	// 为了可以访问渲染工具的功能
	s_Graphics = s_UnityInterfaces->Get<IUnityGraphics>();
	// to receive notification about events on the graphics device 
	// 为了获取图像设备的信息
	s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);

// Vulkan is a low-overhead, cross-platform 3D graphics and computing API.
// Vulkan是一款图像渲染api,unity提供了它的支持,但是我暂时没有使用它的需求
#if SUPPORT_VULKAN
	if (s_Graphics->GetRenderer() == kUnityGfxRendererNull)
	{
		extern void RenderAPI_Vulkan_OnPluginLoad(IUnityInterfaces*);
		RenderAPI_Vulkan_OnPluginLoad(unityInterfaces);
	}
#endif // SUPPORT_VULKAN

	// Run OnGraphicsDeviceEvent(initialize) manually on plugin load
	// to not miss the event in case the graphics device is already initialized
	// 手工调用一次callback的初始化方法
	OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
}
  • unload则十分简单
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
	s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
}
  • 定义事件回调函数
static RenderAPI* s_CurrentAPI = NULL;
static UnityGfxRenderer s_DeviceType = kUnityGfxRendererNull;

static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType)
{
	// Create graphics API implementation upon initialization
	if (eventType == kUnityGfxDeviceEventInitialize)
	{
		assert(s_CurrentAPI == NULL);
		s_DeviceType = s_Graphics->GetRenderer();
		s_CurrentAPI = CreateRenderAPI(s_DeviceType);
	}

	// Let the implementation process the device related events
	if (s_CurrentAPI)
	{
		s_CurrentAPI->ProcessDeviceEvent(eventType, s_UnityInterfaces);
	}

	// Cleanup graphics API implementation upon shutdown
	if (eventType == kUnityGfxDeviceEventShutdown)
	{
		delete s_CurrentAPI;
		s_CurrentAPI = NULL;
		s_DeviceType = kUnityGfxRendererNull;
	}
}
IssuePluginEvent

这里需要输入渲染的event,在unity的代码中调用到(参加上面unity代码)

static void UNITY_INTERFACE_API OnRenderEvent(int eventID)
{
	// Unknown / unsupported graphics device type? Do nothing
	if (s_CurrentAPI == NULL)
		return;

	TODO:使用opengl绘制相应的场景
}

// --------------------------------------------------------------------------
// GetRenderEventFunc, an example function we export which is used to get a rendering event callback function.

extern "C" UnityRenderingEvent UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API GetRenderEventFunc()
{
	return OnRenderEvent;
}

常用脚本汇总

漫游

第一人称漫游

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

public class FirstPlay : MonoBehaviour
{
    CharacterController player;
    //方向灵敏度
    public float sensitivityX = 5F;
    public float sensitivityY = 5F;

    //上下最大视角(Y视角)
    public float minimumY = -60F;
    public float maximumY = 60F;

    float moveFB;
    float moveLR;
    public float speed = 1f;
    public float mspeed;    //鼠标滚轮滚动速度
    float rotationY = 0F;

    private bool isButtonDown = false;  //判断鼠标是否按下

    void Start()
    {
        player = GetComponent<CharacterController>();
        //isButtonDown = false;
    }

    private void OnEnable()  //在隐藏之后出现会再次调用
    {
        isButtonDown = false;
        mspeed = 5f;
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            isButtonDown = true;
        }
        if (Input.GetMouseButtonUp(0))
        {
            isButtonDown = false;
        }
        if (isButtonDown)
        {
            //根据鼠标移动的快慢(增量), 获得相机左右旋转的角度(处理X)
            float rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityX;

            //根据鼠标移动的快慢(增量), 获得相机上下旋转的角度(处理Y)
            rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
            //角度限制. rotationY小于min,返回min. 大于max,返回max. 否则返回value 
            rotationY = Mathf.Clamp(rotationY, minimumY, maximumY);

            //总体设置一下相机角度
            transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
        }
        if (Input.GetKeyDown(KeyCode.KeypadPlus) || Input.GetKeyDown(KeyCode.Plus))
        {
            mspeed += 1.0f;
        }
        if (Input.GetKeyDown(KeyCode.KeypadMinus) || Input.GetKeyDown(KeyCode.Minus))
        {
            mspeed -= 1.0f;
        }
        if (mspeed > 35f)
        {
            mspeed = 35f;
        }
        if (mspeed < 1f)
        {
            mspeed = 1f;
        }
        if(Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
        {
            moveFB = Input.GetAxis("Vertical") * speed;
        }
        else
        {
            moveFB = Input.GetAxis("Mouse ScrollWheel") * mspeed;
        }
        //moveFB = Input.GetAxis("Vertical") * speed;
        //moveFB = Input.GetAxis("Mouse ScrollWheel") * mspeed;
        moveLR = Input.GetAxis("Horizontal") * speed;
        Vector3 movement = new Vector3(moveLR, 0, moveFB);
        movement = transform.rotation * movement;
        //movement.y -= 4000f * Time.deltaTime;
        player.Move(movement * 3 * Time.deltaTime);
        //transform.position += movement * Time.deltaTime;
    }
}

第三人称漫游

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class FreeTPSCamera : MonoBehaviour {
    [Header("相机距离")]
    public float freeDistance = 2;
    [Header("相机最近距离")]
    public float minDistance = 0.5f;
    [Header("相机最远距离")]
    public float maxDistance = 20;
    [Header("是否可控制相机距离(鼠标中键)")]
    public bool canControlDistance=true;
    [Header("更改相机距离的速度")]
    public float distanceSpeed = 1;
 
    [Header("视角灵敏度")]
    public float rotateSpeed = 1;
    [Header("物体转向插值(灵敏度,取值为0到1)")]
    public float TargetBodyRotateLerp = 0.3f;
    [Header("需要转向的物体")]
    public GameObject TargetBody;//此脚本能操作转向的物体
    [Header("相机焦点物体")]
    public GameObject CameraPivot;//相机焦点物体  
    [Header("===锁敌===")]
    public GameObject lockTarget=null;
    public float lockSlerp=1;
    public GameObject lockMark;
    private bool marked;
 
    [Header("是否可控制物体转向")]
    public bool CanControlDirection = true;
    [Header("俯角(0-89)")]
    public float maxDepression=80;
    [Header("仰角(0-89)")]
    public float maxEvelation=80;
    
 
    private Vector3 PredictCameraPosition;
    private Vector3 offset;
    private Vector3 wallHit;
    private GameObject tmpMark;
    // Use this for initialization
    void Start () {
        
        offset = transform.position - CameraPivot.transform.position;
        if (TargetBody == null)
        {
            TargetBody = GameObject.FindGameObjectWithTag("Player");
            Debug.Log("未绑定目标物体,默认替换为Player标签的物体");
        }
        if (!CameraPivot)
        {
            Debug.LogError("未绑定相机焦点物体");
        }
 
    }
 
    void LockTarget()
    {
        if(lockTarget)
        {
            lockTarget = null;
            marked = false;
            Destroy(tmpMark);
            return;
        }
 
        Vector3 top = transform.position + new Vector3(0, 1, 0)+transform.forward*5;
        LayerMask mask = (1 << LayerMask.NameToLayer("Mob")); //将物体的Layer设置为Ignore Raycast,Player和Mob来忽略相机的射线,不然相机将跳到某些物体前,比如怪物,玩家等,
      
        Collider[] cols = Physics.OverlapBox(top, new Vector3(0.5f,0.5f,5),transform.rotation,mask);
        foreach (var col in cols)
        {
            lockTarget = col.gameObject;
        }   
    }
 
    bool Inwall()
    {
 
        RaycastHit hit;
        LayerMask mask = (1 << LayerMask.NameToLayer("Player")) | (1 << LayerMask.NameToLayer("Ignore Raycast"))| (1 << LayerMask.NameToLayer("Mob"))|(1<<LayerMask.NameToLayer("Weapon")); //将物体的Layer设置为Ignore Raycast,Player和Mob来忽略相机的射线,不然相机将跳到某些物体前,比如怪物,玩家等,
        mask = ~mask;//将以上的mask取反,表示射线将会忽略以上的层
        //Debug.DrawLine(CameraPivot.transform.position, transform.position - transform.forward, Color.red);
        
        PredictCameraPosition = CameraPivot.transform.position + offset.normalized * freeDistance ;//预测的相机位置
        if (Physics.Linecast(CameraPivot.transform.position, PredictCameraPosition, out hit, mask))//碰撞到任意碰撞体,注意,因为相机没有碰撞器,所以是不会碰撞到相机的,也就是没有碰撞物时说明没有遮挡
        {//也就是说,这个if就是指被遮挡的情况
 
 
            wallHit = hit.point;//碰撞点位置
            //Debug.DrawLine(transform.position, wallHit, Color.green);
            return true;
        }
        else//没碰撞到,也就是说没有障碍物
        {
            return false;
        }
 
 
    }
 
 
    void FreeCamera()
    {
        offset = offset.normalized * freeDistance;
        transform.position = CameraPivot.transform.position + offset;//更新位置
 
        if (CanControlDirection)//控制角色方向开关
        {
            Quaternion TargetBodyCurrentRotation = TargetBody.transform.rotation;
 
            if (Input.GetKey(KeyCode.A))
            {
                if (Input.GetKey(KeyCode.W))
                {
                    TargetBody.transform.rotation = Quaternion.Lerp(TargetBodyCurrentRotation, Quaternion.Euler(new Vector3(TargetBody.transform.localEulerAngles.x, transform.localEulerAngles.y - 45, TargetBody.transform.localEulerAngles.z)), TargetBodyRotateLerp);
                }
                else if (Input.GetKey(KeyCode.S))
                {
                    TargetBody.transform.rotation = Quaternion.Lerp(TargetBodyCurrentRotation, Quaternion.Euler(new Vector3(TargetBody.transform.localEulerAngles.x, transform.localEulerAngles.y - 135, TargetBody.transform.localEulerAngles.z)), TargetBodyRotateLerp);
                }
 
 
                else if (!Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.S))
                {
                    TargetBody.transform.rotation = Quaternion.Lerp(TargetBodyCurrentRotation, Quaternion.Euler(new Vector3(TargetBody.transform.localEulerAngles.x, transform.localEulerAngles.y - 90, TargetBody.transform.localEulerAngles.z)), TargetBodyRotateLerp);
                }
            }
            else if (Input.GetKey(KeyCode.D))
            {
                if (Input.GetKey(KeyCode.W))
                {
                    TargetBody.transform.rotation = Quaternion.Lerp(TargetBodyCurrentRotation, Quaternion.Euler(new Vector3(TargetBody.transform.localEulerAngles.x, transform.localEulerAngles.y + 45, TargetBody.transform.localEulerAngles.z)), TargetBodyRotateLerp);
                }
                else if (Input.GetKey(KeyCode.S))
                {
                    TargetBody.transform.rotation = Quaternion.Lerp(TargetBodyCurrentRotation, Quaternion.Euler(new Vector3(TargetBody.transform.localEulerAngles.x, transform.localEulerAngles.y + 135, TargetBody.transform.localEulerAngles.z)), TargetBodyRotateLerp);
                }
 
                else if (!Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.S))
                {
                    TargetBody.transform.rotation = Quaternion.Lerp(TargetBodyCurrentRotation, Quaternion.Euler(new Vector3(TargetBody.transform.localEulerAngles.x, transform.localEulerAngles.y + 90, TargetBody.transform.localEulerAngles.z)), TargetBodyRotateLerp);
                }
            }
            else if (Input.GetKey(KeyCode.W))
            {
                TargetBody.transform.rotation = Quaternion.Lerp(TargetBodyCurrentRotation, Quaternion.Euler(new Vector3(TargetBody.transform.localEulerAngles.x, transform.localEulerAngles.y, TargetBody.transform.localEulerAngles.z)), TargetBodyRotateLerp);
 
            }
            else if (Input.GetKey(KeyCode.S))
            {
                TargetBody.transform.rotation = Quaternion.Lerp(TargetBodyCurrentRotation, Quaternion.Euler(new Vector3(TargetBody.transform.localEulerAngles.x, transform.localEulerAngles.y - 180, TargetBody.transform.localEulerAngles.z)), TargetBodyRotateLerp);
 
            }
        }
 
        if(canControlDistance)//控制距离开关
        {
            freeDistance -= Input.GetAxis("Mouse ScrollWheel") * distanceSpeed;
        }
        
        freeDistance = Mathf.Clamp(freeDistance, minDistance, maxDistance);
 
        if(!lockTarget)
        {
 
        
            transform.LookAt(lockTarget ? (lockTarget.transform.position ): CameraPivot.transform.position);
        }
        else
        {
            Quaternion tmp = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(lockTarget.transform.position - transform.position), lockSlerp*Time.fixedDeltaTime);
            transform.rotation = tmp;
 
        }
 
        float eulerX = transform.localEulerAngles.x;//相机的x欧拉角,也就是垂直方向.
        float inputY = Input.GetAxis("Mouse Y");
 
 
        if (!lockTarget)
        {
                //垂直视野限制
                if (!lockTarget)
            {
                transform.RotateAround(CameraPivot.transform.position, Vector3.up, rotateSpeed * Input.GetAxis("Mouse X"));//x不用限制
            }
        
            if (eulerX > maxDepression && eulerX < 90)//当向上角度越界时
            {
                if (inputY > 0)//如果鼠标时在向下滑动
                    transform.RotateAround(CameraPivot.transform.position, Vector3.right, -rotateSpeed * inputY);//允许滑动
            }
            else if (eulerX < 360-maxEvelation && eulerX > 270)
            {
                if (inputY < 0)
                    transform.RotateAround(CameraPivot.transform.position, Vector3.right, -rotateSpeed * inputY);
            }
            else//角度正常时
            {
            
                    transform.RotateAround(CameraPivot.transform.position, Vector3.right, -rotateSpeed * inputY);
           
 
            }
        }
        if (lockTarget)
        {
            offset = CameraPivot.transform.position - (lockTarget.transform.position);
        }
        else
        {
            offset = transform.position - CameraPivot.transform.position;//以上方向发生了变化,记录新的方向向量
        }
       
        offset = offset.normalized * freeDistance;
 
        ///在一次FixedUpdate中,随时记录新的旋转后的位置,然后得到方向,然后判断是否即将被遮挡,如果要被遮挡,将相机移动到计算后的不会被遮挡的位置
        ///如果不会被遮挡,则更新位置为相机焦点位置+方向的单位向量*距离
        ///
        if (Inwall())//预测会被遮挡
        {
            //print("Inwall");
 
            transform.position = CameraPivot.transform.position + (wallHit - CameraPivot.transform.position) * 0.8f;
 
            return;
 
 
        }
        else
        {
            transform.position = CameraPivot.transform.position + offset;
           
        }
    
    }
 
    // Update is called once per frame
    void FixedUpdate () {
        FreeCamera();
        if(lockTarget)
        {
            
            if (!marked)
            {
                tmpMark = Instantiate(lockMark, lockTarget.transform.position + new Vector3(0, 2.5f, 0), transform.rotation);
                tmpMark.transform.forward = -Vector3.up;
                marked = true;
            }
            
            else
            {
                tmpMark.transform.position = lockTarget.transform.position + new Vector3(0, 2.5f, 0);
                //tmpMark.transform.forward= -transform.up;
                tmpMark.transform.Rotate(Vector3.up *30* Time.fixedDeltaTime,Space.World);
            }
        }
	}
 
    private void Update()
    {
        if(Input.GetKeyDown(KeyCode.F))
        {
            LockTarget();
        }
    }
}

轨迹球漫游

  • 需要将这个脚体和球形碰撞体付给虚拟物体。球形碰撞体的半径需要根据实际需要调整。通过调整speed和damping值来调整旋转速度。
// Attach this script and a sphere collider to the object. Adjust the sphere radius to your needs. Use the speed and damping variables to tweak the rotation speed
using UnityEngine;

public class TrackballCamera : MonoBehaviour
{
    public float distance = 15f;
    public float virtualTrackballDistance = 0.25f;
    public GameObject target;
    private Vector3? lastMousePosition;


    private void Start()
    {
        var startPos = (this.transform.position - target.transform.position).normalized * distance;
        var position = startPos + target.transform.position;
        transform.position = position;
        transform.LookAt(target.transform.position);
    }


    private void LateUpdate()
    {
        if (Input.GetAxis("Mouse ScrollWheel") < 0)
        {
            var lastPos = this.transform.position;
            var targetPos = target.transform.position;

            distance *= 1.01f;
            var vecPos = (targetPos - lastPos).normalized * -distance;

            this.transform.position = vecPos + targetPos;
            this.transform.LookAt(targetPos);
        }
        if (Input.GetAxis("Mouse ScrollWheel") > 0)
        {
            var lastPos = this.transform.position;
            var targetPos = target.transform.position;
            

            distance /= 1.01f;
            var vecPos = (targetPos - lastPos).normalized * -distance;

            this.transform.position = vecPos + targetPos;
            this.transform.LookAt(targetPos);
        }

        var mousePos = Input.mousePosition;

        var mouseBtn = Input.GetMouseButton(0);
        if (mouseBtn)
        {
            if (lastMousePosition.HasValue)
            {
                // We are moving from here.
                var lastPos = this.transform.position;
                var targetPos = target.transform.position;

                // we have traced out this distance on a sphere from lastPos
                /*
				var rotation = TrackBall(
										lastMousePosition.Value.x,
										lastMousePosition.Value.y,
										mousePos.x,
										mousePos.y );
				*/
                var rotation = FigureOutAxisAngleRotation(lastMousePosition.Value, mousePos);

                var vecPos = (targetPos - lastPos).normalized * -distance;

                this.transform.position = rotation * vecPos + targetPos;
                this.transform.LookAt(targetPos);

                lastMousePosition = mousePos;
            }
            else
            {
                lastMousePosition = mousePos;
            }
        }
        else
        {
            lastMousePosition = null;
        }
    }


    private Quaternion FigureOutAxisAngleRotation(Vector3 lastMousePos, Vector3 mousePos)
    {
        if (lastMousePos.x == mousePos.x && lastMousePos.y == mousePos.y)
        {
            return Quaternion.identity;
        }

        var near = new Vector3(0, 0, Camera.main.nearClipPlane);
        Vector3 p1 = Camera.main.ScreenToWorldPoint(lastMousePos + near);
        Vector3 p2 = Camera.main.ScreenToWorldPoint(mousePos + near);

        //WriteLine("## {0} {1}", p1,p2);
        var axisOfRotation = Vector3.Cross(p2, p1);
        var twist = (p2 - p1).magnitude / (2.0f * virtualTrackballDistance);

        if (twist > 1.0f)
        {
            twist = 1.0f;
        }

        if (twist < -1.0f)
        {
            twist = -1.0f;
        }

        var phi = (2.0f * Mathf.Asin(twist)) * 180 / Mathf.PI;
        //WriteLine("AA: {0} angle: {1}",axisOfRotation, phi);

        return Quaternion.AngleAxis(phi, axisOfRotation);
    }


    private Quaternion TrackBall(float p1x, float p1y, float p2x, float p2y, float radius)
    {
        // if there has been no drag, then return "no rotation"
        if (p1x == p2x && p1y == p2y)
        {
            return Quaternion.identity;
        }

        var p1 = ProjectToSphere(radius, p1x, p1y);
        var p2 = ProjectToSphere(radius, p2x, p2y);
        var a = Vector3.Cross(p2, p1); // axis of rotation
                                       // how much to rotate around above axis
        var d = p1 - p2;
        var t = d.magnitude / (2.0f * radius);

        // clamp values to stop things going out of control.
        if (t > 1.0f)
        {
            t = 1.0f;
        }

        if (t < -1.0f)
        {
            t = -1.0f;
        }

        var phi = 2.0f * Mathf.Asin(t);
        phi = phi * 180 / Mathf.PI; // to degrees

        return Quaternion.AngleAxis(phi, a);
    }


    /// <summary>
    /// Projects an x,y pair onto a sphere of radius distance.
    /// OR onto a hyperbolic sheet if we are away from the center
    /// of the sphere
    /// </summary>
    /// <returns>The point on the sphere</returns>
    /// <param name='distance'>Distance</param>
    /// <param name='x'>X</param>
    /// <param name='y'>Y</param>
    private Vector3 ProjectToSphere(float distance, float x, float y)
    {
        float z;
        float d = Mathf.Sqrt(x * x + y * y);
        if (d < distance * 0.707f)
        {
            // inside sphere
            z = Mathf.Sqrt(distance * distance - d * d);
        }
        else
        {
            // on hyperbola
            var t = distance / 1.4142f;
            z = t * t / d;
        }

        return new Vector3(x, y, z);
    }
}

记录相机位置姿态

using UnityEngine;
using OfficeOpenXml;
using System.IO;
public class WriteExcel : MonoBehaviour
{
    public GameObject leftCam;
    int count = 2;
    Camera cam;
    //ShearCamera sc;
    string excelPath;
    FileInfo fileInfo;
    ExcelPackage excelPackage;
    ExcelWorksheet worksheet;
    void Start()
    {
        //sc = leftCam.GetComponent<ShearCamera>();
        cam = GetComponent<Camera>();
        excelPath = Application.dataPath + "/StreamingAssets" + "/test.xlsx";
        fileInfo = new FileInfo(excelPath);
        excelPackage = new ExcelPackage(fileInfo);
        worksheet = excelPackage.Workbook.Worksheets[1];
        worksheet.Cells[1, 1].Value = "序号";
        worksheet.Cells[1, 2].Value = "相机位置";
        worksheet.Cells[1, 3].Value = "相机朝向";
        worksheet.Cells[1, 4].Value = "向上矢量";
        worksheet.Cells[1, 5].Value = "向右矢量";
        //worksheet.Cells[1, 6].Value = "相机间距";
        //worksheet.Cells[1, 7].Value = "人眼距零平面距离";
        excelPackage.Save();
    }
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.O))
        {
            worksheet.Cells[count, 1].Value = count - 1;
            worksheet.Cells[count, 2].Value = transform.position;
            worksheet.Cells[count, 3].Value = cam.transform.forward;
            worksheet.Cells[count, 4].Value = cam.transform.up;
            worksheet.Cells[count, 5].Value = cam.transform.right;
            //worksheet.Cells[count, 6].Value = sc.distNearCam;
           // worksheet.Cells[count, 7].Value = sc.distToZeroPlane;
            Debug.Log("成功记录第" + (count - 1) + "个数据");
            worksheet.Cells[count + 1, 1].Value = "end";
            excelPackage.Save();
            count++;
        }
    }
}

自动漫游

using UnityEngine;
using OfficeOpenXml;
using System.IO;

public class CramerMove : MonoBehaviour
{
    private Vector3 StartPosition;
    private Vector3 EndPosition;
    private float TempTimerPosition;
    private float MovePercentPosition;
    private float ContinueTime = 2.0f;

    private Vector3 StartUp;
    private Vector3 EndUp;
    private float TempTimerUp;
    private float MovePercentUp;

    private Vector3 StartForward;
    private Vector3 EndForward;
    private float TempTimerForward;
    private float MovePercentForward;

    private Vector3 StartRight;
    private Vector3 EndRight;
    private float TempTimerRight;
    private float MovePercentRight;

    private float StartdistNearCam;
    private float EnddistNearCam;
    private float TempTimerdistNearCam;
    private float MovePercentdistNearCam;

    private float StartdistToZeroPlane;
    private float EnddistToZeroPlane;
    private float TempTimerdistToZeroPlane;
    private float MovePercentdistToZeroPlane;

    private bool IsPlay;
    string excelPath;
    FileInfo fileInfo;
    ExcelPackage excelPackage;
    ExcelWorksheet worksheet;
    private int count = 2;
    //ShearCamera sc;
    public GameObject leftCam;
    Camera cam;
    int i = 0;
    private void Start()
    {
        //sc = leftCam.GetComponent<ShearCamera>();
        cam = GetComponent<Camera>();
        excelPath = Application.dataPath + "/StreamingAssets" + "/test.xlsx";//读取excel表格
        fileInfo = new FileInfo(excelPath);
        excelPackage = new ExcelPackage(fileInfo);
        worksheet = excelPackage.Workbook.Worksheets[1];

        StartPosition = Parse(worksheet.Cells[2, 2].Value.ToString());
        StartForward = Parse(worksheet.Cells[2, 3].Value.ToString());
        StartUp = Parse(worksheet.Cells[2, 4].Value.ToString());
        StartRight = Parse(worksheet.Cells[2, 5].Value.ToString());
        StartdistNearCam = float.Parse(worksheet.Cells[2, 6].Value.ToString());
        StartdistToZeroPlane = float.Parse(worksheet.Cells[count, 7].Value.ToString());
        //StartRotation = Parse(worksheet.Cells[count, 8].Value.ToString());       

        cam.transform.position = StartPosition;
        cam.transform.forward = StartForward;
        cam.transform.up = StartUp;
        cam.transform.right = StartRight;
        //sc.distNearCam = StartdistNearCam;
        //sc.distToZeroPlane = StartdistToZeroPlane;
        IsPlay = true;
    }

    private void Update()
    {
        
        if (Input.GetKey(KeyCode.P)||i==1)

            if (IsPlay)
            {
                i = 1;
                StartPosition = Parse(worksheet.Cells[count, 2].Value.ToString());//相机位置
                EndPosition = Parse(worksheet.Cells[count + 1, 2].Value.ToString());
                TempTimerPosition += Time.deltaTime;
                MovePercentPosition += Time.deltaTime / ContinueTime;
                cam.transform.position = Vector3.Lerp(a: StartPosition, b: EndPosition, MovePercentPosition);

                StartForward = Parse(worksheet.Cells[count, 3].Value.ToString());//相机朝向
                EndForward = Parse(worksheet.Cells[count + 1, 3].Value.ToString());
                TempTimerForward += Time.deltaTime;
                MovePercentForward += Time.deltaTime / ContinueTime;
                cam.transform.forward = Vector3.Lerp(a: StartForward, b: EndForward, MovePercentForward);

                StartUp = Parse(worksheet.Cells[count, 4].Value.ToString());//相机向上向量
                EndUp = Parse(worksheet.Cells[count + 1, 4].Value.ToString());
                TempTimerUp += Time.deltaTime;
                MovePercentUp += Time.deltaTime / ContinueTime;
                cam.transform.up = Vector3.Lerp(a: StartUp, b: EndUp, MovePercentUp);

                StartRight = Parse(worksheet.Cells[count, 5].Value.ToString());//相机向右向量
                EndRight = Parse(worksheet.Cells[count + 1, 5].Value.ToString());
                TempTimerRight += Time.deltaTime;
                MovePercentRight += Time.deltaTime / ContinueTime;
                cam.transform.right = Vector3.Lerp(a: StartRight, b: EndRight, MovePercentRight);

                StartdistNearCam = float.Parse(worksheet.Cells[count, 6].Value.ToString());//瞳距
                EnddistNearCam = float.Parse(worksheet.Cells[count + 1, 6].Value.ToString());
                TempTimerdistNearCam += Time.deltaTime;
                MovePercentdistNearCam += Time.deltaTime / ContinueTime;
                //sc.distNearCam = Mathf.Lerp(a: StartdistNearCam, b: EnddistNearCam, MovePercentdistNearCam);

                StartdistToZeroPlane = float.Parse(worksheet.Cells[count, 7].Value.ToString());//到零平面在距离
                EnddistToZeroPlane = float.Parse(worksheet.Cells[count + 1, 7].Value.ToString());
                TempTimerdistToZeroPlane += Time.deltaTime;
                MovePercentdistToZeroPlane += Time.deltaTime / ContinueTime;
                //sc.distToZeroPlane = Mathf.Lerp(a: StartdistToZeroPlane, b: EnddistToZeroPlane, MovePercentdistToZeroPlane);

                if (MovePercentPosition > 1 && MovePercentForward > 1 && MovePercentUp > 1 && MovePercentRight > 1/* && MovePercentdistNearCam > 1 && MovePercentdistToZeroPlane > 1*/)
                {
                    Debug.Log("已到达点" + EndPosition);
                    count++;
                    MovePercentPosition = 0;
                    MovePercentForward = 0;
                    MovePercentUp = 0;
                    MovePercentRight = 0;
                    MovePercentdistNearCam = 0;
                    MovePercentdistToZeroPlane = 0;
                    MovePercentRight = 0;
                    if (worksheet.Cells[count + 1, 1].Value.ToString() == "end")
                    IsPlay = false;
                }
            }
    }
    public static Vector3 Parse(string str)//将字符串转为三维向量
    {
        str = str.Replace("(", " ").Replace(")", " "); //将字符串中"("和")"替换为" "
        string[] s = str.Split(',');
        return new Vector3(float.Parse(s[0]), float.Parse(s[1]), float.Parse(s[2]));
    }
}

物体的缩放与移动

//通过虚拟轴控制物体移动、旋转、缩放
public class MoveCube : MonoBehaviour
{
    float moveSpeed = 10f;
    float rotateSpeed = 50f;

    void Update()
    {
        float horizontal = Input.GetAxis("Horizontal"); //获取横轴参数。(如:按A键返回-1 按D键返回+1,但中间有一个过度,而不是直接变-1或+1。)
        float vertical = Input.GetAxis("Vertical"); //获取垂直参数。
        Debug.Log("horizontal: " + horizontal + ",vertical:" + vertical);

        float mouseX = Input.GetAxis("Mouse X");//获取鼠标X轴滑动参数
        float mouseY = Input.GetAxis("Mouse Y");//获取鼠标Y轴滑动参数
        Debug.Log("mouseX: " + mouseX + ",mouseY:" + mouseY);

        float mouseScrollWheel = Input.GetAxis("Mouse ScrollWheel");

        //键盘ADWS键控制物体移动。(当乘以Time.deltaTime实际表示:每秒移动物体N米,而不是每帧N米。)
        this.transform.Translate(new Vector3(horizontal * Time.deltaTime * moveSpeed, 0, vertical * Time.deltaTime * moveSpeed));

        //鼠标XY轴滑动控制物体旋转
        this.transform.Rotate(new Vector3(mouseX * Time.deltaTime * rotateSpeed, mouseY * Time.deltaTime * rotateSpeed));

        //鼠标中键控制物体缩放
        this.transform.localScale += new Vector3(mouseScrollWheel, mouseScrollWheel, mouseScrollWheel);
    }
}

地球漫游器

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

public class CameraControl : MonoBehaviour {
    private Camera mCamera;
    private Transform mCameraNode;
    private Vector3 sphere;//屏幕中心坐标
    public  float mXSpeed = 1;
    public  float mYSpeed =1;
    public Transform target;//获取旋转目标,需要有碰撞体积
    public int speed;//摄像机自动围绕物体旋转速度,手动的话不需要填


    // Use this for initialization
    void Start () {
  
	}

    // Update is called once per frame
    void Update()
    {
        camerarotate();
        camerazoom();

    }

    private void camerarotate() //摄像机围绕目标旋转操作
    {
        Ray ray = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2, 0));//射线

        RaycastHit hit;
        if (Physics.Raycast(ray, out hit))//发射射线(射线,射线碰撞信息,射线长度,射线会检测的层级)
        {
            sphere = new Vector3(hit.point.x, hit.point.y, hit.point.z);
        }
        //射线主要为了获取屏幕中心坐标
        transform.RotateAround(target.position, Vector3.up, speed * Time.deltaTime); //摄像机自动围绕目标旋转功能
        var mouse_x = Input.GetAxis("Mouse X");//获取鼠标X轴移动
        var mouse_y = -Input.GetAxis("Mouse Y");//获取鼠标Y轴移动
        if (Input.GetKey(KeyCode.Mouse2))//鼠标中键功能
        {
            transform.RotateAround(sphere, transform.right, mouse_y * 5);
            transform.RotateAround(sphere, sphere, mouse_x * 5);

        }
        if (Input.GetKey(KeyCode.Mouse0))//鼠标左键功能
        {
            transform.RotateAround(target.transform.position, transform.up, mouse_x * 5);
            transform.RotateAround(target.transform.position, transform.right, mouse_y * 5);
        }
    }

    private void camerazoom() //摄像机滚轮缩放
    {
        if (Input.GetAxis("Mouse ScrollWheel") > 0)
            transform.Translate(Vector3.forward * 0.1f);


        if (Input.GetAxis("Mouse ScrollWheel") < 0)
            transform.Translate(Vector3.forward * -0.1f);
    }
}


Shader

向shader传送float型纹理

//脚本
private int dataWidth = 9;
private int dataHeight = 48;
Texture2D tex = new Texture2D(dataWidth, dataHeight, TextureFormat.RFloat, false);
tex.filterMode = FilterMode.Point;

Color[] pixels = new Color[dataWidth * dataHeight];

for (int i = 0; i < dataWidth * dataHeight; i++)
{
   float value = 234.2402015f * 1;
   pixels[i] = new Color(value, 0.0f, 0.0f, 1.0f);
}
tex.SetPixels(pixels, 0);
tex.Apply();

//shader层
sampler2D        _DataTex;
float datawidth = 9;
loat dataheight = 48;
float datatest = tex2D(_DataTex, float2(0.5/datawidth,2.5/dataheight));

图像的校正

//matlab
orig = imread("orig.png");
dest=imtransform(orig,TForm(1),...
                        'XData', [1 1280],...
                        'YData', [1 720]);
imwrite(dest,'img2.png');
imshow(dest);

//shader
float3x3 RectifyData = float3x3(float3(1.77169503813251,0.136886500822738,0.000411731741850891),
		       float3(0.100551213579608,1.34186124742767,5.88806191143576e-05),
		       float3(-204.588758439240,- 130.492806976330,1.00000000000000));

			float x = i.uv.x;
			float y = 1.0f - i.uv.y;

			float orgiCol = x * 1280.0f;
			float orgiRow = y * 720.0f;

			float3  dest = mul(float3(orgiCol, orgiRow, 1.0), RectifyData);
			dest = dest / dest.z;

			if (dest.x < 0 || dest.x>1280 || dest.y < 0 || dest.y>720)
				return fixed4(0, 0, 0, 1);
         
			float2 destUV;
			destUV.x = dest.x / 1280.0f;
			destUV.y = 1.0f -dest.y / 720.0f;

			fixed4 col = tex2D(_MainTex, destUV);