Как добавить текстуру растрового изображения/изображения на поверхность в Android OpenGL ES3.0?

Для Android я видел несколько примеров добавления растровых текстур на поверхность в OpenGL ES1.x и 2.x, но кажется, что API-интерфейсы несколько изменились для ES 3.x (например, glEnableClientState() был удален), и мне интересно что нужно добавить/изменить в следующий код, чтобы иметь возможность передавать растровые изображения на поверхности моего куба. Я внес некоторые изменения в этот код, который нашел в Интернете, и он уже успешно рисует и вращает куб с разными цветами на каждой поверхности, однако теперь я хотел бы рисовать определенные изображения ресурсов на каждой поверхности, а не просто цвета.

Это класс Cube.java:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES30;
import android.opengl.GLUtils;
import android.util.Log;

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

import javax.microedition.khronos.opengles.GL10;

public class Cube {
    private int mProgramObject;
    private int mMVPMatrixHandle;
    private int mColorHandle;
    private FloatBuffer mVertices;

    //initial size of the cube.  set here, so it is easier to change later.
    float size = 0.7f;

    //this is the initial data, which will need to translated into the mVertices variable in the constructor.
    float[] mVerticesData = new float[]{
            ////////////////////////////////////////////////////////////////////
            // FRONT
            ////////////////////////////////////////////////////////////////////
            // Triangle 1
            -size, size, size, // top-left
            -size, -size, size, // bottom-left
            size, -size, size, // bottom-right
            // Triangle 2
            size, -size, size, // bottom-right
            size, size, size, // top-right
            -size, size, size, // top-left
            ////////////////////////////////////////////////////////////////////
            // BACK
            ////////////////////////////////////////////////////////////////////
            // Triangle 1
            -size, size, -size, // top-left
            -size, -size, -size, // bottom-left
            size, -size, -size, // bottom-right
            // Triangle 2
            size, -size, -size, // bottom-right
            size, size, -size, // top-right
            -size, size, -size, // top-left

            ////////////////////////////////////////////////////////////////////
            // LEFT
            ////////////////////////////////////////////////////////////////////
            // Triangle 1
            -size, size, -size, // top-left
            -size, -size, -size, // bottom-left
            -size, -size, size, // bottom-right
            // Triangle 2
            -size, -size, size, // bottom-right
            -size, size, size, // top-right
            -size, size, -size, // top-left
            ////////////////////////////////////////////////////////////////////
            // RIGHT
            ////////////////////////////////////////////////////////////////////
            // Triangle 1
            size, size, -size, // top-left
            size, -size, -size, // bottom-left
            size, -size, size, // bottom-right
            // Triangle 2
            size, -size, size, // bottom-right
            size, size, size, // top-right
            size, size, -size, // top-left

            ////////////////////////////////////////////////////////////////////
            // TOP
            ////////////////////////////////////////////////////////////////////
            // Triangle 1
            -size, size, -size, // top-left
            -size, size, size, // bottom-left
            size, size, size, // bottom-right
            // Triangle 2
            size, size, size, // bottom-right
            size, size, -size, // top-right
            -size, size, -size, // top-left
            ////////////////////////////////////////////////////////////////////
            // BOTTOM
            ////////////////////////////////////////////////////////////////////
            // Triangle 1
            -size, -size, -size, // top-left
            -size, -size, size, // bottom-left
            size, -size, size, // bottom-right
            // Triangle 2
            size, -size, size, // bottom-right
            size, -size, -size, // top-right
            -size, -size, -size // top-left
    };

    float colorcyan[] = myColor.cyan();
    float colorblue[] = myColor.blue();
    float colorred[] = myColor.red();
    float colorgray[] = myColor.gray();
    float colorgreen[] = myColor.green();
    float coloryellow[] = myColor.yellow();

    private int numFaces = 6;
    private int[] imageFileIDs = {  // Image file IDs
            R.drawable.geo1,
            R.drawable.geo2,
            R.drawable.geo3,
            R.drawable.geo4,
            R.drawable.geo5,
            R.drawable.geo6
    };
    private int[] textureIDs = new int[numFaces];
    private Bitmap[] bitmap = new Bitmap[numFaces];

