贴花的几何变换
目录 | 前情提要几何变换:平移/旋转/缩放平移:以“我”为起点的射线追踪旋转:法线贴花、暴露翻滚角缩放:线性增长的相对速率蓝图入口细节优化演示 |
---|
- 前情提要
- 几何变换:平移/旋转/缩放
- 平移:以“我”为起点的射线追踪
- 旋转:法线贴花、暴露翻滚角
- 缩放:线性增长的相对速率
- 蓝图入口
- 细节优化
- 演示
前情提要
在上一篇文章中我完成了整个流出的前半部分:让用户从电脑中选择图片,自动制作成UE4贴花,并贴到地面上。本文讨论如何在非地面的平面/曲面上动态贴贴花。3D引擎中的贴花(decal)技术是以射影几何学为基础的投影材质,相比于表面材质(surface material),轻量的贴花材质在特定场合下有更好的性能,比如贴海报、静态液体、局部纹理,本文讨论贴花后半部分关于空间几何变换的基本原理。
几何变换:平移/旋转/缩放
无论在二维空间还是三维空间,物体的几何变换都围绕着平移、旋转、缩放而展开,只是3维空间需要考虑空间直角坐标系(笛卡尔坐标系)x、y、z三个维度的变换值,其中由系统自动设定的维度值我们称作"隐含维度",需要由用户操作决定的维度值称作"显式维度"。总共3*3=9个维度变量中,由用户输入决定的只有4个,剩下5个变量由系统自动维护,下面我们来一一解释这个原则。
单位 | 几何变换 | 隐含维度 | 显式维度 | |
---|---|---|---|---|
平移 | 单位1/厘米 | 相对于坐标原点的x/y/z轴偏量 | 1 | 2 |
旋转 | 角度/弧度 | 以主视角和地心为基准的俯仰角、偏航角、翻滚角 | 2 | 1 |
缩放 | 倍数/百分比 | 3个直角分量相对于原始尺寸的增量 | 2 | 1 |
平移:以“我”为起点的射线追踪
射线追踪(line trace)是物理引擎中重要的组成部分,多数射击游戏都需要锁定射线命中的物体本体,虚幻引擎提供了射线追踪的良好支持。在我们动态贴画的场景中,希望能实现这样的效果:当用户指定屏幕上的某一点就能于这一点所在的物体表面贴上一层贴花。这个需求抽象出来就是要利用射线追踪技术,以主视摄像机为起点,摄像机的朝向为方向向量发出射线,再根据撞击点的法线确定贴花方向。
鼠标平移作为最常用的二维连续型输入设备,总是被用来控制人物/镜头的朝向(单位球面),我们的贴花项目中也不例外,让鼠标来决定贴花平移的这2个维度,剩下一个维度自然由射线的长度决定,所以"隐含维度"只有1个。
旋转:法线贴花、暴露翻滚角
法线贴图本身指利用图片的alpha通道存储像素的第三维度,通过人眼对色光的抽象能力模拟出图片的立体效果。法线贴花即根据射线追踪的撞击点所在平面的切线的法线向量(二维向量)决定贴花的俯仰角(pitch)和偏航角(yaw)。虽然空间向量是(x,y,z)三个维度,但方向向量由于模长始终为1,即X^2 Y^2 Z^2=1,z可以写成(1-X^2-Y^2)^0.5,所以终点位于单位球面的方向向量实质上是2维向量。
但是贴花actor的旋转是三维的,而法线只暴露了其中2个维度,即俯仰角和偏航角,剩下的翻滚角(roll)只能让用户来决定。飞行游戏中(直升机除外),键盘控制规则一般会遵守这个默认习惯:W/S键控制飞机俯仰,Z/C键控制飞机偏航,A/D键控制飞机翻滚。我们也可以采用这种模式来操作贴花围绕法线的翻滚角。
缩放:线性增长的相对速率
解决了平移和旋转,缩放就简单多了,虽然缩放是3个维度的考量,但由于贴花本身是一张图片,投影深度(即主视轴)可以写死一个固定值(比如400),还剩剩下长和宽2个维度,又因为大多情况下需要锁定纵横比,所以只剩下1个维度暴露给用户操作,这里推荐使用鼠标滚轮来输入这个线性变量。
关于主轴缩放的速度,不建议使用绝对速度,而应该使用相对速度,简单地说,就是缩放速度和物体尺寸成正比。因为这种设计模式符合用户习惯:我们在手机端翻滚很长的网页时,手指滑动速度并不和页面滚动速度并一致,而是后者的加速度。同理,每次缩放的增量不是一个固定值而是原来尺寸的固定倍数(比如1.1)。除此之外,缩放需要有边界以免失控,比如上限设为1000%,下限设为5%。
蓝图入口
蓝图入口是所有代码的索引,本文展示所有蓝图/C 分支的入口,代码明细存储在额外的仓库,就不展示了。
- Event BeginPlay:初始化设置
- Event Tick:计算每一帧的射线追踪
- Right Mouse Button:鼠标右键上传新的图片
- Space Bar:空格键黏贴新的贴图
- Mouse Wheel Up:鼠标前滚放大
- Mouse Wheel Down:鼠标后滚缩小
- InputAxis Rotate:顺时针/逆时针旋转(翻滚)
- InputAxis Accelerate:调整移动速度
细节优化
- 贴花模型:平移旋转缩放的对象是可视化模型,最终确定下来后才复制一份静态贴花。
- 贴花优先级:在同一切面上不同的贴花之间的展示优先级应该遵守“后来者居上”的原则。
- 实时状态:使用Widget制作UI界面展示当前的状态(如旋转角和缩放比)以及鼠标/键盘的操作提示。
- 射线长度上限:设定射线追踪的长度上限(如10000)以避免无穷远点和足够远点,节省资源。
- 输入模式切换:贴花的输入模式由于没有重力限制,不同于普通的输入模式(如人物行走),需要需要在2者间做好合适的切换。
演示
<完>