在 Android OpenGL ES 中创建 3D 道路

问题描述 投票:0回答:2

我正在尝试在 Android 中创建一个简单的游戏。我所说的“道路”是指像

Temple Run
Subway Surf
这样的游戏,但更简单和抽象,所以我只能使用 OpenGL ES 来完成它,而无需任何其他库。 所以我读了很多解释 3D 构造逻辑的基础教程,并使用了创建旋转 3D 立方体的基本示例。

我现在正在尝试使用该示例来创建游戏道路。我使正方形看起来更像一个矩形,并将其复制到 30x5 的正方形道路上。我尝试了很多组合和互联网来找到解决方案,但我遇到了这个问题\问题:

  1. 如何将所有 30x5 方块设置为相邻的?我总是 得到带有一些不需要的间隙的方块
  2. 我想将视点(“相机”)设置为与物体成 45 度角 第一排中间,这样玩家就可以看到他身上的路
  3. 接下来,我想沿着路走。所以我看到了旋转 以及它是如何运作的。有没有办法对观点或 我需要更改绘制 Z 的方块吗?
  4. 我看到 onDrawFrame() 一遍又一遍地调用。到 控制FPS,我在网上看到有人用过 有自己的 FPS 计算和 sleep()。不是有建好的吗 已经?

GL渲染器代码:

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.util.Log;


class GLRenderer implements GLSurfaceView.Renderer {

    private static final String TAG = "GLRenderer" ;
    private final Context context;

    private float mCubeRotation = 70.0f;
    private Triangle triangle;
    private Cube[][] cube;


    GLRenderer(Context context) {
        this.context = context;
    }
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); 

        gl.glClearDepthf(1.0f);
        gl.glEnable(GL10.GL_DEPTH_TEST);
        gl.glDepthFunc(GL10.GL_LEQUAL);

        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_NICEST);

    }
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        Log.d("MyOpenGLRenderer", "Surface changed. Width=" + width
                + " Height=" + height);
        System.out.println("arg");

        //get map
        cube = new Cube[30][5];
        for(int i = 0; i < cube.length; i++)
            for(int j = 0; j < cube[i].length; j++)
                    cube[i][j] = new Cube();

        //draw triangle
        triangle = new Triangle(0.5f, 1, 0, 0);

        // Define the view frustum
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        float ratio = (float) width / height;
        GLU.gluPerspective(gl, 45.0f, ratio, 0.1f, 100.0f);

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

    }
    public void onDrawFrame(GL10 gl) {

        // Clear the screen to black
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 


        //translate(dx, dy, dz)

        // Position model so we can see it
        //gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();

        gl.glTranslatef(0.0f, 0.0f, -10.0f);
        gl.glRotatef(mCubeRotation, 1.0f, 1.0f, 1.0f);
        gl.glTranslatef(0.0f, 0.0f, -10.0f);
        cube[0][0].draw(gl);
        gl.glTranslatef(0.0f, 0.0f, -10.0f);
        cube[0][1].draw(gl);
        gl.glTranslatef(0.0f, 0.0f, -10.0f);
        cube[0][2].draw(gl);

        gl.glLoadIdentity();                                    

        //set rotation
        mCubeRotation -= 0.15f;
        System.out.println("mCubeRotation: "+mCubeRotation);

    }
}

立方体代码:

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

class Cube {

    private FloatBuffer mVertexBuffer;  //vertex
    private FloatBuffer mColorBuffer;   //color 
    private ByteBuffer  mIndexBuffer;   //face indices

    float width  = 1.0f;
    float height = 0.5f;
    float depth  = 1.0f;

    private float vertices[] = { 
                         -width, -height, -depth, // 0
                          width, -height, -depth, // 1
                          width,  height, -depth, // 2
                         -width,  height, -depth, // 3
                         -width, -height,  depth, // 4
                          width, -height,  depth, // 5
                          width,  height,  depth, // 6
                         -width,  height,  depth, // 7
    };

    private float colors[] = {
                               0.0f,  1.0f,  0.0f,
                               1.0f,  0.0f,  1.0f,
                               0.0f,  1.0f,  1.0f,
                               0.5f,  0.0f,  1.0f,
                               1.0f,  0.5f,  0.0f,
                               1.0f,  1.0f,  0.0f,
                               0.0f,  1.0f,  1.0f,
                               0.0f,  0.0f,  1.0f,
                               0.0f,  0.0f,  1.0f,
                               1.0f,  1.0f,  0.0f,
                               1.0f,  1.0f
                            };

