【问题标题】:OpenGL ES - texture map all faces of an 8 vertex cube?OpenGL ES - 纹理贴图 8 个顶点立方体的所有面?
【发布时间】:2019-07-27 03:13:43
【问题描述】:

使用 Android 模拟器完成一些 OpenGL-ES 教程。我已经掌握了纹理映射,但在映射到立方体时遇到了一些麻烦。是否可以将纹理映射到具有 8 个顶点和 6 个面的 12 个三角形的立方体的所有面,如下所述?

// Use half as we are going for a 0,0,0 centre.
    width  /= 2;
    height /= 2;
    depth  /= 2;

    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
    };

    short indices[] = { 
            // Front
            0,1,2,
            0,2,3,
            // Back
            5,4,7,
            5,7,6,
            // Left
            4,0,3,
            4,3,7,
            // Right
            1,5,6,
            1,6,2,
            // Top
            3,2,6,
            3,6,7,
            // Bottom
            4,5,1,
            4,1,0,
    };

   float texCoords[] = {
        1.0f, 1.0f,
        0.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

        1.0f, 1.0f,
        0.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

        1.0f, 1.0f,
        0.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

        1.0f, 1.0f,
        0.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

        1.0f, 1.0f,
        0.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,

        1.0f, 1.0f,
        0.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,
    };

我的正面和背面都可以正常工作,但是,其他面都没有显示纹理。

绘图代码

public void draw(GL10 gl) {
    // Counter-clockwise winding.
    gl.glFrontFace(GL10.GL_CCW);

    // Enable face culling.
    gl.glEnable(GL10.GL_CULL_FACE);

    // What faces to remove with the face culling.
    gl.glCullFace(GL10.GL_BACK);

    // Enabled the vertices buffer for writing and to be used during
    // rendering.
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

    // Specifies the location and data format of an array of vertex
    // coordinates to use when rendering.
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, verticesBuffer);

    if (normalsBuffer != null) {
        // Enabled the normal buffer for writing and to be used during rendering.
        gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);

        // Specifies the location and data format of an array of normals to use when rendering.
        gl.glNormalPointer(GL10.GL_FLOAT, 0, normalsBuffer);
    }

    // Set flat color
    gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]);

    // Smooth color
    if ( colorBuffer != null ) {
        // Enable the color array buffer to be used during rendering.
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        // Point out the where the color buffer is.
        gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
    }

    // Use textures?
    if ( textureBuffer != null) {
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glEnable(GL10.GL_TEXTURE_2D);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
    }

    // Translation and rotation before drawing
    gl.glTranslatef(x, y, z);
    gl.glRotatef(rx, 1, 0, 0);
    gl.glRotatef(ry, 0, 1, 0);
    gl.glRotatef(rz, 0, 0, 1);

    gl.glDrawElements(GL10.GL_TRIANGLES, numOfIndices, GL10.GL_UNSIGNED_SHORT, indicesBuffer);

    // Disable the vertices buffer.
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
    gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    // Disable face culling.
    gl.glDisable(GL10.GL_CULL_FACE);
}

【问题讨论】:

  • 听起来你可能是按面而不是按顶点制作纹理。您能否发布更多绘图代码,以便我们了解您如何将这些数据集联系在一起?
  • 我有一个例子,他们使用 24 个顶点来定义他们的立方体。我相信这必须是每个顶点并且是默认值?如何指定每个面?

标签: android opengl-es


【解决方案1】:

您必须使用 24 个顶点。在 OpenGL 中,顶点不仅仅是位置,它是所有顶点属性的集合。每个顶点数组都使用相同的索引访问。

臭名昭著的立方体示例在开始使用 OpenGL 时几乎每个人都觉得效率低下,但在现实世界中,更复杂的模型中,重复度非常低。

【讨论】:

  • 你是什么意思你必须使用24个顶点?如果您必须复制顶点,那么使用索引缓冲区有什么意义,那么如果您仍在向 GPU 发送重复数据?
【解决方案2】:

我“仅”将 GLES20TriangleRenderer.java 文件修改为 SDK 示例 BasicGLSurfaceView,对其进行编译并在两台 Android 设备(Android 手机和 Nexus 7)上对其进行测试,这在两台设备上运行良好 :)

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.

   Modified by YLP (06 January 2014) for to handle a rotated texture mapped cube

 */

package com.example.android.basicglsurfaceview;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.os.SystemClock;
import android.util.Log;

class GLES20TriangleRenderer implements GLSurfaceView.Renderer {

