Fundamentals of OpenGL ES operation (model import, scene roaming, object movement, illumination change)

preface

For small partners unfamiliar with openGL, here is the drawing process:

  • Calculate projection matrix, object change matrix, viewing angle matrix
  • The vertex cache of the incoming object,
  • Pass parameters into the shader (including the matrix above)
  • Determining the position of a point on the screen in the vertex shader is generally the multiplication of vertex coordinates and matrix
  • Determine the color of points in the clip shader, including lighting and so on

openGL ES is easy to use, but it is also troublesome in practice. The main reason is that the encapsulation of openGL ES is too poor, and what we hope is that developers can focus on design logic rather than flinch from how to draw.

The following describes several encapsulation classes, which can greatly reduce the difficulty of use.

This paper refers to teacher Wu Yafeng's OpenGL ES 3.x Game Development Volume I and II, which will not be pointed out later.

1 Shader class

Shader class is an encapsulated tool class, which is mainly used in the following ways:

public Shader(String mVertexShaderFile,String mFragmentShaderFile,Resources resources)

Construct a Shader from a given scripting language

parametermeaning
StringvertexPathPath of vertex shader
StringfragPathPath to clip shader
ResourcesresourcesContext for file reading
ShaderReturn valueReturns the constructed Shader class

usage method:

String vertexPath = "vertexShader.shader";
String fragPath = "fragShader.shader";
Shader shader = new Shader(vertexPath, fragPath, this.context);

public void use()

Specifies that this shader is used when the shader transfers data.

usage method:

Shader = new Shader(v,f,r);
shader.use();

public void setFloat(String name, float v)

parametermeaning
StringnameVariable name of uniform
floatvVariable value

Pass in a uniform variable of type float

Here's an explanation for those who don't understand:
Relatively fixed values in the Shader are passed in in a way similar to global variables, called unifom. As long as the variable name is specified during use and passed in java, it can be used in the Shader.

public void setInt(String name, int v)

Pass in a uniform variable of type int

public void setMat4f(String name, float[] mat4)

Pass in a unifrom variable of matrix type

public void setVec3f(String name, FloatBuffer buffer)

Pass in a three-dimensional vector

public void setPointer3f(String name, boolean normalized, FloatBuffer buffer)

Specifies a 3-dimensional float type cache, which is mainly used for vertex or normal vector incoming

public void setPointer2f(String name, boolean normalized, FloatBuffer buffer)

Specifies a 2D float type cache, which is mainly used for texture coordinates

Given an operation method:

Shader shader = new Shader(v,f,r);
shader.use();
shader.setMat4f("uMVPMatrix", mMVPMatrix);
//Pass the position, rotation and transformation matrix into the shader program
shader.setMat4f("uMMatrix", currMatrix);
// Transfer vertex position data into the render pipeline
shader.setPointer3f("aPosition",false, mVertexBuffer);
//Pass vertex normal data into the render pipeline
shader.setPointer3f("aNormal",false, mNormalBuffer);
//Transfer vertex texture coordinate data into the rendering pipeline
shader.setPointer2f("aTexCoor", false, mTexCoorBuffer);

2 Object3D class

Object3D mainly records the position of objects, including translation and rotation.

public Object3D()

Create an object of Object3D type, which is in the (0,0,0) position by default

public Object3D(float x, float y, float z)

Create an Object3D object and specify the coordinates in the world coordinate system

public void scale(float x,float y,float z)

The x,y,z axes are scaled by a specified multiple

public void translate(float x,float y,float z)

Along the x,y,z axes of the world coordinate system.

public void rotate(float angle,float x,float y,float z)

Rotate the angle angle about the axis (x,y,z)

public void moveForward(float x)

Move in the z direction of the object

public void moveLeft(float x)

Move along the x direction (left side) of the object

public void rotateRight(float angle)

Rotating along the x axis of an object is equivalent to changing the depression and elevation angles

public void rotateCameraUp(float angle)

Rotating along the y axis of the object (vertically upward) is equivalent to rotating left and right

3 Model class

The model class inherits Object3D and provides methods for loading model (obj) and drawing texture

public Model(String fname, int drawableId, Resources r)

variablemeaning
StringfnameFile path
intdrawableTexture pattern id
ResourcesrContext for reading files

public Model(float[] vertices, float[] normals, float texCoors[], int drawableId, Resources resources)