    //vertex shader code
    String vShaderStr =
            "#version 300 es              \n"
                    + "uniform mat4 uMVPMatrix;     \n"
                    + "in vec4 vPosition;           \n"
                    + "void main()                  \n"
                    + "{                            \n"
                    + "   gl_Position = uMVPMatrix * vPosition;  \n"
                    + "}                            \n";
    //fragment shader code.
    String fShaderStr =
            "#version 300 es                                \n"
                    + "precision mediump float;                     \n"
                    + "uniform vec4 vColor;                         \n"
                    + "out vec4 fragColor;                          \n"
                    + "void main()                                  \n"
                    + "{                                            \n"
                    + "  fragColor = vColor;                        \n"
                    + "}                                            \n";

    String TAG = "Cube";


    //finally some methods
    //constructor
    public Cube(Context ctx) {

        if (ctx == null)
            throw new NullPointerException("3D rendering needs valid context.");

        //first setup the mVertices correctly.
        mVertices = ByteBuffer
                .allocateDirect(mVerticesData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(mVerticesData);
        mVertices.position(0);

        //setup the shaders
        int vertexShader;
        int fragmentShader;
        int programObject;
        int[] linked = new int[1];

        // Load the vertex/fragment shaders
        vertexShader = PrimaryRenderer.LoadShader(GLES30.GL_VERTEX_SHADER, vShaderStr);
        fragmentShader = PrimaryRenderer.LoadShader(GLES30.GL_FRAGMENT_SHADER, fShaderStr);

        // Create the program object
        programObject = GLES30.glCreateProgram();

        if (programObject == 0) {
            Log.e(TAG, "So some kind of error, but what?");
            return;
        }

        GLES30.glAttachShader(programObject, vertexShader);
        GLES30.glAttachShader(programObject, fragmentShader);

        // Bind vPosition to attribute 0
        GLES30.glBindAttribLocation(programObject, 0, "vPosition");

        // Link the program
        GLES30.glLinkProgram(programObject);

        // Check the link status
        GLES30.glGetProgramiv(programObject, GLES30.GL_LINK_STATUS, linked, 0);

        if (linked[0] == 0) {
            Log.e(TAG, "Error linking program:");
            Log.e(TAG, GLES30.glGetProgramInfoLog(programObject));
            GLES30.glDeleteProgram(programObject);
            return;
        }

        // Store the program object
        mProgramObject = programObject;
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = false;

        for (int face = 0; face < numFaces; face++) {
            bitmap[face] = BitmapFactory.decodeStream(
                    ctx.getResources().openRawResource(imageFileIDs[face]), null, options);
        }

        //now everything is setup and ready to draw.

    }

    public void draw(float[] mvpMatrix) {

        // Use the program object
        GLES30.glUseProgram(mProgramObject);

        // get handle to shape's transformation matrix
        mMVPMatrixHandle = GLES30.glGetUniformLocation(mProgramObject, "uMVPMatrix");
        PrimaryRenderer.checkGlError("glGetUniformLocation");

        // get handle to fragment shader's vColor member
        mColorHandle = GLES30.glGetUniformLocation(mProgramObject, "vColor");

        // Apply the projection and view transformation
        GLES30.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
        PrimaryRenderer.checkGlError("glUniformMatrix4fv");

        int VERTEX_POS_INDX = 0;
        mVertices.position(VERTEX_POS_INDX);  //just in case.  We did it already though.

        //add all the points to the space, so they can be correct by the transformations.
        //would need to do this even if there were no transformations actually.
        GLES30.glVertexAttribPointer(VERTEX_POS_INDX, 3, GLES30.GL_FLOAT,
                false, 0, mVertices);
        GLES30.glEnableVertexAttribArray(VERTEX_POS_INDX);

        //Now we are ready to draw the cube finally.
        int startPos = 0;
        int verticesPerface = 6;

        //draw front face
        GLES30.glUniform4fv(mColorHandle, 1, colorblue, 0);
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIDs[0]);
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
        startPos += verticesPerface;

        //draw back face
        GLES30.glUniform4fv(mColorHandle, 1, colorcyan, 0);
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIDs[1]);
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
        startPos += verticesPerface;

