DirectX11学习笔记五 摄像机类

这一节跟渲染好像关系不大,但是值得看一看,我觉得更像是对游戏引擎和渲染的一些非常浅显的摸索和思考,以前用unity都是直接调的标准资源包里的摄像机类,很少从底层原理来考虑摄像机的实现方法。GameObject也是,unity都封装好了。
本节的demo里一共介绍了3种摄像机

  • 第一人称
  • 第三人称
  • 自由视角
    其中自由视角和第一人称差距不大。

摄像机基类

先放一个以前用过的unity的非官方的第一人称幽灵视角摄像机类。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Control : MonoBehaviour {
   
 
    public float zoomSensitivity = 10f;
    public float mouseSensitivity = 5f;
    public float speedSensitivity = 20f;
    private float m_deltX = 0f;
    private float m_deltY = 0f;
    private Camera mainCamera;
    void Start () {
   
        mainCamera = GetComponent<Camera>();
	}
	
	// Update is called once per frame
	void Update ()
    {
   
        if (Input.GetMouseButton(0))
        {
   
            LockCursor(true);
            UFOMove();
            ZoomMove();
        }
        else LockCursor(false);
    }
    private void FixedUpdate()
    {
   
        if (Input.GetMouseButton(0))
        {
   
            LookRotation();
        }
    }
    private void ZoomMove()
    {
   
        if (Input.GetAxis("Mouse ScrollWheel") != 0)
        {
   
            mainCamera.transform.localPosition = mainCamera.transform.position + mainCamera.transform.forward * Input.GetAxis("Mouse ScrollWheel") * zoomSensitivity; ;
        }
    }
    private void UFOMove()
    {
   
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        if (Input.GetKey(KeyCode.LeftShift))
        {
   
            horizontal *= 3; vertical *= 3;
        }
        mainCamera.transform.Translate(Vector3.forward * vertical * speedSensitivity * Time.deltaTime);
        mainCamera.transform.Translate(Vector3.right * horizontal * speedSensitivity * Time.deltaTime);
    }
    private void LookRotation()
    {
   
        m_deltX += Input.GetAxis("Mouse X") * mouseSensitivity;
        m_deltY -= Input.GetAxis("Mouse Y") * mouseSensitivity;
        m_deltX = ClampAngle(m_deltX, -360, 360);
        m_deltY = ClampAngle(m_deltY, -70, 70);
        mainCamera.transform.rotation = Quaternion.Euler(m_deltY, m_deltX, 0);
    }
    private void LockCursor(bool b)
    {
   
        //Cursor.lockState = b ? CursorLockMode.Locked : Cursor.lockState = CursorLockMode.None;
        Cursor.visible = b ? false : true;
    }
    float ClampAngle(float angle, float minAngle, float maxAgnle)
    {
   
        if (angle <= -360)
            angle += 360;
        if (angle >= 360)
            angle -= 360;
 
        return Mathf.Clamp(angle, minAngle, maxAgnle);
    }
}
//原文链接:https://blog.csdn.net/MaxLykoS/article/details/72801979

unity中摄像机需要的一些有用的属性
在这里插入图片描述
只看重要的部分,首先得有Transform摄像机的坐标,位置旋转缩放,然后是,透视类型,FOV,剪裁距离和视口。
接下来就要写我们自己的摄像机类了,但是在写之前,得先弄清楚一些事情。

DirectXMath数学库

这个数学库实际上之前算世界变换矩阵的时候用到过,只不过当时只是矩阵计算,而在这里会添加一些向量计算。
可以参考这篇博客
做一些补充

  1. XMVECTOR和XMFloat3
    首先XMVECTOR里有很多属性,但是看float那一行就够了。其次,XMVECTOR的float有4个数,而XMFloat3有三个数,当然可以用XMFloat4,但是很多情况下用3就够了。另外,XMFloat3这种类似的类型只是用来赋值存储,不能用于计算,用于计算的是XMVECTOR。
    那二者如何转化呢?
    float3 to vector -> XMLoadFloat3(float3)
    vector to float3 -> XMStoreFloat3(float3, vector)
    matrix to float4x4 -> XMStoreFloat4x4(float4x4, matrix)
    float4x4 to matrix -> XMLoadFloat4x4(float4x4)
    取单值
    float3.x
    XMVectorGetX(vector)
    最后,假如两个vector点乘,结果仍是vector(应该是个常数),但是这个vector的xyzw都一样(都是结果常数)。
  2. XMVector3Transform和XMVector3TransformNormal
    具体可以查微软文档,其中前者将认为输入向量的w为1,而返回的向量w可能不为1。后者将会忽略矩阵的最后一行计算。
  3. 常数乘向量时,要把常数保存到xyzw都一样的vector中再跟其他vector计算,用XMVectorReplicate函数。

实现第一人称Camera

前面提到,unity中摄像机的一些属性如下
摄像机的坐标属性,透视类型,FOV,剪裁距离和视口。

  1. 坐标属性
	// 摄像机的观察空间坐标系对应在世界坐标系中的表示
	DirectX::XMFLOAT3 m_Position;
	DirectX::XMFLOAT3 m_Right;
	DirectX::XMFLOAT3 m_Up;
	DirectX::XMFLOAT3 m_Look;

坐标属性非常重要,关系到很多方法。
移动
平面步行

void FirstPersonCamera::Walk(float d)
{
   
	XMVECTOR Pos = XMLoadFloat3(&m_Position);
	XMVECTOR Right = XMLoadFloat3(&m_Right);
	XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
	XMVECTOR Front = XMVector3Normalize(XMVector3Cross(Right, Up));
	XMVECTOR Dist = XMVectorReplicate(d);
	// DestPos = Dist * Front + SrcPos
	XMStoreFloat3(&m_Position, XMVectorMultiplyAdd(Dist, Front, Pos));
	//步行只能在同一水平面上,所以up是固定的,front是用up和right叉乘的
	//最后d乘front再加上原位置即可
}

//调用,第一人称视角
	if (keyState.IsKeyDown(Keyboard::W))
		cam1st->Walk(dt * 3.0f);
	if (keyState.IsKeyDown(Keyboard::S))
		cam1st->Walk(dt * -3.0f);

UFO式飞行

void FirstPersonCamera::MoveForward(float d)
{
   
	XMVECTOR Pos = XMLoadFloat3(&m_Position);
	XMVECTOR Look = XMLoadFloat3(&m_Look);
	XMVECTOR Dist = XMVectorReplicate(d);
	// DestPos = Dist * Look + SrcPos
	XMStoreFloat3(&m_Position, XMVectorMultiplyAdd(Dist, Look, Pos));
	//look就是front,直接叠加即可
}

//调用 自由视角
	if (keyState.IsKeyDown(Keyboard::W))
		cam1st->MoveForward(dt * 3.0f);
	if (keyState.IsKeyDown(Keyboard::S))
		cam1st->MoveForward(dt * -3.0f);

左右移动

void FirstPersonCamera::Strafe(float d)
{
   
	XMVECTOR Pos = XMLoadFloat3(&m_Position);
	XMVECTOR Right = XMLoadFloat3(&m_Right);
	XMVECTOR Dist = XMVectorReplicate(d);
	// DestPos = Dist * Right + SrcPos</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值