variablemeaning
float[]verticesvertex array
float[]normalsNormal vector array
float[]texCoorsTexture coordinate array
intdrawableTexture pattern id
ResourcesrContext for reading files

public void draw(Shader shader, Camera camera)

variablemeaning
ShadershaderShader used
CameracameraCamera used

4 Camera class

It inherits Object3D as the main body of roaming

public Camera(float left, float right, float bottom, float top, float near, float far, float x, float y, float z)

variablemeaning
floatleftleft of near face
floatrightnear face right
floatbottombottom of near face
floattopnear face top
flaotnearDistance of near face
floatfarfar face distance
floatxInitial position x coordinate
floatyInitial position y coordinate
floatzInitial position z coordinate

public void translate(float x,float y,float z)

Along the x,y,z axes of the world coordinate system.

public void rotate(float angle,float x,float y,float z)

Rotate the angle angle about the axis (x,y,z)

public void moveForward(float x)

Move along the z direction of the object

public void moveLeft(float x)

Move in the x direction (left) of the object

public void rotateRight(float angle)

Rotating along the x axis of the object is equivalent to changing the depression and elevation angles

public void rotateCameraUp(float angle)

Rotating along the y axis of the object (vertically upward) is equivalent to rotating left and right

5 Light class

Inherited the Camera class, omitted.

6 source code

The complete project is shown in:

https://github.com/HGGshiwo/OpenGLES.example

Shader class source code:

package com.example.myapplication.Shader;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.FloatBuffer;

import android.content.res.Resources;
import android.opengl.GLES30;
import android.util.Log;

//Load tool classes for vertex Shader and slice Shader
public class Shader
{
    private final int id;

    public Shader(String vertexSource, String fragmentSource) {
        id =  createProgram(vertexSource, fragmentSource);
   }

   public Shader(
           String mVertexShaderFile,//Vertex shader code script
           String mFragmentShaderFile,//Chip shader code script
           Resources resources
   ) {
        String mVertexShader = loadFromAssetsFile(mVertexShaderFile, resources);
        String mFragmentShader = loadFromAssetsFile(mFragmentShaderFile, resources);
        id = createProgram(mVertexShader, mFragmentShader);
   }

