Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
|
wiki2:oglpipeline [2015/11/20 20:09] alfred [OpenGL Pipeline Básico] |
wiki2:oglpipeline [2020/05/09 09:25] (actual) |
||
|---|---|---|---|
| Línea 1: | Línea 1: | ||
| ====== OpenGL Pipeline ====== | ====== OpenGL Pipeline ====== | ||
| ===== OpenGL Pipeline Básico ===== | ===== OpenGL Pipeline Básico ===== | ||
| + | |||
| + | ==== Load pixels in memory ==== | ||
| + | |||
| + | === Android version === | ||
| + | |||
| + | <code java> | ||
| + | float[] tableVerticesWithTriangles = { | ||
| + | // Triangle 1 | ||
| + | 0, 0.5f, | ||
| + | -0.5f, 0, | ||
| + | 0.5f, 0, | ||
| + | |||
| + | // Triangle 2 | ||
| + | 0, 0, | ||
| + | 0.5f, -0.5f, | ||
| + | -0.5f, -0.5f | ||
| + | }; | ||
| + | |||
| + | vertexData = ByteBuffer | ||
| + | .allocateDirect(tableVerticesWithTriangles.length * BYTES_PER_FLOAT) | ||
| + | .order(ByteOrder.nativeOrder()) | ||
| + | .asFloatBuffer(); | ||
| + | |||
| + | vertexData.put(tableVerticesWithTriangles); | ||
| + | </code> | ||
| + | |||
| + | ==== Change the area where we are gonna render ==== | ||
| + | |||
| + | <code java> | ||
| + | @Override | ||
| + | public void onSurfaceChanged(GL10 glUnused, int width, int height) { | ||
| + | glViewport(0, 0, width, height); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ==== Coding vertex shader ==== | ||
| + | |||
| + | <code java> | ||
| + | attribute vec4 a_Position; | ||
| + | void main() | ||
| + | { | ||
| + | gl_Position = a_Position; | ||
| + | gl_PointSize = 10.0; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ==== Coding fragment shader ==== | ||
| + | |||
| + | <code> | ||
| + | precision mediump float; | ||
| + | uniform vec4 u_Color; | ||
| + | void main() | ||
| + | { | ||
| + | gl_FragColor = u_Color; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ==== Compiling shaders ==== | ||
| + | |||
| + | <code java> | ||
| + | private int compileShader(int type, String shaderCode) { | ||
| + | final int shaderObjectId = glCreateShader(type); | ||
| + | if (shaderObjectId == 0) { | ||
| + | Log.w(TAG, "Could not create new shader."); | ||
| + | return 0; | ||
| + | } | ||
| + | |||
| + | glShaderSource(shaderObjectId, shaderCode); | ||
| + | glCompileShader(shaderObjectId); | ||
| + | final int[] compileStatus = new int[1]; | ||
| + | glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0); | ||
| + | |||
| + | Log.v(TAG, "Results of compiling source:" + "\n" + shaderCode + "\n:" + glGetShaderInfoLog(shaderObjectId)); | ||
| + | |||
| + | if (compileStatus[0] == 0) { | ||
| + | glDeleteShader(shaderObjectId); | ||
| + | Log.w(TAG, "Compilation of shader failed."); | ||
| + | return 0; | ||
| + | } | ||
| + | Log.w(TAG, "Compilation of shader was good."); | ||
| + | return shaderObjectId; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ==== Link and use the shader program ==== | ||
| + | |||
| + | <code java> | ||
| + | public int linkProgram(int vertexShaderId, int fragmentShaderId) { | ||
| + | final int programObjectId = glCreateProgram(); | ||
| + | if (programObjectId == 0) { | ||
| + | Log.w(TAG, "Could not create new program"); | ||
| + | return 0; | ||
| + | } | ||
| + | |||
| + | glAttachShader(programObjectId, vertexShaderId); | ||
| + | glAttachShader(programObjectId, fragmentShaderId); | ||
| + | glLinkProgram(programObjectId); | ||
| + | |||
| + | final int[] linkStatus = new int[1]; | ||
| + | glGetProgramiv(programObjectId, GL_LINK_STATUS, linkStatus, 0); | ||
| + | Log.v(TAG, "Results of linking program:\n" + glGetProgramInfoLog(programObjectId)); | ||
| + | if (linkStatus[0] == 0) { | ||
| + | glDeleteProgram(programObjectId); | ||
| + | Log.w(TAG, "Linking of program failed."); | ||
| + | return 0; | ||
| + | } | ||
| + | |||
| + | glValidateProgram(programObjectId); | ||
| + | final int[] validateStatus = new int[1]; | ||
| + | glGetProgramiv(programObjectId, GL_VALIDATE_STATUS, validateStatus, 0); | ||
| + | Log.v(TAG, "Results of validating program: " + validateStatus[0] | ||
| + | + "\nLog:" + glGetProgramInfoLog(programObjectId)); | ||
| + | if (validateStatus[0] == 0) { | ||
| + | Log.w(TAG, "Validation program failed."); | ||
| + | return 0; | ||
| + | } | ||
| + | |||
| + | return programObjectId; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ==== Initialize values ==== | ||
| + | |||
| + | * Set the color to clear the screen | ||
| + | * Obtain the shaders code in string format | ||
| + | * Link and use the shader program | ||
| + | * As we are working with fixed triangles, assign shader variable values | ||
| + | |||
| + | <code java> | ||
| + | glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | ||
| + | |||
| + | String vertexShaderSource = Utils.ResourcesReader(context, R.raw.vertex); | ||
| + | String fragmentShaderSource = Utils.ResourcesReader(context, R.raw.fragment); | ||
| + | |||
| + | int vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource); | ||
| + | int fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); | ||
| + | program = linkProgram(vertexShader, fragmentShader); | ||
| + | glUseProgram(program); | ||
| + | |||
| + | uColorLocation = glGetUniformLocation(program, U_COLOR); | ||
| + | aPositionLocation = glGetAttribLocation(program, A_POSITION); | ||
| + | vertexData.position(0); | ||
| + | glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT, | ||
| + | false, 0, vertexData); | ||
| + | glEnableVertexAttribArray(aPositionLocation); | ||
| + | </code> | ||
| + | |||
| + | ==== Render ==== | ||
| + | |||
| + | |||
| + | <code java> | ||
| + | glClear(GL_COLOR_BUFFER_BIT); | ||
| + | |||
| + | glUniform4f(uColorLocation, 1.0f, 0f, 0f, 1.0f); | ||
| + | glDrawArrays(GL_TRIANGLES, 0, 3); | ||
| + | |||
| + | glUniform4f(uColorLocation, 0.0f, 0f, 1f, 1.0f); | ||
| + | glDrawArrays(GL_TRIANGLES, 3, 3); | ||
| + | </code> | ||
| + | |||
| ==== Functional examples ==== | ==== Functional examples ==== | ||
| * {{:wiki2:ogl:two-triangles.zip|}} | * {{:wiki2:ogl:two-triangles.zip|}} | ||
| - | ===== Transformaciones ===== | + | ===== Color ===== |
| + | |||
| + | ==== Define vertices, color and indexs ==== | ||
| + | |||
| + | <code java> | ||
| + | float[] tableVerticesWithTriangles = { | ||
| + | // x, y r,g,b | ||
| + | 0, 0.5f, 1,0,0, | ||
| + | -0.5f, 0, 0,1,0, | ||
| + | 0.5f, 0, 0,0,1 | ||
| + | }; | ||
| + | |||
| + | vertexData = ByteBuffer | ||
| + | .allocateDirect(tableVerticesWithTriangles.length * BYTES_PER_FLOAT) | ||
| + | .order(ByteOrder.nativeOrder()) | ||
| + | .asFloatBuffer(); | ||
| + | vertexData.put(tableVerticesWithTriangles); | ||
| + | |||
| + | byte[] tableIndices = {0, 1, 2}; | ||
| + | indexArray = ByteBuffer.allocateDirect(3).put(tableIndices); | ||
| + | </code> | ||
| + | |||
| + | ==== Shaders ==== | ||
| + | |||
| + | === Vertex Shader === | ||
| + | <code> | ||
| + | attribute vec4 a_Position; | ||
| + | attribute vec4 a_Color; | ||
| + | |||
| + | varying vec4 v_Color; | ||
| + | |||
| + | void main() | ||
| + | { | ||
| + | v_Color = a_Color; | ||
| + | gl_Position = a_Position; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | === Fragment Shader === | ||
| + | <code> | ||
| + | precision mediump float; | ||
| + | varying vec4 v_Color; | ||
| + | |||
| + | void main() | ||
| + | { | ||
| + | gl_FragColor = v_Color; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ==== Render ==== | ||
| + | |||
| + | * Obtain the attributes location for color and position. | ||
| + | * Write color and position (in this case this step could be performed only once). | ||
| + | * Enable them. | ||
| + | * Draw them. | ||
| + | |||
| + | <code java> | ||
| + | // next step is really important in java | ||
| + | vertexData.position(0); | ||
| + | indexArray.position(0); | ||
| + | |||
| + | glClear(GL_COLOR_BUFFER_BIT); | ||
| + | |||
| + | aColorLocation = glGetAttribLocation(program, A_COLOR); | ||
| + | aPositionLocation = glGetAttribLocation(program, A_POSITION); | ||
| + | |||
| + | |||
| + | glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT, | ||
| + | false, STRIDE, vertexData); | ||
| + | glEnableVertexAttribArray(aPositionLocation); | ||
| + | |||
| + | vertexData.position(POSITION_COMPONENT_COUNT); | ||
| + | glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT, | ||
| + | false, STRIDE, vertexData); | ||
| + | glEnableVertexAttribArray(aColorLocation); | ||
| + | |||
| + | glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, indexArray); | ||
| + | |||
| + | glDisableVertexAttribArray(aPositionLocation); | ||
| + | glDisableVertexAttribArray(aColorLocation); | ||
| + | </code> | ||
| + | |||
| + | === Constant values === | ||
| + | <code java> | ||
| + | private static final int BYTES_PER_FLOAT = 4; | ||
| + | private static final int POSITION_COMPONENT_COUNT = 2; | ||
| + | private static final int COLOR_COMPONENT_COUNT = 3; | ||
| + | private static final int STRIDE = (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * BYTES_PER_FLOAT; | ||
| + | </code> | ||
| + | |||
| + | ==== Example ==== | ||
| + | |||
| + | {{:wiki2:ogl:color.zip|Example}} | ||
| + | ===== Transformaciones y proyecciones ===== | ||
| + | |||
| + | * {{:wiki2:ogl:tutorial_3_matrices.pdf|Explicacion de matrices y proyecciones}} | ||
| + | * {{:wiki2:ogl:objectoriented.matrix.zip|Ejemplo de matrices y orientación a objetos en OpenGL ES}} | ||
| ===== Texturas ===== | ===== Texturas ===== | ||
| + | ==== Cargar texturas ==== | ||
| + | |||
| + | - Read the texture. | ||
| + | - Bind the texture. | ||
| + | - Set filtering: a default must be set, or the texture will be black. | ||
| + | - Load the bitmap into the bound texture with ''texImage2D''. | ||
| + | - Unbind from the texture with ''glBindTexture(GL_TEXTURE_2D, 0)''. | ||
| + | |||
| + | <code java> | ||
| + | public static int loadTexture(Context context, int resourceId) { | ||
| + | final int[] textureObjectIds = new int[1]; | ||
| + | glGenTextures(1, textureObjectIds, 0); | ||
| + | if (textureObjectIds[0] == 0) { | ||
| + | Log.w(TAG, "Could not generate a new OpenGL texture object."); | ||
| + | return 0; | ||
| + | } | ||
| + | |||
| + | final BitmapFactory.Options options = new BitmapFactory.Options(); | ||
| + | options.inScaled = false; | ||
| + | final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options); | ||
| + | if (bitmap == null) { | ||
| + | Log.w(TAG, "Resource ID " + resourceId + " could not be decoded."); | ||
| + | glDeleteTextures(1, textureObjectIds, 0); | ||
| + | return 0; | ||
| + | } | ||
| + | glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]); | ||
| + | |||
| + | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
| + | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
| + | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | ||
| + | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | ||
| + | |||
| + | texImage2D(GL_TEXTURE_2D, 0, bitmap, 0); | ||
| + | glBindTexture(GL_TEXTURE_2D, 0); | ||
| + | bitmap.recycle(); | ||
| + | |||
| + | Log.w(TAG, "Texture loaded"); | ||
| + | |||
| + | return textureObjectIds[0]; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Podríamos cargar mipmaps: | ||
| + | <code java> | ||
| + | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | ||
| + | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
| + | glGenerateMipmap(GL_TEXTURE_2D); | ||
| + | </code> | ||
| + | |||
| + | ==== Shaders ==== | ||
| + | === Vertex === | ||
| + | <code> | ||
| + | attribute vec4 a_Position; | ||
| + | attribute vec2 a_TextureCoordinates; | ||
| + | varying vec2 v_TextureCoordinates; | ||
| + | |||
| + | void main() | ||
| + | { | ||
| + | v_TextureCoordinates = a_TextureCoordinates; | ||
| + | gl_Position = a_Position; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | === Fragment === | ||
| + | <code> | ||
| + | precision mediump float; | ||
| + | uniform sampler2D u_TextureUnit; | ||
| + | varying vec2 v_TextureCoordinates; | ||
| + | |||
| + | void main() | ||
| + | { | ||
| + | gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ==== When render ==== | ||
| + | <code java> | ||
| + | vertexData.position(0); | ||
| + | indexArray.position(0); | ||
| + | |||
| + | glClear(GL_COLOR_BUFFER_BIT); | ||
| + | |||
| + | glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT, | ||
| + | false, STRIDE, vertexData); | ||
| + | |||
| + | vertexData.position(POSITION_COMPONENT_COUNT); | ||
| + | glVertexAttribPointer(aTextCoordLocation, TEXTURE_COORDINATES_COMPONENT_COUNT, GL_FLOAT, | ||
| + | false, STRIDE, vertexData); | ||
| + | |||
| + | glEnableVertexAttribArray(aPositionLocation); | ||
| + | glEnableVertexAttribArray(aTextCoordLocation); | ||
| + | |||
| + | glActiveTexture(GL_TEXTURE0); | ||
| + | glBindTexture(GL_TEXTURE_2D, texture); | ||
| + | glUniform1i(uTextureUnitLocation, 0); | ||
| + | |||
| + | glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, indexArray); | ||
| + | |||
| + | glDisableVertexAttribArray(aPositionLocation); | ||
| + | glDisableVertexAttribArray(aTextCoordLocation); | ||
| + | </code> | ||
| + | |||
| + | Setting these values: | ||
| + | <code java> | ||
| + | float[] tableVerticesWithTriangles = { | ||
| + | // x, y s,t | ||
| + | 0, 0.5f, 0.5f,0, | ||
| + | -0.5f, 0, 0,1, | ||
| + | 0.5f, 0, 1,1 | ||
| + | }; | ||
| + | </code> | ||
| + | |||
| + | And these constants: | ||
| + | <code java> | ||
| + | private static final int BYTES_PER_FLOAT = 4; | ||
| + | private static final int POSITION_COMPONENT_COUNT = 2; | ||
| + | private static final int TEXTURE_COORDINATES_COMPONENT_COUNT = 2; | ||
| + | private static final int STRIDE = (POSITION_COMPONENT_COUNT + TEXTURE_COORDINATES_COMPONENT_COUNT) * BYTES_PER_FLOAT; | ||
| + | </code> | ||
| + | ==== Code ==== | ||
| + | * {{:wiki2:ogl:textures.zip|}} | ||
| ===== Luces ===== | ===== Luces ===== | ||