OpenGL - 具有6个自由度矢量的定位相机

时间:2011-04-26 01:59:42

标签: opengl

我使用Android上的增强现实框架,它为我提供了相机位置作为6自由度矢量,包括估计的相机光学和相机方向。

由于我是OpenGL的新手,我不太明白这意味着什么,我的问题是 - 如何使用这个4x4矩阵将我的相机定位在OpenGL中。

以下是来自Android SDK的示例,它呈现了一个简单的纹理三角形(我不知道哪些细节很重要,所以我包括了整个两个类 - 渲染器和三角形对象)。

我的猜测是它将相机与gluLookAt放在onDrawFrame()中。我想调整一下, 我从框架中收到这些矩阵(这些只是样本) -

当相机直视三角形时,我需要使用这种类型的矩阵以某种方式定位我的相机:

 0.9930384    0.045179322   0.10878302   0.0
-0.018241059  0.9713616    -0.23690554   0.0 
-0.11637083   0.23327199    0.9654233    0.0 
 21.803288   -14.920643    -150.6514     1.0 

当我将相机移动一点距离时:

 0.9763242    0.041258257   0.21234424   0.0 
 0.014808476  0.96659267   -0.2558918    0.0 
-0.21580763   0.25297752    0.94309634   0.0 
 17.665      -18.520836    -243.28784    1.0 

当我向右倾斜相机时:

 0.8340566    0.0874321     0.5447095    0.0 
 0.054606464  0.96943074   -0.23921578   0.0 
-0.5489726    0.22926341    0.8037848    0.0 
-8.809776    -7.5869675    -244.01971    1.0 

有什么想法?我的猜测是,唯一重要的是实际上是最后一行,其他一切都接近于零。

我很乐意获得有关如何调整此代码以使用这些矩阵的任何建议,包括设置透视矩阵或任何设置(再次,新手)。

public class TriangleRenderer implements GLSurfaceView.Renderer{

public TriangleRenderer(Context context) {
    mContext = context;
    mTriangle = new Triangle();
}

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    /*
     * By default, OpenGL enables features that improve quality
     * but reduce performance. One might want to tweak that
     * especially on software renderer.
     */
    gl.glDisable(GL10.GL_DITHER);

    /*
     * Some one-time OpenGL initialization can be made here
     * probably based on features of this particular context
     */
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
            GL10.GL_FASTEST);

    gl.glClearColor(0,0,0,0);
    gl.glShadeModel(GL10.GL_SMOOTH);
    gl.glEnable(GL10.GL_DEPTH_TEST);
    gl.glEnable(GL10.GL_TEXTURE_2D);

    /*
     * Create our texture. This has to be done each time the
     * surface is created.
     */

    int[] textures = new int[1];
    gl.glGenTextures(1, textures, 0);

    mTextureID = textures[0];
    gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);

    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
            GL10.GL_NEAREST);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D,
            GL10.GL_TEXTURE_MAG_FILTER,
            GL10.GL_LINEAR);

    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
            GL10.GL_CLAMP_TO_EDGE);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
            GL10.GL_CLAMP_TO_EDGE);

    gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
            GL10.GL_REPLACE);

    InputStream is = mContext.getResources()
            .openRawResource(R.raw.robot);
    Bitmap bitmap;
    try {
        bitmap = BitmapFactory.decodeStream(is);
    } finally {
        try {
            is.close();
        } catch(IOException e) {
            // Ignore.
        }
    }

    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
    bitmap.recycle();
}

public void onDrawFrame(GL10 gl) {
    /*
     * By default, OpenGL enables features that improve quality
     * but reduce performance. One might want to tweak that
     * especially on software renderer.
     */
    gl.glDisable(GL10.GL_DITHER);

    gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
            GL10.GL_MODULATE);

    /*
     * Usually, the first thing one might want to do is to clear
     * the screen. The most efficient way of doing this is to use
     * glClear().
     */

    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

    /*
     * Now we're ready to draw some 3D objects
     */

    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();

    GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    gl.glActiveTexture(GL10.GL_TEXTURE0);
    gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
    gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
            GL10.GL_REPEAT);
    gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
            GL10.GL_REPEAT);

    long time = SystemClock.uptimeMillis() % 4000L;
    float angle = 0.090f * ((int) time);

    gl.glRotatef(angle, 0, 0, 1.0f);

    mTriangle.draw(gl);
}