    //Method of loading and formulating shader
    public static int loadShader(
            int shaderType, //The type of shader is gles30 GL_ VERTEX_ SHADER   GLES30. GL_ FRAGMENT_ SHADER
            String source   //Script string for shader
    ) {
        //Create a new shader
        int shader = GLES30.glCreateShader(shaderType);
        //If the creation is successful, the shader will be loaded
        if (shader != 0)
        {
            //Load the source code of the shader
            GLES30.glShaderSource(shader, source);
            //Compile shader
            GLES30.glCompileShader(shader);
            //An array storing the number of shader s successfully compiled
            int[] compiled = new int[1];
            //Get the compilation of Shader
            GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compiled, 0);
            if (compiled[0] == 0)
            {//If compilation fails, the error log is displayed and the shader is deleted
                Log.e("ES30_ERROR", "Could not compile shader " + shaderType + ":");
                Log.e("ES30_ERROR", GLES30.glGetShaderInfoLog(shader));
                GLES30.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }

   //Method of creating shader program
   public int createProgram(String vertexSource, String fragmentSource) {
	    //Load vertex shader
        int vertexShader = loadShader(GLES30.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) 
        {
            return 0;
        }
        
        //Load slice shader
        int pixelShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentSource);
        if (pixelShader == 0) 
        {
            return 0;
        }

        //Create program
        int program = GLES30.glCreateProgram();
        //If the program is created successfully, add vertex shader and slice shader to the program
        if (program != 0) 
        {
        	//Adds a vertex shader to the program
            GLES30.glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            //Add a slice shader to the program
            GLES30.glAttachShader(program, pixelShader);
            checkGlError("glAttachShader");
            //Link program
            GLES30.glLinkProgram(program);
            //An array that stores the number of successful linked program s
            int[] linkStatus = new int[1];
            //Get the link of program
            GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, linkStatus, 0);
            //If the link fails, an error is reported and the program is deleted
            if (linkStatus[0] != GLES30.GL_TRUE) 
            {
                Log.e("ES30_ERROR", "Could not link program: ");
                Log.e("ES30_ERROR", GLES30.glGetProgramInfoLog(program));
                GLES30.glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }
    
   //Check whether there are wrong methods in each step of operation 
   public static void checkGlError(String op) {
        int error;
        while ((error = GLES30.glGetError()) != GLES30.GL_NO_ERROR) 
        {
            Log.e("ES30_ERROR", op + ": glError " + error);
            throw new RuntimeException(op + ": glError " + error);
        }
   }
   
   //Method of loading shader content from sh script
   public static String loadFromAssetsFile(String fname,Resources r) {
   	String result=null;    	
   	try
   	{
   		InputStream in=r.getAssets().open(fname);
			int ch=0;
		    ByteArrayOutputStream baos = new ByteArrayOutputStream();
		    while((ch=in.read())!=-1)
		    {
		      	baos.write(ch);
		    }      
		    byte[] buff=baos.toByteArray();
		    baos.close();
		    in.close();
   		result=new String(buff,"UTF-8"); 
   		result=result.replaceAll("\\r\\n","\n");
   	}
   	catch(Exception e)
   	{
   		e.printStackTrace();
   	}    	
   	return result;
   }

   public void use(){
       GLES30.glUseProgram(id);
   }

   public void setFloat(String name, float v){
       int location = GLES30.glGetUniformLocation(id, name);
       GLES30.glUniform1f(location, v);
   }

   public void setInt(String name, int v){
       int location = GLES30.glGetUniformLocation(id, name);
       GLES30.glUniform1i(location, v);
   }

   public void setMat4f(String name, float[] mat4){
       int location = GLES30.glGetUniformLocation(id, name);
       GLES30.glUniformMatrix4fv(location, 1, false, mat4, 0);
   }

   public void setVec3f(String name, FloatBuffer buffer){
       int location = GLES30.glGetUniformLocation(id, name);
       GLES30.glUniform3fv(location, 1, buffer);
   }

   public void setPointer3f(String name, boolean normalized, FloatBuffer buffer){
       int location = GLES30.glGetAttribLocation(id, name);
       GLES30.glVertexAttribPointer
               (
                       location,
                       3,
                       GLES30.GL_FLOAT,
                       normalized,
                       3*4,
                       buffer
               );
       GLES30.glEnableVertexAttribArray(location);
   }

   public void setPointer2f(String name, boolean normalized, FloatBuffer buffer){
       int location = GLES30.glGetAttribLocation(id, name);
       GLES30.glVertexAttribPointer
               (
                       location,
                       2,
                       GLES30.GL_FLOAT,
                       normalized,
                       2*4,
                       buffer
               );
       GLES30.glEnableVertexAttribArray(location);
   }
}

Object3D class source code:

package com.example.myapplication.Object;

import android.opengl.Matrix;

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

public class Object3D {

    public float[] currMatrix;//Current transformation matrix
    public float[] up; //Camera lookAt use
    public float[] front; //Camera lookAt use
    public float[] position; //Camera lookAt use

    public Object3D(){
        up = new float[]{0f,1f,0f};
        front = new float[]{0f,0f,-1f};
        position = new float[]{0,0,0};
        currMatrix = new float[16];
        Matrix.setRotateM(currMatrix,0,0,0,1,0);//Note that this is set
    }

    public Object3D(
            float x,
            float y,
            float z

    ){
        up = new float[]{0f,1f,0f};
        front = new float[]{0f,0f,-1f};
        position = new float[]{x,y,z};

        currMatrix = new float[16];
        Matrix.translateM(currMatrix, 0, x, y, z);//translate cannot be called because the subclass is overloaded
    }

    public void translate(float x,float y,float z){//Sets the movement along the xyz axis
        Matrix.translateM(currMatrix, 0, x, y, z);
        position[0]+=x;
        position[1]+=y;
        position[2]+=z;
    }

    public void moveForward(float x){
        float [] front = this.front;
        this.translate(-1*x*front[0],0,-1*x*front[2]);
    }

    public void moveLeft(float x){
        float [] rightDistance = Model.vectorNormal(
                Model.getCrossProduct(
                        up[0],
                        up[1],
                        up[2],
                        front[0],
                        front[1],
                        front[2]
                ));

        translate(
                x*rightDistance[0],
                0,
                x*rightDistance[2]
        );
    }

    public void rotateRight(float angle){
        float [] right = Model.vectorNormal(
                Model.getCrossProduct(
                        up[0],
                        up[1],
                        up[2],
                        front[0],
                        front[1],
                        front[2]
                ));
        rotate(angle, right[0], right[1], right[2]);
    }

