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 实施不当行为的主要内容,如果未能解决你的问题,请参考以下文章

评论系统的实施(Facebook赞)

网络安全审计介绍与部署实施

征信画像项目实施文档摘要

glm lookAt 和矩阵变换产生奇怪的行为

蜜罐技术——通过布置一些作为诱饵的主机网络服务或者信息,诱使攻击方对它们实施攻击,从而可以对攻击行为进行捕获和分析

爬虫技术罪与罚