开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:1871

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 1059|回复: 14

[Y-miku] 全重力方向第三人称摄像机实现

[复制链接]  [移动端链接]
排名
330
昨日变化

41

主题

380

帖子

4815

积分

Rank: 9Rank: 9Rank: 9

UID
26484
好友
17
蛮牛币
12552
威望
0
注册时间
2014-5-24
在线时间
2498 小时
最后登录
2017-9-22

游戏蛮牛QQ群会员VIP

QQ
发表于 2017-4-20 21:18:04 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 Y-miku 于 2017-4-20 21:21 编辑

前段时间做了个星球地形,想把第一称的摄像机改成第三人称的,本来想网上找个现成的,发现在重力方向不为下时有严重的bug,就自己写了一个,先说一下普通的摄像机怎么做吧
先定义两个float, rotateX rotateY,鼠标左右摇的时候加减rotateX,上下摇的时候加减rotateY,这里要把rotateY限制在一个范围内,如-90至90
现在我们得到了相机的旋转角度,将其转为四元数,乘以new vector3(0f,0f,-distance),之后加上y方向的偏移量,一般在y方向会偏上一点
四元数乘vector3表示将vector以原点为中心旋转,假设四元数欧拉角为xyz,则先x轴旋转x度,再按y轴旋转y,再按z轴旋转z度
而这里的vector3即为 rotateX rotateY为0时的相机坐标,这样,经过旋转,可以得到旋转rotateX rotateY度时的相机坐标
得到了位置,角度就好求了,可以直接lookat,也可以把四元数赋过去


而当重力方向不为下时,就有点麻烦了,首先,相机初始位置变了,不再是(0f,0f,-distance),重力方向为下时,角色角度的z值肯定为0,而此时角度的三个分量都不确定
其次,旋转角度也不再是简单的 (rotateX rotateY 0),在旋转前要将局部坐标 (rotateX rotateY 0)转换到世界坐标


这里有个办法就是先计算局部坐标下的位置,角度,再转换到世界坐标
核心代码为以下三句
[AppleScript] 纯文本查看 复制代码
wanted_position = _rotation * new Vector3(targetOffset.x, 0f, -distance) + new Vector3(0, targetOffset.y, 0); 
                transform.position = target.TransformPoint (wanted_position);
                transform.rotation = target.rotation*Quaternion.Euler(new Vector3(_input_rotation.y, _input_rotation.x, 0f));


第三句用四元数乘四元数相当于把第二个四元数按第一个四元数旋转,相当于把角度从局部坐标转到了世界坐标
结果如下图,效果还是不错的
QQ截图20170420205238.png

QQ截图20170420210905.png