    public void rotateUp(float angle){
        float radians = (float) Math.toRadians(angle);
        rotate(angle, 0, 1, 0);
    }


    public void scale(float x,float y,float z){
        Matrix.scaleM(currMatrix,0,x,y,z);
    }

    public void rotate(float angle,float x,float y,float z){//Sets the movement around the xyz axis
        Matrix.rotateM(currMatrix,0,angle,x,y,z);
        float[] rotateMatrix = new float[16];
        float[] rotateFront =  new float[]{front[0],front[1],front[2],1f};
        float[] rotateUp = new float[]{up[0],up[1],up[2],1.0f};
        Matrix.setRotateM(rotateMatrix,0,angle,x,y,z);
        Matrix.multiplyMV(
                rotateFront,
                0,
                rotateMatrix,
                0,
                rotateFront,
                0
        );
        float[] rotateFrontNormalized = Model.vectorNormal(rotateFront);
        front[0]=rotateFrontNormalized[0];
        front[1]=rotateFrontNormalized[1];
        front[2]=rotateFrontNormalized[2];

        Matrix.multiplyMV(
                rotateUp,
                0,
                rotateMatrix,
                0,
                rotateUp,
                0
        );
        float[] rotateUpNormalized = Model.vectorNormal(rotateUp);
        up[0]=rotateUpNormalized[0];
        up[1]=rotateUpNormalized[1];
        up[2]=rotateUpNormalized[2];
    }
}

Model class source code

package com.example.myapplication.Object;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES30;
import android.opengl.GLUtils;
import android.opengl.Matrix;

import com.example.myapplication.Camera.Camera;
import com.example.myapplication.Shader.Shader;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

public class Model extends Object3D{
    int vCount=0;

    public FloatBuffer mVertexBuffer;//Vertex coordinate data buffer
    public FloatBuffer mNormalBuffer;//Vertex normal vector data buffer
    public FloatBuffer mTexCoorBuffer;//Vertex texture coordinate data buffer

    int texId;//texture

    public float shininess;//Smoothness

    public Model(
            float[] vertices,
            float[] normals,
            float texCoors[],
            int drawableId,
            Resources resources
    ){
        super();
        shininess = 50;
        initTexture(drawableId, resources);
        initVertexData(vertices, normals, texCoors);
    }


