惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
博客园 - Franky
GbyAI
GbyAI
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
爱范儿
爱范儿
IT之家
IT之家
酷 壳 – CoolShell
酷 壳 – CoolShell
aimingoo的专栏
aimingoo的专栏
博客园_首页
MongoDB | Blog
MongoDB | Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Recent Announcements
Recent Announcements
Scott Helme
Scott Helme
有赞技术团队
有赞技术团队
M
MIT News - Artificial intelligence
C
CERT Recently Published Vulnerability Notes
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Jina AI
Jina AI
F
Fortinet All Blogs
N
Netflix TechBlog - Medium
L
LangChain Blog
L
LINUX DO - 最新话题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Hacker News: Front Page
MyScale Blog
MyScale Blog
P
Palo Alto Networks Blog
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
AI
AI
T
Troy Hunt's Blog
Microsoft Azure Blog
Microsoft Azure Blog
阮一峰的网络日志
阮一峰的网络日志
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Vercel News
Vercel News
Microsoft Security Blog
Microsoft Security Blog
罗磊的独立博客
S
Secure Thoughts
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗
人人都是产品经理
人人都是产品经理
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
S
Security @ Cisco Blogs
Cloudbric
Cloudbric
E
Exploit-DB.com RSS Feed
Attack and Defense Labs
Attack and Defense Labs

博客园 - Len3d

研报和信息查询网站 研报查询链接 初步测试了一下C++11的async/future 徒手画个disk不容易啊。。。 fast powf SSE sqrt还是比C math库的sqrtf快了不少 Mongoose也是个大坑 A tiny program to benchmark image transpose algorithms On extracting ops from LLVM backend Into concurrent LRU caching once again 性能大坑 多项式在线拟合神器 iOS app开发资料整理 Windows上使用clang编译 - Len3d nodejs Rpath handling on Linux C++ Web Service SDK Fast integer math tricks for C Point in polygon algorithm C code
完美的视图旋转算法
Len3d · 2016-05-26 · via 博客园 - Len3d

这里说的视图旋转不是FPS游戏里面那种第一人称的视图旋转,那个处理起来比较自然。这里说的视图旋转是类似3ds Max, Maya这种3D设计软件里面的第三人称的视图旋转。有的系统里面叫做tumble,有的人习惯叫orbit,有的系统里面干脆就叫rotate。不管怎样,这个看似非常基础的算法,网上居然几乎找不到理想的方法说明,我简直震惊了。好吧,经过一些实验,自己写了一个算法,经测试各种角度的旋转都是完美的,共享出来大家鉴定下。如果有更好的算法,还请留言告诉我。我们先来看看实现:

eiBool need_init;
eiNode *cam_inst = ei_edit_node(cam_inst_name, &need_init);

eiIndex xform_pid = ei_node_find_param(cam_inst, "transform");
eiIndex motion_xform_pid = ei_node_find_param(cam_inst, "motion_transform");
eiMatrix xform_val = *ei_node_get_matrix(cam_inst, xform_pid);

eiVector up_vector = ei_vector(0.0f, 0.0f, 1.0f);
eiVector camera_pos = point_transform(ei_vector(0.0f, 0.0f, 0.0f), xform_val);
eiVector cam_up = normalize(vector_transform(ei_vector(0.0f, 1.0f, 0.0f), xform_val));
eiVector cam_right = normalize(vector_transform(ei_vector(1.0f, 0.0f, 0.0f), xform_val));
eiVector cam_dir = normalize(vector_transform(ei_vector(0.0f, 0.0f, -1.0f), xform_val));
if (!target_set) /* initialize camera to align with original view */
{
	eiVector obj_center = ei_vector(0.0f, 0.0f, 0.0f);
	point_on_plane(camera_target, camera_pos, -cam_dir, obj_center);
	target_set = EI_TRUE;
}
eiVector target_vec = camera_pos - camera_target;
eiScalar target_dist = normalize_len(target_vec, target_vec);
/* make horizontal speed slower when approaching up vector */
eiScalar horiz_speed = 1.0f - 0.7f * absf(dot(up_vector, target_vec));
target_vec = vector_transform(target_vec, rotate(radians(offset[0] * -0.2f * horiz_speed), cam_up));
target_vec = vector_transform(target_vec, rotate(radians(offset[1] * -0.2f), cam_right));
camera_pos = camera_target + target_vec * target_dist;
eiVector camera_dir_z = target_vec;
eiVector camera_dir_x = cross(up_vector, camera_dir_z);
if (absf(dot(up_vector, camera_dir_z)) > 0.99f) /* fix up vector precision issue */
{
	eiVector fixed_up = cross(camera_dir_z, cam_right);
	camera_dir_x = cross(fixed_up, camera_dir_z);
}
if (dot(cam_right, camera_dir_x) < 0.0f) /* fix sudden flip when approaching up vector */
{
	camera_dir_x = - camera_dir_x;
}
eiVector camera_dir_y = cross(camera_dir_z, camera_dir_x);

xform_val = ei_matrix(
	camera_dir_x.x, camera_dir_x.y, camera_dir_x.z, 0.0f, 
	camera_dir_y.x, camera_dir_y.y, camera_dir_y.z, 0.0f, 
	camera_dir_z.x, camera_dir_z.y, camera_dir_z.z, 0.0f, 
	camera_pos.x, camera_pos.y, camera_pos.z, 1.0f);

ei_node_set_matrix(cam_inst, xform_pid, &xform_val);
ei_node_set_matrix(cam_inst, motion_xform_pid, &xform_val);

ei_end_edit_node(cam_inst);

实现是基于Elara SDK写的(Elara是一个离线渲染器,详见:www.elarafx.com),不过都是基本的数学函数,看起来应该不复杂,我就不改写了。

说一下比较核心的几个地方:

1. 一定要基于up vector构造新的摄像机坐标系,否则我发现总会产生转多了视图倾斜的问题。up vector的方向也是不同的系统中使用这个算法需要注意的地方,这里用的是跟3ds Max兼容的up vector即Z轴朝上方向。

2. 初始化的时候,一定要计算好摄像机target点的位置,否则第一次旋转会产生跳变。

3. 因为基于up vector构造坐标系,一定要处理下摄像机朝向旋转到与up vector很接近的方向时候的精度问题。

4. 当旋转过顶部的时候,由于与up vector叉乘产生的向量的方向突变,所以会产生跳变,这里要特殊处理一下。

5. 摄像机朝向越接up vector的方向,绕up vector旋转的速度应该越慢,这样看起来不会产生跳跃感。

6. point_on_plane算法中,要取绝对值,不能用signed distance,以保证camera target总在摄像机朝向的前方。