        //draw left face
        GLES30.glUniform4fv(mColorHandle, 1, colorred, 0);
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
        startPos += verticesPerface;

        //draw right face
        GLES30.glUniform4fv(mColorHandle, 1, colorgray, 0);
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
        startPos += verticesPerface;

        //draw top face
        GLES30.glUniform4fv(mColorHandle, 1, colorgreen, 0);
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
        startPos += verticesPerface;

        //draw bottom face
        GLES30.glUniform4fv(mColorHandle, 1, coloryellow, 0);
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
        //last face, so no need to increment.

    }

    public void loadTexture(GL10 gl) {
        gl.glGenTextures(6, textureIDs, 0); // Generate texture-ID array for 6 IDs
        // Generate OpenGL texture images
        for (int face = 0; face < numFaces; face++) {
            gl.glBindTexture(GLES30.GL_TEXTURE_2D, textureIDs[face]);
            gl.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
            gl.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
            GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap[face], 0);

            bitmap[face].recycle();
        }
    }

}

======================

Открытый метод loadTexture() вызывается из моего класса рендерера как часть инициализации экземпляра Cube. Он связывает каждое из 6 растровых изображений с 2D-текстурой, однако мне не хватает кода для успешной загрузки текстур в движок. Все примеры, которые я видел до сих пор, относятся только к ES 1.x и ES 2.x и не кажутся совместимыми с приведенным выше кодом. Любая помощь, пожалуйста.


person Oke Uwechue    schedule 23.07.2019    source источник


Ответы (1)


Вы должны добавить атрибут координаты текстуры к вершинному шейдеру (vUV). Конечно, вы должны задать атрибут координат текстуры (аналогично координатам вершин). Обратите внимание, что координаты текстуры находятся в диапазоне [0.0, 1.0], и вам нужен один атрибут координаты текстуры (u, v) для каждой координаты вершины (x, y, z):

GLES30.glVertexAttribPointer(TEX_COORD_INDX, 2, GLES30.GL_FLOAT, false, 0, mTexCoords);
GLES30.glEnableVertexAttribArray(TEX_COORD_INDX);

Передаем координаты текстуры фрагментному шейдеру (out vec2 uv;):

#version 300 es

uniform mat4 uMVPMatrix; 

in vec4 vPosition;
in vec2 vUV;

out vec2 uv;

void main() 
{
    uv = vUV;
    gl_Position = uMVPMatrix * vPosition;
}

Добавьте форму сэмплера текстуры во фрагментный шейдер (u_texture). Униформа должна быть установлена ​​текстурным блоком (например, 0 для GL_TEXTURE0). Поскольку вы используете текстурный модуль 0, а 0 является инициализацией по умолчанию, вы можете пропустить это. Найдите текстуру по texture и назначьте цвет для вывода фрагментного шейдера:

#version 300 es
precision mediump float; 

in vec2 vUV;

out vec4 fragColor;

uniform sampler2D u_texture;

void main()
{
    vec4 color = texture(u_texture, uv.xy);
    fragColor = color;
}
person Rabbid76    schedule 23.07.2019
comment
Спасибо. Рассмотрю это решение. - person Oke Uwechue; 24.07.2019
comment
после долгих исследований в Интернете и экспериментов я в итоге пошел другим путем и в итоге получил файл .glsl, выглядящий так: precision mediump float; uniform vec3 u_LightPos; uniform sampler2D u_Texture; varying vec3 v_Position; varying vec3 v_Normal; varying vec2 v_TexCoordinate; - person Oke Uwechue; 30.07.2019
comment
Спасибо. Ваш совет по атрибутам координат texture был полезен. Мне действительно не хватало этих заявлений. Мой первоначальный код передавал движку только данные вершины, поэтому в итоге я добавил в процедуру рисования следующие операторы: cubeTextureCoordinates.position(0); GLES30.glVertexAttribPointer(textureCoordinateHandle, textureCoordinateDataSize, GLES30.GL_FLOAT, false, 0, cubeTextureCoordinates); GLES30.glEnableVertexAttribArray(textureCoordinateHandle); - person Oke Uwechue; 30.07.2019