    public Model(String fname, int drawableId, Resources r){
        super();
        //Original vertex coordinate list -- loaded directly from obj file
        ArrayList<Float> alv=new ArrayList<Float>();
        //Vertex assembly face index list -- loaded from the file according to the face information
        ArrayList<Integer> alFaceIndex=new ArrayList<Integer>();
        //Result vertex coordinate list -- organized by face
        ArrayList<Float> alvResult=new ArrayList<Float>();
        //Normal vector set Map of points corresponding to each index before average
        //The key of this HashMap is the index of the point, and the value is the set of normal vectors of each face where the point is located
        HashMap<Integer, HashSet<Normal>> hmn=new HashMap<Integer,HashSet<Normal>>();
        //List of original texture coordinates
        ArrayList<Float> alt=new ArrayList<Float>();
        //Result texture coordinate list
        ArrayList<Float> altResult=new ArrayList<Float>();

        try {
            InputStream in = r.getAssets().open(fname);
            InputStreamReader isr = new InputStreamReader(in);
            BufferedReader br = new BufferedReader(isr);
            String temps = null;

            //Scan the file and execute different processing logic according to different line types
            while ((temps = br.readLine()) != null) {//Read a line of text

                String[] tempsa = temps.split("[ ]+");//Break text lines with spaces
                if (tempsa[0].trim().equals("v")) {//Vertex coordinate line
                    //If it is a vertex coordinate line, the XYZ coordinates of this vertex are extracted and added to the original vertex coordinate list
                    alv.add(Float.parseFloat(tempsa[1]));
                    alv.add(Float.parseFloat(tempsa[2]));
                    alv.add(Float.parseFloat(tempsa[3]));
                } else if (tempsa[0].trim().equals("vt")) {//Texture coordinate line
                    //If it is a texture coordinate line, the ST coordinate is extracted and added to the original texture coordinate list
                    alt.add(Float.parseFloat(tempsa[1]));//Extract S texture coordinates
                    alt.add(1 - Float.parseFloat(tempsa[2]));    //Extract T texture coordinates
                } else if (tempsa[0].trim().equals("f")) {//Face data row
                    /*
                     *If it is a triangular face row, it is selected from the original vertex coordinate list according to the index of the vertices that make up the face
                     *Extract the corresponding vertex coordinate values and add them to the resulting vertex coordinate list according to three
                     *The normal vector of the face is calculated from the coordinates of the vertices and added to the points corresponding to each index before averaging
                     *In the Map composed of the normal vector set of
                     */

                    int[] index = new int[3];//An array of three vertex index values

                    //Calculate the index of the 0th vertex and obtain the XYZ three coordinates of this vertex
                    index[0] = Integer.parseInt(tempsa[1].split("/")[0]) - 1;
                    float x0 = alv.get(3 * index[0]);
                    float y0 = alv.get(3 * index[0] + 1);
                    float z0 = alv.get(3 * index[0] + 2);
                    alvResult.add(x0);
                    alvResult.add(y0);
                    alvResult.add(z0);

                    //Calculate the index of the first vertex and obtain the XYZ three coordinates of this vertex
                    index[1] = Integer.parseInt(tempsa[2].split("/")[0]) - 1;
                    float x1 = alv.get(3 * index[1]);
                    float y1 = alv.get(3 * index[1] + 1);
                    float z1 = alv.get(3 * index[1] + 2);
                    alvResult.add(x1);
                    alvResult.add(y1);
                    alvResult.add(z1);

                    //Calculate the index of the second vertex and obtain the XYZ three coordinates of this vertex
                    index[2] = Integer.parseInt(tempsa[3].split("/")[0]) - 1;
                    float x2 = alv.get(3 * index[2]);
                    float y2 = alv.get(3 * index[2] + 1);
                    float z2 = alv.get(3 * index[2] + 2);
                    alvResult.add(x2);
                    alvResult.add(y2);
                    alvResult.add(z2);

                    //Record the vertex index of this face
                    alFaceIndex.add(index[0]);
                    alFaceIndex.add(index[1]);
                    alFaceIndex.add(index[2]);

                    //The normal vector of the triangular surface is obtained by finding the cross product of the two edge vectors 0-1 and 0-2
                    //Find the vector from point 0 to point 1
                    float vxa = x1 - x0;
                    float vya = y1 - y0;
                    float vza = z1 - z0;
                    //Find the vector from point 0 to point 2
                    float vxb = x2 - x0;
                    float vyb = y2 - y0;
                    float vzb = z2 - z0;
                    //Calculate the normal vector by finding the cross product of two vectors
                    float[] vNormal = vectorNormal(getCrossProduct
                            (
                                    vxa, vya, vza, vxb, vyb, vzb
                            ));
                    for (int tempInxex : index) {//Record the normal vector of each index point into the Map composed of the normal vector set of the points corresponding to each index before averaging
                        //Gets the normal vector set of the corresponding points of the current index
                        HashSet<Normal> hsn = hmn.get(tempInxex);
                        if (hsn == null) {//Create if collection does not exist
                            hsn = new HashSet<Normal>();
                        }
                        //Adds the normal vector of this point to the collection
                        //Since the Normal class overrides the equals method, the same Normal vector does not appear at this point repeatedly
                        //In the corresponding normal vector set
                        hsn.add(new Normal(vNormal[0], vNormal[1], vNormal[2]));
                        //Put the collection into the HsahMap
                        hmn.put(tempInxex, hsn);
                    }

                    //Organize the texture coordinate data of the three vertices of the triangle into the resulting texture coordinate list
                    int indexTex = Integer.parseInt(tempsa[1].split("/")[1]) - 1;//Get texture coordinate number
                    //Texture coordinates of the 0th vertex
                    altResult.add(alt.get(indexTex * 2));
                    altResult.add(alt.get(indexTex * 2 + 1));

                    indexTex = Integer.parseInt(tempsa[2].split("/")[1]) - 1;//Get texture coordinate number
                    //Texture coordinates of the first vertex
                    altResult.add(alt.get(indexTex * 2));
                    altResult.add(alt.get(indexTex * 2 + 1));

                    indexTex = Integer.parseInt(tempsa[3].split("/")[1]) - 1;//Get texture coordinate number
                    //Texture coordinates of the second vertex
                    altResult.add(alt.get(indexTex * 2));
                    altResult.add(alt.get(indexTex * 2 + 1));
                }
            }

            //Generate vertex array
            int size = alvResult.size();
            float[] vXYZ = new float[size];
            for (int i = 0; i < size; i++) {
                vXYZ[i] = alvResult.get(i);
            }

            //Generate normal vector array
            float[] nXYZ = new float[alFaceIndex.size() * 3];
            int c = 0;
            for (Integer i : alFaceIndex) {
                //Extract a set of normal vectors from the Map according to the index of the current point
                HashSet<Normal> hsn = hmn.get(i);
                //Find the average normal vector
                float[] tn = Normal.getAverage(hsn);
                //Store the calculated average normal vector into the normal vector array
                nXYZ[c++] = tn[0];
                nXYZ[c++] = tn[1];
                nXYZ[c++] = tn[2];
            }

            //Generate texture array
            size = altResult.size();
            float[] tST = new float[size];//An array used to store the resulting texture coordinate data
            for (int i = 0; i < size; i++) {//Storing texture coordinate data into an array
                tST[i] = altResult.get(i);
            }
            initVertexData(vXYZ,nXYZ,tST);
            initTexture(drawableId, r);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void initVertexData(float[] vertices,float[] normals,float texCoors[]) {
        //Initialization of vertex coordinate data
        vCount=vertices.length/3;
        //Create vertex coordinate data buffer
        //vertices.length*4 is because an integer has four bytes
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
        vbb.order(ByteOrder.nativeOrder());//Set byte order
        mVertexBuffer = vbb.asFloatBuffer();//Convert to Float type buffer
        mVertexBuffer.put(vertices);//Put vertex coordinate data into the buffer
        mVertexBuffer.position(0);//Set buffer start position

        //Initialization of vertex normal vector data
        ByteBuffer cbb = ByteBuffer.allocateDirect(normals.length*4);
        cbb.order(ByteOrder.nativeOrder());//Set byte order
        mNormalBuffer = cbb.asFloatBuffer();//Convert to Float type buffer
        mNormalBuffer.put(normals);//Put vertex normal vector data into the buffer
        mNormalBuffer.position(0);//Set buffer start position

        //Initialization of vertex texture coordinate data
        ByteBuffer tbb = ByteBuffer.allocateDirect(texCoors.length*4);
        tbb.order(ByteOrder.nativeOrder());//Set byte order
        mTexCoorBuffer = tbb.asFloatBuffer();//Convert to Float type buffer
        mTexCoorBuffer.put(texCoors);//Put vertex texture coordinate data into the buffer
        mTexCoorBuffer.position(0);//Set buffer start position
    }

    public void initTexture(int drawableId, Resources resources){
        //Generate texture ID
        int[] textures = new int[1];
        GLES30.glGenTextures
                (
                        1,          //Number of texture IDs generated
                        textures,   //Array of texture IDS
                        0           //Offset
                );
        int textureId=textures[0];
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER,GLES30.GL_NEAREST);
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D,GLES30.GL_TEXTURE_MAG_FILTER,GLES30.GL_LINEAR);
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S,GLES30.GL_REPEAT);
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T,GLES30.GL_REPEAT);

