这回转脸algorithm有什么问题?

我实现了追逐一个旋转的星球的鱼雷物体。 具体来说,它会转向每个更新的星球。 最初我的工具是:

void move() { vector3<float> to_target = target - get_position(); to_target.normalize(); position += (to_target * speed); } 

这对完美的鱼雷来说是一个坚实的球体。 现在我的鱼雷实际上是一个模型,它有一个向前的向量,所以使用这个方法看起来很奇怪,因为它实际上并没有转向,而是向着跳跃。 所以我修改了一下得到了,

 double get_rotation_angle(vector3<float> u, vector3<float> v) const { u.normalize(); v.normalize(); double cosine_theta = u.dot(v); // domain of arccosine is [-1, 1] if (cosine_theta > 1) { cosine_theta = 1; } if (cosine_theta < -1) { cosine_theta = -1; } return math3d::to_degree(acos(cosine_theta)); } vector3<float> get_rotation_axis(vector3<float> u, vector3<float> v) const { u.normalize(); v.normalize(); // fix linear case if (u == v || u == -v) { v[0] += 0.05; v[1] += 0.0; v[2] += 0.05; v.normalize(); } vector3<float> axis = u.cross(v); return axis.normal(); } void turn_to_face() { vector3<float> to_target = (target - position); vector3<float> axis = get_rotation_axis(get_forward(), to_target); double angle = get_rotation_angle(get_forward(), to_target); double distance = math3d::distance(position, target); gl_matrix_mode(GL_MODELVIEW); gl_push_matrix(); { gl_load_identity(); gl_translate_f(position.get_x(), position.get_y(), position.get_z()); gl_rotate_f(angle, axis.get_x(), axis.get_y(), axis.get_z()); gl_get_float_v(GL_MODELVIEW_MATRIX, OM); } gl_pop_matrix(); move(); } void move() { vector3<float> to_target = target - get_position(); to_target.normalize(); position += (get_forward() * speed); } 

逻辑很简单,我通过叉积来find旋转轴,由点积旋转的角度,然后向目标位置每次更新。 不幸的是,由于旋转发生得太快而总是来回转动,所以看起来极有可能。 鱼雷的正向vector来自ModelViewmatrix,第三列A

  MODELVIEW MATRIX -------------------------------------------------- RUAT -------------------------------------------------- 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 -------------------------------------------------- 

任何建议或想法将不胜感激。

编辑
在我目前的实施中,我没有forwardvector,唯一的vector是positionOM是我的定位matrix。 另外,在任何对象更新之前,我都会调用glu_look_at ,这就是为什么我必须存储OM所有对象转换,这样才能更轻松地检查碰撞。 简而言之,
vector3<float> get_forward() :返回第三列。
vector3<float> get_position() :返回vector3<float> get_position()列。
vector3<float> get_up_vector() :返回第二列。

而在我的绘画例程中,

 void draw() { gl_push_matrix(); { // camera is set here ... // ... gl_mult_matrix_f(OM); // draw } gl_pop_matrix(); } 

目前看起来你正在将鱼雷的旋转(在模型视图matrix中)设置为错误的角度。 你计算的角度是在鱼雷面临的向量( forward )和to_target 。 这对于确定要转多远是有用的,但是用正确的方向显示鱼雷需要从单位matrix转向forward

维护matrix

每次打电话给turn_to_face ,不要重新创建一个matrix,而要维护一个matrix,而且每次只需转换和旋转matrix可能会更容易一些。

 matrix44<float> position_and_rotation; // Or whatever class you have. ... void turn_to_face() { ... position_and_rotation.rotate(axis, angle); glMultMatrixf(position_and_rotation.data()); // Where data() returns a raw // pointer to the underlying // data of the matrix. ... } void move() { position_and_rotation.translate(get_forward() * speed); } 

随时间旋转

我上面写的是接近正确的,但它仍然是错误的。 它不会把你的鱼雷转向地球,它会直接将它转向地球,只需一个电话就可以turn_to_face 。 要逐渐将其转化,您需要定义一个rotational_speed

 position_and_rotation.rotate(axis, min(rotational_speed, angle)); 

这意味着您在打电话给turn_to_face过程中不会超过rotational_speed ,也会阻止您不断地超出正确的方向。

小事

你需要确保你总是朝着你所面对的方向前进。 目前我无法看到任何forward更新的地方。

get_rotation_angle您正在对两个向量进行归一化,这意味着点积的范围已经是[-1,1](您不需要手动钳制到该范围)。

to_target中的turn_to_face函数中的move函数和distance都没有使用,所以摆脱了他们的:)

正如Gary已经提到的那样,你需要把鱼雷的局部前向向量计算(不一定是身份matrix的第三行,取决于你的模型是如何创建的)。 如果鱼雷的本地前进向量不同,请在那里改变。

你的代码中有4件事改变了:

  1. 改名为to_target forward并引入forward_torpedo_local
  2. 不要在这里使用gl_load_identity() ,它会弄乱你的相机设置
  3. move()代码move()turn_to_face() ,因为它只是一行代码
  4. 实际上在渲染之前移动鱼雷,否则腐烂和pos是不同步的

这里是代码:

 void turn_to_face() { vector3<float> forward_torpedo_local(0.0, 0.0, 1.0); vector3<float> forward = (target - position); forward.normalize(); position += (forward * speed); vector3<float> axis = get_rotation_axis(forward_torpedo_local, forward); double angle = get_rotation_angle(forward_torpedo_local, forward); gl_matrix_mode(GL_MODELVIEW); gl_push_matrix(); { gl_translate_f(position.get_x(), position.get_y(), position.get_z()); gl_rotate_f(angle, axis.get_x(), axis.get_y(), axis.get_z()); } gl_pop_matrix(); } 

在调用get_rotation_axis和get_rotation_angle之前,应该对vector进行归一化处理,而不是在这些函数内部进行归一化处理,但是这只是一个次要的优化。