    public GLES20TriangleRenderer(Context context) {
        mContext = context;

        // mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
        // mTriangleVertices.put(mTriangleVerticesData).position(0);

        mTriangleVertices = ByteBuffer.allocateDirect(cubeVerticesStrip.length * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
        mTriangleVertices.put(cubeVerticesStrip).position(0);

        mTriangleTexcoords = ByteBuffer.allocateDirect(cubeTexCoordsStrip.length * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
        mTriangleTexcoords.put(cubeTexCoordsStrip).position(0);

    }

    public void onDrawFrame(GL10 glUnused) {
        // Ignore the passed-in GL10 interface, and use the GLES20
        // class's static methods instead.
        GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

        GLES20.glEnable( GLES20.GL_DEPTH_TEST );
        GLES20.glDepthFunc( GLES20.GL_LEQUAL );
        GLES20.glDepthMask( true );

        GLES20.glUseProgram(mProgram);
        checkGlError("glUseProgram");

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);

        // mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
        // GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
        //        TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
        // checkGlError("glVertexAttribPointer maPosition");

        // mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
        // GLES20.glEnableVertexAttribArray(maPositionHandle);
        // checkGlError("glEnableVertexAttribArray maPositionHandle");

        // GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false,
        //         TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
        // checkGlError("glVertexAttribPointer maTextureHandle");
        // GLES20.glEnableVertexAttribArray(maTextureHandle);
        // checkGlError("glEnableVertexAttribArray maTextureHandle");

        // From http://www.endodigital.com/opengl-es-2-0-on-the-iphone/part-fourteen-creating-the-cube
        // (but slighty modified)
        mTriangleVertices.position(0);
        // GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
           GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mTriangleVertices);
        GLES20.glEnableVertexAttribArray(maPositionHandle);

        mTriangleTexcoords.position(0);
        // GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false,TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
           GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, 0, mTriangleTexcoords);
        GLES20.glEnableVertexAttribArray(maTextureHandle);

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

        Matrix.setRotateM(mMMatrix, 0, angle, 0, 0, 1.0f);