public void onSurfaceChanged(GL10 gl, int w, int h) {
    gl.glViewport(0, 0, w, h);

    /*
    * Set our projection matrix. This doesn't have to be done
    * each time we draw, but usually a new projection needs to
    * be set when the viewport is resized.
    */

    float ratio = (float) w / h;
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();
    gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);

}

private Context mContext;
private Triangle mTriangle;
private int mTextureID;} class Triangle {
public Triangle() {

    // Buffers to be passed to gl*Pointer() functions
    // must be direct, i.e., they must be placed on the
    // native heap where the garbage collector cannot
    // move them.
    //
    // Buffers with multi-byte datatypes (e.g., short, int, float)
    // must have their byte order set to native order

    ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
    vbb.order(ByteOrder.nativeOrder());
    mFVertexBuffer = vbb.asFloatBuffer();

    ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4);
    tbb.order(ByteOrder.nativeOrder());
    mTexBuffer = tbb.asFloatBuffer();

    ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
    ibb.order(ByteOrder.nativeOrder());
    mIndexBuffer = ibb.asShortBuffer();

    // A unit-sided equalateral triangle centered on the origin.
    float[] coords = {
            // X, Y, Z
            -0.5f, -0.25f, 0,
             0.5f, -0.25f, 0,
             0.0f,  0.559016994f, 0
    };

    for (int i = 0; i < VERTS; i++) {
        for(int j = 0; j < 3; j++) {
            mFVertexBuffer.put(coords[i*3+j] * 2.0f);
        }
    }

    for (int i = 0; i < VERTS; i++) {
        for(int j = 0; j < 2; j++) {
            mTexBuffer.put(coords[i*3+j] * 2.0f + 0.5f);
        }
    }

    for(int i = 0; i < VERTS; i++) {
        mIndexBuffer.put((short) i);
    }

    mFVertexBuffer.position(0);
    mTexBuffer.position(0);
    mIndexBuffer.position(0);
}

public void draw(GL10 gl) {
    gl.glFrontFace(GL10.GL_CCW);
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
    gl.glEnable(GL10.GL_TEXTURE_2D);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexBuffer);
    gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, VERTS,
            GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
}

private final static int VERTS = 3;

private FloatBuffer mFVertexBuffer;
private FloatBuffer mTexBuffer;
private ShortBuffer mIndexBuffer;

1 个答案:

答案 0 :(得分:1)

“技巧”是要理解,OpenGL没有相机。它的作用是通过一个与相机必须从位置(0,0,0)移动的运动完全相反的运动来改变整个世界。

这种变换(=运动)以所谓的同质变换矩阵的形式描述。固定功能OpenGL使用两个矩阵的组合:

  • 模型视图 M ,它描述了世界和视图(以及某种程度上世界范围内的对象)的位置。
  • 投影 P ,可以看作虚拟相机的“镜头”(请记住,OpenGL中没有相机)。

任何顶点位置 v c = P * M * v 转换( c 是剪辑空间中的变换顶点坐标,屏幕空间不是像素,而是屏幕边缘为-1,1 - 视口然后从剪辑空间映射到屏幕像素空间。

Android给你的是这样一个转换矩阵。我不确定,但看看它可能的价值,你得到 P * M 。只要不涉及光照,您可以使用glLoadMatrix将其直接加载到模型视图矩阵中,并将投影设置为标识。您将矩阵作为16个浮点数组传递给OpenGL; OpenGL的索引顺序有时会让人感到困惑,但你倾倒android矩阵的方式我认为你已经把它们弄好了(你把它们打印成“错误”,转换就是,这与人们陷入OpenGL glLoadMatrix的陷阱相同,但是两个时间转置是身份,它可能是正确的。如果它最初不起作用,则翻转列和行,即“镜像”从左上角开始的对角线上的矩阵做右下角。)