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
parameter | meaning | |
---|---|---|
String | vertexPath | Path of vertex shader |
String | fragPath | Path to clip shader |
Resources | resources | Context for file reading |
Shader | Return value | Returns 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)
parameter | meaning | |
---|---|---|
String | name | Variable name of uniform |
float | v | Variable 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)
variable | meaning | |
---|---|---|
String | fname | File path |
int | drawable | Texture pattern id |
Resources | r | Context for reading files |
public Model(float[] vertices, float[] normals, float texCoors[], int drawableId, Resources resources)
variable | meaning | |
---|---|---|
float[] | vertices | vertex array |
float[] | normals | Normal vector array |
float[] | texCoors | Texture coordinate array |
int | drawable | Texture pattern id |
Resources | r | Context for reading files |
public void draw(Shader shader, Camera camera)
variable | meaning | |
---|---|---|
Shader | shader | Shader used |
Camera | camera | Camera 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)
variable | meaning | |
---|---|---|
float | left | left of near face |
float | right | near face right |
float | bottom | bottom of near face |
float | top | near face top |
flaot | near | Distance of near face |
float | far | far face distance |
float | x | Initial position x coordinate |
float | y | Initial position y coordinate |
float | z | Initial 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(); } }