    private byte indices[] = {
                              0, 4, 5,
                              0, 5, 1,
                              1, 5, 6,
                              1, 6, 2,
                              2, 6, 7,
                              2, 7, 3,
                              3, 7, 4,
                              3, 4, 0,
                              4, 7, 6,
                              4, 6, 5,
                              3, 0, 1,
                              3, 1, 2
                              };

    public Cube() {
            ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
            byteBuf.order(ByteOrder.nativeOrder());
            mVertexBuffer = byteBuf.asFloatBuffer();
            mVertexBuffer.put(vertices);
            mVertexBuffer.position(0);

            byteBuf = ByteBuffer.allocateDirect(colors.length * 4);
            byteBuf.order(ByteOrder.nativeOrder());
            mColorBuffer = byteBuf.asFloatBuffer();
            mColorBuffer.put(colors);
            mColorBuffer.position(0);

            mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
            mIndexBuffer.put(indices);
            mIndexBuffer.position(0);
    }

    public void draw(GL10 gl) {             
            gl.glFrontFace(GL10.GL_CW);

            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
            gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);

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

            gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, 
                            mIndexBuffer);

            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
    }
}

最终我将使用 glDrawArrays() 或 glDrawElements() 绘制方形数组,但现在我只使用了 3 个对象。

android opengl-es 3d
2个回答
0
投票

这里有很多问题。我无法详细介绍所有内容,但希望我能给您一些指导,引导您走向正确的方向。

要绘制 150 个正方形,您有多种选择:

  1. 使用单个正方形创建一个顶点缓冲区,并绘制它 150 次,并应用平移。这可能是最容易让你开始工作的,所以我建议先让它工作。如果你的所有方块看起来都一样,这是一个合理的方法。
  2. 创建 150 个具有不同坐标的顶点缓冲区。我不会推荐它,因为它效率最低,并且比其他方法没有任何好处。
  3. 将所有 150 个正方形的顶点存储在单个顶点缓冲区中。这将是前 3 个选项中最有效的,但只有在方块的相对方向保持不变的情况下才有效。一旦你掌握了基础知识,你可能想尝试一下。
  4. 使用实例渲染。这是一个更高级的功能,仅在 ES 3.0 中可用。只是提一下以供将来参考。

您尝试的是选项 1 和 2 之间的混合。如果您想选择选项 1,则只需要

Cube
类的一个实例。如果你看看你做了什么,这是有道理的。您创建了 150 个完全相同的对象,这不是很有用。

现在,回答你的问题:

  1. 要绘制正方形之间没有间隙,翻译量需要与每个正方形的大小相同。您的方块有 2 个单位宽,但您将每个方块平移 10 个单位。你还把它们翻译成z方向,我不太明白。
  2. 如果您想坚持使用一直在使用的功能,请查看
    GLU.gluLookAt()
    。它允许您将相机放置在您想要的位置,并将其指向任何方向。
  3. 与 2 相同。每次想要移动视点时,请调用
    GLU.gluLookAt()
  4. Android 将帧速率限制为每秒 60 帧。恕我直言,这通常是你应该拍摄的目标。如果你想稍后将其限制为 30 fps 以节省电量,我认为你可以在到达那里时跨过那座桥。根据我最近的研究,在 Android 上没有干净且可移植的方法来执行此操作。我见过的提议的解决方案对我来说都看起来有点老套。

您的代码中还有更多内容:

  • 你的颜色定义看起来很奇怪。您在 4 个分量中指定颜色,并且数组的大小对此是正确的。但是您编写的数组每行包含 3 个值,这使得您看起来需要 3 个分量颜色。任何一种都可以完成,但您需要确保保持一致。 3 个组件就足够了,除非您需要透明度。
  • 您正在使用 ES 1.0。这是有效的,并且可能更容易上手。但您应该意识到它的许多功能都被认为是过时的,使用 ES 2.0 可以让您学习更多现代和当前的 OpenGL 功能。最初的障碍会更高,所以这里肯定需要权衡。

0
投票

我有同样的问题,我们如何使用opengl在android中实现这种类型的设计

© www.soinside.com 2019 - 2024. All rights reserved.