        //Load picture through input stream =========================== begin===================
        InputStream is = resources.openRawResource(drawableId);
        Bitmap bitmapTmp;
        try
        {
            bitmapTmp = BitmapFactory.decodeStream(is);
        }
        finally
        {
            try
            {
                is.close();
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
        }
        //Load picture through input stream ============================ end=====================
        GLUtils.texImage2D
                (
                        GLES30.GL_TEXTURE_2D, //Texture type
                        0,
                        GLUtils.getInternalFormat(bitmapTmp),
                        bitmapTmp, //texture image 
                        GLUtils.getType(bitmapTmp),
                        0 //Texture border size
                );
        bitmapTmp.recycle(); 		  //Release the picture after the texture is loaded successfully
        texId = textureId;
    }

    public void draw(Shader shader, Camera camera) {
        //Pass the final transformation matrix into the shader program
        float[] mMVPMatrix=new float[16];
        Matrix.multiplyMM(mMVPMatrix, 0, camera.mVMatrix, 0, currMatrix, 0);
        Matrix.multiplyMM(mMVPMatrix, 0, camera.mProjMatrix, 0, mMVPMatrix, 0);
        shader.setMat4f("uMVPMatrix", mMVPMatrix);

        //Pass the position, rotation and transformation matrix into the shader program
        shader.setMat4f("uMMatrix", currMatrix);
        // Transfer vertex position data into the render pipeline
        shader.setPointer3f("aPosition",false, mVertexBuffer);
        //Pass vertex normal data into the render pipeline
        shader.setPointer3f("aNormal",false, mNormalBuffer);
        //Transfer vertex texture coordinate data into the rendering pipeline
        shader.setPointer2f("aTexCoor", false, mTexCoorBuffer);
        //Pass roughness into shader program
        shader.setFloat("uShininess", shininess);
        //Bind texture
        GLES30.glActiveTexture(GLES30.GL_TEXTURE0);//Enable texture 0
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, texId);//Bind texture
        //Draw loaded objects
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vCount);
    }

    //Find the cross product of two vectors
    public static float[] getCrossProduct(float x1,float y1,float z1,float x2,float y2,float z2)
    {
        //Find the component ABC of the cross product vector of two vectors on the XYZ axis
        float A=y1*z2-y2*z1;
        float B=z1*x2-z2*x1;
        float C=x1*y2-x2*y1;

        return new float[]{A,B,C};
    }

    //Vector normalization
    public static float[] vectorNormal(float[] vector)
    {
        //Find the module of vector
        float module=(float)Math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]+vector[2]*vector[2]);
        return new float[]{vector[0]/module,vector[1]/module,vector[2]/module};
    }
}