之后是行走的问题,我设定的是行走按摄像机的方向进行,假如我按w键,而此时角色面朝右,则角色不会向角色的前方(即右)走,而会向摄像机的前方走
这里我将角色作为一个子物体,y轴旋转在子物体进行
获取摄像机的前方向,操作在局部空间进行
[C#] 纯文本查看 复制代码
characterTrans.localRotation = Quaternion.Lerp(characterTrans.localRotation,Quaternion.Euler(new Vector3(0f,rotateY+angle)),20f*Time.deltaTime);


这里rotateY即为摄像机局部y轴旋转度,x,y为x轴和y轴的值,据此可以确定一个角度angle,以z轴正方向为0度,向右递增
将两个角度相加即可求得要达到的局部y轴旋转度
例如,当按前时,angle为0,最终方向即为相机朝向,当按后时,angle为180,最终方向为相机朝向+180,即为相机反向
下面是camera的代码,可以按自己的需求更改
[C#] 纯文本查看 复制代码
using UnityEngine;
using System.Collections;
using System.Collections.Generic;


public class CameraController : UnitySingleton<CameraController>
{
        public Transform target;

        public LayerMask collisionLayers = new LayerMask();
        public float collisionAlpha = 0.15f;
        public float collisionFadeSpeed = 10;

        public bool allowRotation = true;
        public bool lockCursor = true;
    public bool stayBehindTarget = false;

    public Vector2 targetOffset = new Vector2();


        public Vector2 originRotation = new Vector2();
        public bool returnToOrigin = true;
        public float returnSmoothing = 3;

        public float distance = 5;
        public float minDistance = 0;
        public float maxDistance = 10;

        public Vector2 sensitivity = new Vector2(3, 3);

        public float zoomSpeed = 1;
        public float zoomSmoothing = 16;

        public float minAngle = -90;
        public float maxAngle = 90;


        private float _wanted_distance;
        private Quaternion _rotation;
        private Vector2 _input_rotation;

        private CharacterManager _character;
        void Start()
        {
                _wanted_distance = distance;
                _input_rotation = originRotation;
                _character = target.GetComponent<CharacterManager> ();
        }

        void Update()
        {

        }


        void FixedUpdate()
        {

                // Zoom control
                if(InputManager.Instance.GetZoom()==1)
                {
                        _wanted_distance += zoomSpeed;
                }
                else if(InputManager.Instance.GetZoom()==-1)
                {
                        _wanted_distance -= zoomSpeed;
                }

                // Prevent wanted distance from going below or above min and max distance
                _wanted_distance = Mathf.Clamp(_wanted_distance, minDistance, maxDistance);

                // If user clicks, change position based on drag direction and sensitivity
                // Stop at 90 degrees above / below object
                if (InputManager.Instance.isScrolling()) {
                        _input_rotation.x += InputManager.Instance.GetScrollWheel ().x * sensitivity.x;
                        ClampRotation ();
                        _input_rotation.y -= InputManager.Instance.GetScrollWheel ().y * sensitivity.y;
                        _input_rotation.y = Mathf.Clamp (_input_rotation.y, minAngle, maxAngle);
                        _rotation = Quaternion.Euler (_input_rotation.y, _input_rotation.x, 0);
                } else if(returnToOrigin){
                        originRotation = _input_rotation;
                        originRotation.x = 0f;
                        ClampRotation ();
                        _input_rotation = Vector3.Lerp (_input_rotation, originRotation, returnSmoothing * Time.deltaTime);
                }
                _rotation = Quaternion.Euler(new Vector3(_input_rotation.y, _input_rotation.x, 0f));


                distance = Mathf.Clamp(Mathf.Lerp(distance, _wanted_distance, Time.deltaTime * zoomSmoothing), minDistance, maxDistance);

                Vector3 wanted_position = _rotation * new Vector3(targetOffset.x, 0, -_wanted_distance - 0.2f) + new Vector3(0, targetOffset.y, 0);
                wanted_position = target.TransformPoint (wanted_position);
                Vector3 current_position = _rotation * new Vector3(targetOffset.x, 0, 0) + new Vector3(0, targetOffset.y, 0);
                current_position = target.TransformPoint (current_position);

                RaycastHit hit;
                if(Physics.Linecast(current_position, wanted_position, out hit, collisionLayers))
                {
                        distance = Vector3.Distance(current_position, hit.point) - 0.2f;
                }


                // Set the position and rotation of the camera
                wanted_position = _rotation * new Vector3(targetOffset.x, 0f, -distance) + new Vector3(0, targetOffset.y, 0); 
                transform.position = target.TransformPoint (wanted_position);
                transform.rotation = target.rotation*Quaternion.Euler(new Vector3(_input_rotation.y, _input_rotation.x, 0f));
                _character.rotation = _input_rotation.x;
        }

    private void ClampRotation()
    {
        if(originRotation.x < -180)
        {
            originRotation.x += 360;
        }
        else if(originRotation.x > 180)
        {
            originRotation.x -= 360;
        }

        if(_input_rotation.x - originRotation.x < -180)
        {
            _input_rotation.x += 360;
        }
        else if(_input_rotation.x - originRotation.x > 180)
        {
            _input_rotation.x -= 360;
        }
    }
}




评分

参与人数 2鲜花 +7 收起 理由
开拓ay + 5 很给力!
wx_JuCUJiix + 2 神马都是浮云

查看全部评分


回复

使用道具 举报

4四处流浪
499/500
排名
9115
昨日变化
8

0

主题

307

帖子

499

积分

Rank: 4

UID
161170
好友
0
蛮牛币
775
威望
0
注册时间
2016-8-8
在线时间
104 小时
最后登录
2017-9-12
发表于 2017-4-21 08:55:50 | 显示全部楼层
good one!!

回复

使用道具 举报

5熟悉之中
739/1000
排名
3070
昨日变化
2

1

主题

139

帖子

739

积分

Rank: 5Rank: 5

UID
194381
好友
0
蛮牛币
1568
威望
0
注册时间
2016-12-31
在线时间
237 小时
最后登录
2017-9-21
发表于 2017-4-21 09:42:08 | 显示全部楼层

回复

使用道具 举报

5熟悉之中
934/1000
排名
3317
昨日变化
1

0

主题

409

帖子

934

积分

Rank: 5Rank: 5

UID
190737
好友
0
蛮牛币
798
威望
0
注册时间
2017-2-23
在线时间
187 小时
最后登录
2017-9-24
发表于 2017-4-21 10:26:32 | 显示全部楼层
谢谢分享                           

回复 支持 反对

使用道具 举报

4四处流浪
464/500
排名
4968
昨日变化
35

0

主题

95

帖子

464

积分

Rank: 4

UID
207120
好友
0
蛮牛币
624
威望
0
注册时间
2017-2-18
在线时间
157 小时
最后登录
2017-9-23
发表于 2017-4-21 11:04:47 | 显示全部楼层
好牛掰的样子。不错啊

回复 支持 反对

使用道具 举报

7日久生情
2011/5000
排名
573
昨日变化
1

1

主题

530

帖子

2011

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
111260
好友
0
蛮牛币
7301
威望
0
注册时间
2015-6-30
在线时间
342 小时
最后登录
2017-9-23
发表于 2017-4-21 11:17:51 | 显示全部楼层
谢谢分享                           

回复 支持 反对

使用道具 举报

7日久生情
1757/5000
排名
17035
昨日变化
8

2

主题

1478

帖子

1757

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
185807
好友
0
蛮牛币
2328
威望
0
注册时间
2016-11-22
在线时间
253 小时
最后登录
2017-9-22
发表于 2017-4-21 17:59:41 | 显示全部楼层
赞,学习了,谢谢分享

回复 支持 反对

使用道具 举报

7日久生情
2011/5000
排名
573
昨日变化
1

1

主题

530

帖子

2011

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
111260
好友
0
蛮牛币
7301
威望
0
注册时间
2015-6-30
在线时间
342 小时
最后登录
2017-9-23
发表于 2017-4-22 08:53:13 | 显示全部楼层
谢谢分享                           

回复 支持 反对

使用道具 举报

5熟悉之中
710/1000
排名
2245
昨日变化
13

8

主题

39

帖子

710

积分

Rank: 5Rank: 5

UID
165566
好友
0
蛮牛币
1441
威望
0
注册时间
2016-10-8
在线时间
173 小时
最后登录
2017-9-23
发表于 2017-4-23 09:49:32 | 显示全部楼层
感谢分享

回复

使用道具 举报

排名
27751
昨日变化
18

1

主题

6

帖子

22

积分

Rank: 1

UID
124393
好友
0
蛮牛币
1097
威望
0
注册时间
2015-10-1
在线时间
7 小时
最后登录
2017-4-24
发表于 2017-4-23 14:35:50 | 显示全部楼层
不知所云?楼上的人看懂了?????

回复 支持 反对

使用道具 举报

排名
17682
昨日变化
8

0

主题

21

帖子

65

积分

Rank: 2Rank: 2

UID
207440
好友
0
蛮牛币
46
威望
0
注册时间
2017-2-20
在线时间
22 小时
最后登录
2017-8-14
发表于 2017-4-23 21:45:16 | 显示全部楼层
感谢楼主。。。。。。。

回复

使用道具 举报

排名
17682
昨日变化
8

0

主题

21

帖子

65

积分

Rank: 2Rank: 2

UID
207440
好友
0
蛮牛币
46
威望
0
注册时间
2017-2-20
在线时间
22 小时
最后登录
2017-8-14
发表于 2017-4-23 21:59:14 | 显示全部楼层
支持 好帖子!!!!!

回复

使用道具 举报

排名
17682
昨日变化
8

0

主题

21

帖子

65

积分

Rank: 2Rank: 2

UID
207440
好友
0
蛮牛币
46
威望
0
注册时间
2017-2-20
在线时间
22 小时
最后登录
2017-8-14
发表于 2017-4-23 22:41:32 | 显示全部楼层
感谢楼主!!!!!

回复

使用道具 举报

3偶尔光临
245/300
排名
5921
昨日变化
3

0

主题

22

帖子

245

积分

Rank: 3Rank: 3Rank: 3

UID
215959
好友
0
蛮牛币
1776
威望
0
注册时间
2017-4-2
在线时间
53 小时
最后登录
2017-8-1
发表于 2017-4-26 21:47:10 | 显示全部楼层
谢谢楼主分享!

回复

使用道具 举报

排名
31624
昨日变化
17

0

主题

41

帖子

75

积分

Rank: 2Rank: 2

UID
220368
好友
0
蛮牛币
-5
威望
0
注册时间
2017-5-3
在线时间
28 小时
最后登录
2017-9-20
发表于 2017-5-12 20:33:05 | 显示全部楼层
感谢楼主啦

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表