LookAt 实施不当行为
Posted
技术标签:
【中文标题】LookAt 实施不当行为【英文标题】:LookAt Implementation Misbehaviors 【发布时间】:2012-06-13 04:42:24 【问题描述】:我期待实现一个 LookAt(forward, up) 方法,其中:
Vector3 forward = eyePosition - targetPosition;
Vector3 up;
我在网上看到了一些实现,但分析代码时,我发现了潜在的不当行为......
我从最简单到最难列出它们:
1) 如果 UP 是零向量,这将不起作用。
2) 如果 FORWARD 是零向量,这将不起作用。
3) 如果 UP 和 FORWARD 是平行的,这将不起作用。
...
那么..这个方法应该如何正确实现呢?
这是我找到的一个代码示例。
/*
* gluLookAt.h
*
* This is a modified version of the function of the same name from
* the Mesa3D project ( http://mesa3d.org/ ), which is licensed
* under the MIT license, which allows use, modification, and
* redistribution
*
* In order to work under OpenGL ES, all instances of GLdouble
* had to be changed to GLfloat, and all "d" function calls had
* to be changed to the "f" versions.
*
* Original developer's comments have been left in place.
*
* Out of respect for the original authors, this is licensed under
* the Mesa (MIT) license. Original license follows:
*
* -----------------------------------------------------------------------
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#import <Foundation/Foundation.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez,
GLfloat centerx, GLfloat centery, GLfloat centerz,
GLfloat upx, GLfloat upy, GLfloat upz);
gluLookAt.m
/*
* gluLookAt.c
*/
#include "gluLookAt.h"
void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez,
GLfloat centerx, GLfloat centery, GLfloat centerz,
GLfloat upx, GLfloat upy, GLfloat upz)
GLfloat m[16];
GLfloat x[3], y[3], z[3];
GLfloat mag;
/* Make rotation matrix */
/* Z vector */
z[0] = eyex - centerx;
z[1] = eyey - centery;
z[2] = eyez - centerz;
mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
if (mag) /* mpichler, 19950515 */
z[0] /= mag;
z[1] /= mag;
z[2] /= mag;
/* Y vector */
y[0] = upx;
y[1] = upy;
y[2] = upz;
/* X vector = Y cross Z */
x[0] = y[1] * z[2] - y[2] * z[1];
x[1] = -y[0] * z[2] + y[2] * z[0];
x[2] = y[0] * z[1] - y[1] * z[0];
/* Recompute Y = Z cross X */
y[0] = z[1] * x[2] - z[2] * x[1];
y[1] = -z[0] * x[2] + z[2] * x[0];
y[2] = z[0] * x[1] - z[1] * x[0];
/* mpichler, 19950515 */
/* cross product gives area of parallelogram, which is < 1.0 for
* non-perpendicular unit-length vectors; so normalize x, y here
*/
mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
if (mag)
x[0] /= mag;
x[1] /= mag;
x[2] /= mag;
mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
if (mag)
y[0] /= mag;
y[1] /= mag;
y[2] /= mag;
#define M(row,col) m[col*4+row]
M(0, 0) = x[0];
M(0, 1) = x[1];
M(0, 2) = x[2];
M(0, 3) = 0.0;
M(1, 0) = y[0];
M(1, 1) = y[1];
M(1, 2) = y[2];
M(1, 3) = 0.0;
M(2, 0) = z[0];
M(2, 1) = z[1];
M(2, 2) = z[2];
M(2, 3) = 0.0;
M(3, 0) = 0.0;
M(3, 1) = 0.0;
M(3, 2) = 0.0;
M(3, 3) = 1.0;
#undef M
glMultMatrixf(m);
/* Translate Eye to Origin */
glTranslatef(-eyex, -eyey, -eyez);
【问题讨论】:
根据您对函数应如何对退化参数值作出反应的理念,此实现很好。如果您提供退化的参数,大多数 OpenGL 的行为都会很糟糕。确保有意义的参数的负担放在程序员身上。您的条件 1-3 排除了有效的场景视图,因此不良行为至少与 OpenGL 的其余部分一致。如果您想要一个检查其参数的 gluLookAt 版本,只需为此编写一个包装器。 【参考方案1】:好的.. 我刚刚想到了解决这个问题的想法。我还没有测试它,甚至还没有编写代码,但我分享了讨论它的想法,我感谢你的意见!
伪代码:(使用列主矩阵和右手坐标系)
// transformation matrix (column major)
float matrix[16];
void crossProduct( const flaot a[3], const float b[3], float result[3] )
result[0] = a[1] * b[2] - a[2] * b[1];
result[1] = -a[0] * b[2] + a[2] * b[0];
result[2] = a[0] * b[1] - a[1] * b[0];
void LookAt( float forward[3], float up[3] )
// get forward length
int length = sqrt( forward[0] * forward[0] + forward[1] * forward[1] + forward[2] * forward[2] );
// if not zero, normalize it
if ( length )
forward[0] /= length;
forward[1] /= length;
forward[2] /= length;
else
// get last forward direction
forward[0] = matrix[8];
forward[1] = matrix[9];
forward[2] = matrix[10];
// get up length
length = sqrt( up[0] * up[0] + up[1] * up[1] + up[2] * up[2] );
// if not zero, normalize it
if ( length )
up[0] /= length;
up[1] /= length;
up[2] /= length;
else
// get last up direction
up[0] = matrix[4];
up[1] = matrix[5];
up[2] = matrix[6];
float left[3];
crossProduct( up, forward, left);
// if cross product is zero, forward and up are parallels. get last left direction
if ( left[0]==0 && left[1]==0 && left[2]==0 )
left[0] = matrix[0];
left[1] = matrix[1];
left[2] = matrix[2];
// recalculate orthogonal up
crossProduct( forward, left, up );
// update matrix values
matrix[0] = left[0];
matrix[1] = left[1];
matrix[2] = left[2];
matrix[3] = 0;
matrix[4] = up[0];
matrix[5] = up[1];
matrix[6] = up[2];
matrix[7] = 0;
matrix[8] = forward[0];
matrix[9] = forward[1];
matrix[10] = forward[2];
matrix[11] = 0;
matrix[12] = 0;
matrix[13] = 0;
matrix[14] = 0;
matrix[15] = 1;
【讨论】:
以上是关于LookAt 实施不当行为的主要内容,如果未能解决你的问题,请参考以下文章