Camera class source code

package com.example.myapplication.Camera;

import android.opengl.GLES30;
import android.opengl.Matrix;

import com.example.myapplication.Object.Object3D;
import com.example.myapplication.Shader.Shader;

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

public class Camera extends Object3D {

    public float[] mVMatrix;//Camera position orientation 9 parameter matrix
    public float[] mProjMatrix;//4x4 matrix projection
    public FloatBuffer positionBuffer;

    public Camera(
            float left,		//left of near face
            float right,    //near face right
            float bottom,   //bottom of near face
            float top,      //near face top
            float near,		//near face distance
            float far,       //far face distance
            float x,
            float y,
            float z
    ){
        super(x,y,z);
        mVMatrix  = new float[16];
        mProjMatrix = new float[16];
        setProjectFrustum(left,right,bottom,top,near,far);
        setLookAt();
        setPositionBuffer();
    }

    public void setLookAt() {
        Matrix.setLookAtM
                (
                        mVMatrix,
                        0,
                        position[0],
                        position[1],
                        position[2],
                        position[0]+front[0],
                        position[1]+front[1],
                        position[2]+front[2],
                        up[0],
                        up[1],
                        up[2]
                );
    }

    protected void setPositionBuffer(){
        ByteBuffer llbb = ByteBuffer.allocateDirect(3*4);
        llbb.order(ByteOrder.nativeOrder());//Set byte order
        positionBuffer=llbb.asFloatBuffer();
        positionBuffer.put(position);
        positionBuffer.position(0);
    }

    public void setProjectFrustum
            (
                    float left,		//left of near face
                    float right,    //near face right
                    float bottom,   //bottom of near face
                    float top,      //near face top
                    float near,		//near face distance
                    float far       //far face distance
            ) {
        Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
    }

    //Set orthographic projection parameters
    public void setProjectOrtho
    (
            float left,		//left of near face
            float right,    //near face right
            float bottom,   //bottom of near face
            float top,      //near face top
            float near,		//near face distance
            float far       //far face distance
    ) {
        Matrix.orthoM(mProjMatrix, 0, left, right, bottom, top, near, far);
    }

    @Override
    public void rotate(float angle,float x,float y,float z){
        super.rotate(angle,x,y,z);
        setLookAt();
    }

    @Override
    public void translate(float x,float y,float z){
        super.translate(x,y,z);
        setPositionBuffer();
        setLookAt();
    }

    @Override
    public void moveForward(float x){
        super.moveForward(x);
        setPositionBuffer();
        setLookAt();
    }

    @Override
    public void moveLeft(float x){
        super.moveLeft(x);
        setPositionBuffer();
        setLookAt();
    }

    @Override
    public void rotateRight(float angle){
        super.rotateRight(angle);
        setPositionBuffer();
        setLookAt();
    }

    @Override
    public void rotateUp(float angle){
        super.rotateUp(angle);
        setPositionBuffer();
        setLookAt();
    }
}

Keywords: Android Big Data ElasticSearch

Added by jwright on Sat, 22 Jan 2022 01:29:39 +0200