        // YLP : add others movements cycles
        Matrix.rotateM(mMMatrix, 0, angle, 1.0f, 0.0f, 0.0f );
        // Matrix.rotateM(mMMatrix, 0, angle, 0.0f, 1.0f, 0.0f );
        // float scale = (float)( Math.abs( Math.sin( ((float)time) * (6.28f/4000.0f) ) ));
        Matrix.scaleM(mMMatrix, 0, scale, scale, scale);


        Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);

        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);

        // Somes tests with only somes triangles
        // GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); // worked initialy but only one triangle
        // GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6); // worked initialy but only two triangles
        // GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); // GL_QUADS does not exist in GL 2.0  :(
        // GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 8); // GL_QUADS does not exist in GL 2.0  :(

        // Draw the cube
        // TODO : make only one glDraWArrays() call instead one per face
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 4, 4);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 8, 4);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 12, 4);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 16, 4);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 20, 4);

        checkGlError("glDrawArrays");
    }

    public void onSurfaceChanged(GL10 glUnused, int width, int height) {
        // Ignore the passed-in GL10 interface, and use the GLES20
        // class's static methods instead.
        GLES20.glViewport(0, 0, width, height);
        float ratio = (float) width / height;
        Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
    }

    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
        // Ignore the passed-in GL10 interface, and use the GLES20
        // class's static methods instead.
        mProgram = createProgram(mVertexShader, mFragmentShader);
        if (mProgram == 0) {
            return;
        }
        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
        checkGlError("glGetAttribLocation aPosition");
        if (maPositionHandle == -1) {
            throw new RuntimeException("Could not get attrib location for aPosition");
        }
        maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
        checkGlError("glGetAttribLocation aTextureCoord");
        if (maTextureHandle == -1) {
            throw new RuntimeException("Could not get attrib location for aTextureCoord");
        }

        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        checkGlError("glGetUniformLocation uMVPMatrix");
        if (muMVPMatrixHandle == -1) {
            throw new RuntimeException("Could not get attrib location for uMVPMatrix");
        }

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

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

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

        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
                GLES20.GL_NEAREST);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                GLES20.GL_TEXTURE_MAG_FILTER,
                GLES20.GL_LINEAR);

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
                GLES20.GL_REPEAT);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
                GLES20.GL_REPEAT);

        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(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();

        Matrix.setLookAtM(mVMatrix, 0, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    }

    private int loadShader(int shaderType, String source) {
        int shader = GLES20.glCreateShader(shaderType);
        if (shader != 0) {
            GLES20.glShaderSource(shader, source);
            GLES20.glCompileShader(shader);
            int[] compiled = new int[1];
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
            if (compiled[0] == 0) {
                Log.e(TAG, "Could not compile shader " + shaderType + ":");
                Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }

    private int createProgram(String vertexSource, String fragmentSource) {
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) {
            return 0;
        }

        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
        if (pixelShader == 0) {
            return 0;
        }

        int program = GLES20.glCreateProgram();
        if (program != 0) {
            GLES20.glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            GLES20.glAttachShader(program, pixelShader);
            checkGlError("glAttachShader");
            GLES20.glLinkProgram(program);
            int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
            if (linkStatus[0] != GLES20.GL_TRUE) {
                Log.e(TAG, "Could not link program: ");
                Log.e(TAG, GLES20.glGetProgramInfoLog(program));
                GLES20.glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }

    private void checkGlError(String op) {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e(TAG, op + ": glError " + error);
            throw new RuntimeException(op + ": glError " + error);
        }
    }

    private static final int FLOAT_SIZE_BYTES = 4;
    private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
    private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
    private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
    private static final int TRIANGLE_TEXCOORDS_DATA_STRIDE_BYTES = 2 * FLOAT_SIZE_BYTES;

    private final float[] mTriangleVerticesData =
    {
            // X, Y, Z, U, V

           // initial triangle from the source
           // -1.0f,   -0.5f,          0,  -0.5f,   0.0f,
           //  1.0f,   -0.5f,          0,   1.5f,  -0.0f,
           // 0.0f,    1.11803399f,   0,   0.5f,   1.61803399f,

            // YLP : transform this to two triangles for to have a quad
            // -1, -1, 0,    0, 0,
            // 1, -1, 0,    1, 0,
            // -1,  1, 0,    0, 1,
            // 1,  1, 0,    1, 1,
            // -1,  1, 0,    0, 1,
            // 1, -1, 0,    1, 0

            // YLP :  use two quads with GL_TRIANGLE_STRIP
            // Don't work because this make one accordeon effect :(
            -1, -1, -1,    0, 0,
             1, -1, -1,    1, 0,
            -1,  1, -1,    0, 1,
             1,  1, -1,    1, 1,
            -1, -1,  1,    0, 0,
             1, -1,  1,    1, 0,
            -1,  1,  1,    0, 1,
             1,  1,  1,    1, 1,
    };

    // From http://www.endodigital.com/opengl-es-2-0-on-the-iphone/part-fourteen-creating-the-cube/
    // (only moodify "static const GLfloat" to "private final float" on it)
    private final float cubeVerticesStrip[] = {
            // Front face
            -1,-1,1, 1,-1,1, -1,1,1, 1,1,1,
            // Right face
            1,-1,1, 1,-1,-1, 1,1,1, 1,1,-1,
            // Back face
            1,-1,-1, -1,-1,-1, 1,1,-1, -1,1,-1,
            // Left face
            -1,-1,-1, -1,-1,1, -1,1,-1, -1,1,1,
            // Bottom face
            -1,-1,-1, 1,-1,-1, -1,-1,1, 1,-1,1,
            // Top face
            -1,1,1, 1,1,1, -1,1,-1, 1,1,-1

    };

    private final float cubeTexCoordsStrip[] = {
            // Front face
            0,0, 1,0, 0,1, 1,1,
            // Right face
            0,0, 1,0, 0,1, 1,1,
            // Back face
            0,0, 1,0, 0,1, 1,1,
            // Left face
            0,0, 1,0, 0,1, 1,1,
            // Bottom face
            0,0, 1,0, 0,1, 1,1,
            // Top face
            0,0, 1,0, 0,1, 1,1
    };

    private FloatBuffer mTriangleVertices;
    private FloatBuffer mTriangleTexcoords;

    private final String mVertexShader =
        "uniform mat4 uMVPMatrix;\n" +
        "attribute vec4 aPosition;\n" +
        "attribute vec2 aTextureCoord;\n" +
        "varying vec2 vTextureCoord;\n" +
        "void main() {\n" +
        "  gl_Position = uMVPMatrix * aPosition;\n" +
        "  vTextureCoord = aTextureCoord;\n" +
        "}\n";

    private final String mFragmentShader =
        "precision mediump float;\n" +
        "varying vec2 vTextureCoord;\n" +
        "uniform sampler2D sTexture;\n" +
        "void main() {\n" +
        "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
        "}\n";

    private float[] mMVPMatrix = new float[16];
    private float[] mProjMatrix = new float[16];
    private float[] mMMatrix = new float[16];
    private float[] mVMatrix = new float[16];

    private float[] mMMatrix2 = new float[16];

    private int mProgram;
    private int mTextureID;
    private int muMVPMatrixHandle;
    private int maPositionHandle;
    private int maTextureHandle;

    private Context mContext;
    private static String TAG = "GLES20TriangleRenderer";
}

=> 我设法在短短几个小时内实现了这一点,而且这项工作:)

==> 因此,如果 Android 不是最好的平台,那么这似乎是一个非常好的和可行的平台,因为我开始在 Android 设备上进行一些多媒体开发:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-15
    • 2018-07-29
    • 2015-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多