OpenGL - позиционировать камеру с вектором 6 степеней свободы - PullRequest
0 голосов
/ 26 апреля 2011

Я работаю с платформой дополненной реальности на 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 Ответ

1 голос
/ 26 апреля 2011

«Хитрость» в том, чтобы понять, что в OpenGL нет камеры. Что делает, так это трансформирует весь мир движением, полностью противоположным тому, что камеру нужно было бы переместить из положения (0,0,0).

Такие преобразования (= движения) описываются в форме так называемых матриц однородного преобразования . Фиксированная функция OpenGL использует комбинацию из двух матриц:

  • Modelview M , который описывает расположение мира и вида (и объектов в мире в некоторой степени).
  • Проекция P , которую можно рассматривать как своего рода «объектив» виртуальной камеры (помните, что в OpenGL камеры нет).

Любая позиция вершины v преобразуется в c = P * M * v ( c - это преобразованная координата вершины в пространстве клипа, то есть в экранном пространстве не в пикселях, а с краями экрана в -1, 1 - область просмотра затем отображается из пространства клипа в пространство пикселов экрана).

То, что дает вам Android, - это такая матрица преобразования. Я не уверен, но, глядя на значения, это может быть, что вы получили P * M . Пока освещение не задействовано, вы можете загрузить его непосредственно в матрицу просмотра модели, используя glLoadMatrix, и проекция будет установлена ​​на идентичность. Вы передаете матрицы в OpenGL как массив из 16 чисел с плавающей запятой; Порядок индексации OpenGL иногда смущает людей, но то, как вы сбросили матрицы Android, я думаю, что вы уже поняли их правильно (вы напечатали их «неправильно», транспонировали, то есть, это та же ловушка, с которой сталкиваются люди с OpenGL glLoadMatrix, но две Если транспонировать - это тождество, то, вероятно, это правильно. Если сначала это не сработает, переверните столбец и строки, т. е. «отразите» матрицу по ее диагонали, идущую сверху вниз, сделайте снизу справа).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...