tool: eclipse
1. Obtain an obj file and analyze the content
3D yoyo net Click to open the link, you can download a lot of model files, use 3dmax to open and export the external format file obj to get an obj model
Change the format to txt to see the data content inside
Some model files will also have mlt files
Please go to https://www.douban.com/note/142379570/ for detailed data explanation
Second, get the data in the obj file
One is to analyze the data by yourself, please go to https://blog.csdn.net/xiaxl/article/details/77048507
Provides the analysis method of mlt and obj models, probably by traversing the data of each line and storing it in the array in the analysis format, and finally getting several vertices, normal vectors, and maps one-to-one corresponding arrays
The second is that I was too lazy, so I started to work hard to find the bag.
The first is obj2opengl.pl, a library that can automatically analyze the obj model through the command line and then export it into a .h file, which will generate an equal number of vertices, texture and normal arrays
Please go to http://maider.blog.sohu.com/281704711.html
However, .h cannot be used directly in the android project (of course, the data in .h can be copied directly to a new class dedicated to storing data, but it is ok when the data is small, for example, a cube may only have dozens of lines of data , but complex models will be more difficult, and a large number of float arrays need to be imported. The blog in the link above also talks about the solution)
Or use jni to parse c++ files
BUT is lazy or chooses to find bags diligently
Then org.obj2openjl learn about https://github.com/miffels/org.obj2openjl
mainly
RawOpenGLModel openGLModel = new Obj2OpenJL().convert("file");
OpenGLModelData openGLModelData = openGLModel.normalize().center().getDataForGLDrawElements();
float[] Vertices = openGLModelData.getVertices();
float[] Normals = openGLModelData.getNormals();
float[] TexCoords = openGLModelData.getTextureCoordinates();
Then put your obj file under the assets file.
At this time, the parsed data has been assigned to the above array and we can start rendering
3. Opengl rendering in Android
Recommend <<Opengl ES 2 for Android>> this book, you will learn more about the rendering process of opengl in Android, camera settings, projection settings
There are also some books in this area that I have packaged together https://download.csdn.net/download/qq_35263780/10366356
Let's talk about my own little project.
The first is the main class of Activity
Get OpenGL Read version information to check whether it is supported Get an OpenGL view class in which to start rendering things in the renderer class
glSurfaceView = new GLSurfaceView(this); final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 20000; if (supportsEs2){ glSurfaceView.setEGLContextClientVersion(2); try { glSurfaceView.setRenderer(new FirstOpenGLProjectRender(this)); } catch (Exception e) { // TODO auto-generated catch block e.printStackTrace (); } setContentView(glSurfaceView);
In the Activity class, there are also some events that deal with the life cycle of the android activity. Similar frameworks are as follows
public class FirstOpenGLProjectActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(); } @Override protected void onPause(){ super.onPause(); } @Override protected void onResume(){ super.onResume(); } }
Create a renderer class (inherit Renderer)
There should also be some functions that deal with the lifecycle
include
public void onSurfaceCreated(GL10 gl, EGLConfig config)
public void onSurfaceChanged(GL10 gl, int width, int height)
public void onDrawFrame(GL10 gl)
So the name suggests that one is called before rendering, the other is called when the screen changes, and the other is called at all times.
A bit like a function mechanism like start() update() in js
The rotation and scaling dynamic effects (projection matrix transformation) are probably all placed in onSurfaceChanged (please correct me if it is wrong)
Then next we need to get our array information and pass it to the underlying opengl rendering
private final FloatBuffer VertexBuffer; private final FloatBuffer NormalBuffer; private final FloatBuffer TexureBuffer; private int VertexCount;
InputStream it = null; try { it = context.getAssets().open("obj1.obj"); } catch (IOException e) { e.printStackTrace (); } RawOpenGLModel openGLModel = new Obj2OpenJL().convert(it); OpenGLModelData openGLModelData = openGLModel.normalize().center().getDataForGLDrawArrays(); float[] Vertices = openGLModelData.getVertices(); VertexCount = Vertices.length / 3; VertexBuffer = ByteBuffer.allocateDirect(Vertices.length * 4).order(ByteOrder.nativeOrder()) .asFloatBuffer(); VertexBuffer.put(Vertices); VertexBuffer.position(0);//Read from 0 float[] Normals = openGLModelData.getNormals(); NormalBuffer = ByteBuffer.allocateDirect(Normals.length * 4).order(ByteOrder .nativeOrder()).asFloatBuffer(); NormalBuffer.put(Normals); NormalBuffer.position(0); float[] TexCoords = openGLModelData.getTextureCoordinates(); TexureBuffer = ByteBuffer.allocateDirect(TexCoords.length * 4).order(ByteOrder .nativeOrder()).asFloatBuffer(); TexureBuffer.put(TexCoords); TexureBuffer.position(0);
The first piece of code above should be seen at the beginning of this blog. We directly analyzed the
obj1.obj
and through
openGLModelData.getVertices()
and so on to get three arrays
You should have also noticed that we pass the obtained data information to a variable of type FloatBuffer, which is related to the mechanism of opengl. We can only pass this information to the underlying shader through this data flow, so as to output the required rendering. Vertex and Color Information
For details, please refer to Section 2.4 of <<Opengl ES 2 for Android>>
So when it comes to shaders
How do we create shaders in our project?
Create a new project file in this folder and save it as a glsl file vertex is vertex shader fragment is fragment shader
Hence the name, the vertex shader must have
gl_Position = whatever;
Fragment shader must have
gl_FragColor = whatever;
Then these two files are compiled with the syntax of C language, and there is probably only one void main() function in a simple shader.
Then the type of the variable and the way to pass the value
Please go to https://www.cnblogs.com/salam/archive/2016/01/08/5113572.html
You must be more serious than me
However, because opengl is such a language mechanism, bugs will not report errors, and it is not particularly easy to find (the Android application has been flashing back for a week, but I have not found the reason and always thought that the mechanism was wrong), but also because I just started to understand the shader. It's not very deep, and there will be a lot of strange problems at the beginning. For example, I just didn't understand the normal vector and light, so the data of gl_FlagColor is not right. I don't know where the bug is. Looking at other people's code, it gradually improved a little bit, and finally shipped a complete small instance is also a joy, so gl_position and gl_FlagColor need to correspond to the amount of data. The data of the vector defines the color a few times), if it is shipped out and does not flash back, it will be black, that is
Did you misspell the variable name in your shader somewhere?
Is the type definition in your shader correct? When is mat3 and when is vec4
Is there any problem with reading the type data?
Is your rendering order correct?
or something
If you read books and tutorials, you will basically have the first problem, hahaha (it's me
But there should be a way to compile shaders now.
So Amway https://www.jianshu.com/p/8687a040eb48
[Probably Amway has a lot of blogs, although I am lazy on the one hand, but it really benefits me a lot. Reading these blogs is definitely more useful than reading mine... Don't waste your time looking for information haha]
And I think it's funny
I hope I can experience this feeling in the future hahaha
pull back
I got the shader code on
vertex shader
uniform mat4 u_Matrix;//Transformation matrix uniform mat4 u_MVPMatrix; //Total transformation matrix attribute vec3 a_Position; attribute vec3 a_Normal; attribute vec2 a_TextureCoord; varying vec3 v_FragPosition; varying vec3 v_Normal; varying vec2 v_TextureCoord; void main() { v_TextureCoord = a_TextureCoord; v_Normal = a_Normal; v_FragPosition = vec3(u_Matrix * vec4(a_Position,1.0)); gl_Position = u_MVPMatrix * vec4(a_Position,1); }
fragment shader
precision mediump float; varying vec3 v_FragPosition; varying vec3 v_Normal; varying vec2 v_TextureCoord; //Texture coordinate variable variable two bits uniform sampler2D u_Texture; //Texture sampler, representing a texture uniform vec3 u_LightLocation; void main() { vec3 normal = normalize(v_Normal); vec3 lightDir = normalize(u_LightLocation-v_FragPosition); float factor = max(0.0, dot(normal, lightDir)); vec4 diffuse = factor * vec4(1.0,1.0,1.0,1.0); gl_FragColor = (diffuse + vec4(0.6,0.6,0.6,1))*texture2D(u_Texture, vec2(v_TextureCoord.s,v_TextureCoord.t)); }
To sum up, the variables of the attribute and uniform types need to be defined in the renderer class and need to be passed from them (floatbuffer), similar to attribute values, and the variables of the Varying class are the data that needs to be passed between the two shaders. For example, I define a vertex shader
varying vec3 v_Normal;
That must also be in the fragment shader
varying vec3 v_Normal;
This value can be obtained from a variable of type attribute
v_Normal = a_Normal;
After writing the shader code, compile and link it in the renderer class
Call this method in onSurfaceCreated
public void UseProgram(){ String vertexShaderSource = TextResourceReader .readTextFileFromResource(context, R.raw.simple_vertex_shader); //Connect to glsl file simple_vertex_shader String fragmentShaderSource = TextResourceReader .readTextFileFromResource(context, R.raw.simple_fragment_shader);//Connect to the glsl file simple_fragment_shader int vertexShader = ShaderHelper.compileVertexShader(vertexShaderSource); int fragmentShader = ShaderHelper.compileFragmentShader(fragmentShaderSource); //connect the shaders program = ShaderHelper.linkProgram(vertexShader, fragmentShader); //Connect vertex shader and fragment shader to program if(LoggerConfig.ON){ ShaderHelper.validateProgram(program); } // use the program defined here when drawing anything to the screen glUseProgram(program); }
The next step is to pass the data stream we obtained earlier to the shader
define variable
private int aPositionHandle;
Get attribute location in shader and assign to variable
aPositionHandle = glGetAttribLocation(program,"a_Position"); //Get the attribute location assignment location number in simple_vertex_shader
Connect with the data stream to start reading data
glVertexAttribPointer(aPositionHandle,3,GL_FLOAT, false, 0, VertexBuffer);glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer ptr)
They are (attribute position; how many components a vertex has; data type; default integer data; tell Opengl where to go, read data in the buffer vertexData to find the data corresponding to aPositionLocation)
finally
glEnableVertexAttribArray(aPositionHandle); //Enable
So far our shader has all the vertex data
The data acquisition of other attributes is also similar
But the texture map of the material needs to be initialized separately
//initialize texture public void initTexture() { int[] textures = new int[1];//Generate texture ID glGenTextures( 1,//The number of texture ids generated textures,//Array of texture ids 0//Offset ); textureId = textures[0];//Get the generated texture id glBindTexture(GL_TEXTURE_2D, textureId);//Bind texture Id glTexParameterf(GL_TEXTURE_2D,//Set the MIN sampling method GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D,//Set the MAG sampling method GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D,//Set the S-axis stretching method GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, //Set the T axis stretching method GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // load image via input stream InputStream is = context.getResources().openRawResource(//Create a stream that only wants texture images R.drawable.t4); Bitmap bitmapTmp; try {bitmapTmp = BitmapFactory.decodeStream(is);}//Load image content from the stream finally{try{is.close();}catch(IOException e){e.printStackTrace();}} GLUtils.texImage2D(//Actually load texture into video memory GL_TEXTURE_2D,//Texture type 0,//The level of the texture, 0 represents the basic image layer, which can be understood as a direct map bitmapTmp,//texture image 0//Texture border size ); bitmapTmp.recycle();//Release the texture map in the memory after the texture is loaded successfully, otherwise it will cause a memory crash when there are too many textures }texture
initTexture(); glUniform1i(uTextureHandle, 0);//Corresponding to texture unit 0 glActiveTexture(GL_TEXTURE0 + 0); glBindTexture(GL_TEXTURE_2D, textureId);
For details, please go to https://blog.csdn.net/sz66cm/article/details/54317272
After assigning all the obtained data to the shader, you can see
[Only added texture without light]
【Add light】
The last source
https://download.csdn.net/download/qq_35263780/10366532