[英]How to add bitmap/image texture to a surface in Android OpenGL ES3.0?
For Android I've seen several examples of adding bitmap textures to a surface in OpenGL ES1.x and 2.x but it seems that the APIs changed somewhat for ES 3.x (eg glEnableClientState() was removed) and I'm wondering what needs to be added/changed to the following code in order to be able to push bitmap images to my cube surfaces.对于 Android,我已经看到了几个向 OpenGL ES1.x 和 2.x 中的表面添加位图纹理的示例,但似乎 ES 3.x 的 API 有所更改(例如,glEnableClientState() 已被删除),我想知道为了能够将位图图像推送到我的立方体表面,需要向以下代码添加/更改什么。 I made some modifications to this code I found online and it already successfully draws and rotates a cube with different colours on each surface, however, now I'd like to draw specific resource images onto each surface instead of just plain colours.
我对在网上找到的这段代码进行了一些修改,它已经成功地在每个表面上绘制和旋转了一个具有不同颜色的立方体,但是,现在我想在每个表面上绘制特定的资源图像,而不仅仅是纯色。
This is the class Cube.java :这是Cube.java类:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES30;
import android.opengl.GLUtils;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Cube {
private int mProgramObject;
private int mMVPMatrixHandle;
private int mColorHandle;
private FloatBuffer mVertices;
//initial size of the cube. set here, so it is easier to change later.
float size = 0.7f;
//this is the initial data, which will need to translated into the mVertices variable in the constructor.
float[] mVerticesData = new float[]{
////////////////////////////////////////////////////////////////////
// FRONT
////////////////////////////////////////////////////////////////////
// Triangle 1
-size, size, size, // top-left
-size, -size, size, // bottom-left
size, -size, size, // bottom-right
// Triangle 2
size, -size, size, // bottom-right
size, size, size, // top-right
-size, size, size, // top-left
////////////////////////////////////////////////////////////////////
// BACK
////////////////////////////////////////////////////////////////////
// Triangle 1
-size, size, -size, // top-left
-size, -size, -size, // bottom-left
size, -size, -size, // bottom-right
// Triangle 2
size, -size, -size, // bottom-right
size, size, -size, // top-right
-size, size, -size, // top-left
////////////////////////////////////////////////////////////////////
// LEFT
////////////////////////////////////////////////////////////////////
// Triangle 1
-size, size, -size, // top-left
-size, -size, -size, // bottom-left
-size, -size, size, // bottom-right
// Triangle 2
-size, -size, size, // bottom-right
-size, size, size, // top-right
-size, size, -size, // top-left
////////////////////////////////////////////////////////////////////
// RIGHT
////////////////////////////////////////////////////////////////////
// Triangle 1
size, size, -size, // top-left
size, -size, -size, // bottom-left
size, -size, size, // bottom-right
// Triangle 2
size, -size, size, // bottom-right
size, size, size, // top-right
size, size, -size, // top-left
////////////////////////////////////////////////////////////////////
// TOP
////////////////////////////////////////////////////////////////////
// Triangle 1
-size, size, -size, // top-left
-size, size, size, // bottom-left
size, size, size, // bottom-right
// Triangle 2
size, size, size, // bottom-right
size, size, -size, // top-right
-size, size, -size, // top-left
////////////////////////////////////////////////////////////////////
// BOTTOM
////////////////////////////////////////////////////////////////////
// Triangle 1
-size, -size, -size, // top-left
-size, -size, size, // bottom-left
size, -size, size, // bottom-right
// Triangle 2
size, -size, size, // bottom-right
size, -size, -size, // top-right
-size, -size, -size // top-left
};
float colorcyan[] = myColor.cyan();
float colorblue[] = myColor.blue();
float colorred[] = myColor.red();
float colorgray[] = myColor.gray();
float colorgreen[] = myColor.green();
float coloryellow[] = myColor.yellow();
private int numFaces = 6;
private int[] imageFileIDs = { // Image file IDs
R.drawable.geo1,
R.drawable.geo2,
R.drawable.geo3,
R.drawable.geo4,
R.drawable.geo5,
R.drawable.geo6
};
private int[] textureIDs = new int[numFaces];
private Bitmap[] bitmap = new Bitmap[numFaces];
//vertex shader code
String vShaderStr =
"#version 300 es \n"
+ "uniform mat4 uMVPMatrix; \n"
+ "in vec4 vPosition; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = uMVPMatrix * vPosition; \n"
+ "} \n";
//fragment shader code.
String fShaderStr =
"#version 300 es \n"
+ "precision mediump float; \n"
+ "uniform vec4 vColor; \n"
+ "out vec4 fragColor; \n"
+ "void main() \n"
+ "{ \n"
+ " fragColor = vColor; \n"
+ "} \n";
String TAG = "Cube";
//finally some methods
//constructor
public Cube(Context ctx) {
if (ctx == null)
throw new NullPointerException("3D rendering needs valid context.");
//first setup the mVertices correctly.
mVertices = ByteBuffer
.allocateDirect(mVerticesData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(mVerticesData);
mVertices.position(0);
//setup the shaders
int vertexShader;
int fragmentShader;
int programObject;
int[] linked = new int[1];
// Load the vertex/fragment shaders
vertexShader = PrimaryRenderer.LoadShader(GLES30.GL_VERTEX_SHADER, vShaderStr);
fragmentShader = PrimaryRenderer.LoadShader(GLES30.GL_FRAGMENT_SHADER, fShaderStr);
// Create the program object
programObject = GLES30.glCreateProgram();
if (programObject == 0) {
Log.e(TAG, "So some kind of error, but what?");
return;
}
GLES30.glAttachShader(programObject, vertexShader);
GLES30.glAttachShader(programObject, fragmentShader);
// Bind vPosition to attribute 0
GLES30.glBindAttribLocation(programObject, 0, "vPosition");
// Link the program
GLES30.glLinkProgram(programObject);
// Check the link status
GLES30.glGetProgramiv(programObject, GLES30.GL_LINK_STATUS, linked, 0);
if (linked[0] == 0) {
Log.e(TAG, "Error linking program:");
Log.e(TAG, GLES30.glGetProgramInfoLog(programObject));
GLES30.glDeleteProgram(programObject);
return;
}
// Store the program object
mProgramObject = programObject;
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
for (int face = 0; face < numFaces; face++) {
bitmap[face] = BitmapFactory.decodeStream(
ctx.getResources().openRawResource(imageFileIDs[face]), null, options);
}
//now everything is setup and ready to draw.
}
public void draw(float[] mvpMatrix) {
// Use the program object
GLES30.glUseProgram(mProgramObject);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES30.glGetUniformLocation(mProgramObject, "uMVPMatrix");
PrimaryRenderer.checkGlError("glGetUniformLocation");
// get handle to fragment shader's vColor member
mColorHandle = GLES30.glGetUniformLocation(mProgramObject, "vColor");
// Apply the projection and view transformation
GLES30.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
PrimaryRenderer.checkGlError("glUniformMatrix4fv");
int VERTEX_POS_INDX = 0;
mVertices.position(VERTEX_POS_INDX); //just in case. We did it already though.
//add all the points to the space, so they can be correct by the transformations.
//would need to do this even if there were no transformations actually.
GLES30.glVertexAttribPointer(VERTEX_POS_INDX, 3, GLES30.GL_FLOAT,
false, 0, mVertices);
GLES30.glEnableVertexAttribArray(VERTEX_POS_INDX);
//Now we are ready to draw the cube finally.
int startPos = 0;
int verticesPerface = 6;
//draw front face
GLES30.glUniform4fv(mColorHandle, 1, colorblue, 0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIDs[0]);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
startPos += verticesPerface;
//draw back face
GLES30.glUniform4fv(mColorHandle, 1, colorcyan, 0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIDs[1]);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
startPos += verticesPerface;
//draw left face
GLES30.glUniform4fv(mColorHandle, 1, colorred, 0);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
startPos += verticesPerface;
//draw right face
GLES30.glUniform4fv(mColorHandle, 1, colorgray, 0);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
startPos += verticesPerface;
//draw top face
GLES30.glUniform4fv(mColorHandle, 1, colorgreen, 0);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
startPos += verticesPerface;
//draw bottom face
GLES30.glUniform4fv(mColorHandle, 1, coloryellow, 0);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, startPos, verticesPerface);
//last face, so no need to increment.
}
public void loadTexture(GL10 gl) {
gl.glGenTextures(6, textureIDs, 0); // Generate texture-ID array for 6 IDs
// Generate OpenGL texture images
for (int face = 0; face < numFaces; face++) {
gl.glBindTexture(GLES30.GL_TEXTURE_2D, textureIDs[face]);
gl.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
gl.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap[face], 0);
bitmap[face].recycle();
}
}
}
====================== ======================
The public method loadTexture() is called from my renderer class as part of the Cube instance initialization.作为 Cube 实例初始化的一部分,从我的渲染器类调用公共方法loadTexture() 。 It associates each of the 6 bitmaps with a 2D texture however I'm missing the code to successfully feed the textures to the engine.
它将 6 个位图中的每一个与 2D 纹理相关联,但是我缺少将纹理成功提供给引擎的代码。 All the examples I've seen so far deal only with ES 1.x and ES 2.x and don't seem to be compatible with the above code.
到目前为止,我看到的所有示例都只处理 ES 1.x 和 ES 2.x,似乎与上述代码不兼容。 Any help please.
请任何帮助。
You've to add a texture coordinate attribute to the vertex shader ( vUV
).您必须向顶点着色器 (
vUV
) 添加纹理坐标属性。 Of course you've to st the texture coordinate attribute (similar the vertex coordinates).当然,您必须设置纹理坐标属性(类似于顶点坐标)。 Note texture coordinates are in range [0.0, 1.0] and you need one texture coordinate attribute (u, v) vor each vertex coordinate (x, y, z):
注意纹理坐标在 [0.0, 1.0] 范围内,您需要一个纹理坐标属性 (u, v) 或每个顶点坐标 (x, y, z):
GLES30.glVertexAttribPointer(TEX_COORD_INDX, 2, GLES30.GL_FLOAT, false, 0, mTexCoords);
GLES30.glEnableVertexAttribArray(TEX_COORD_INDX);
Pass the texture coordinates to the fragment shader ( out vec2 uv;
):将纹理坐标传递给片段着色器(
out vec2 uv;
):
#version 300 es
uniform mat4 uMVPMatrix;
in vec4 vPosition;
in vec2 vUV;
out vec2 uv;
void main()
{
uv = vUV;
gl_Position = uMVPMatrix * vPosition;
}
Add a texture sampler uniform in the fragment shader ( u_texture
).在片段着色器 (
u_texture
) 中添加一个统一的纹理采样器。 The uniform has to be set by the texture unit (eg 0 for GL_TEXTURE0
).统一必须由纹理单元设置(例如
GL_TEXTURE0
为 0)。 Since you use texture unit 0 and 0 is the default initialization, you can skip this.由于您使用纹理单元 0 并且 0 是默认初始化,因此您可以跳过此步骤。 Look up the texture by
texture
and assigne the color to the fragment shader output:按
texture
查找texture
并将颜色分配给片段着色器输出:
#version 300 es
precision mediump float;
in vec2 vUV;
out vec4 fragColor;
uniform sampler2D u_texture;
void main()
{
vec4 color = texture(u_texture, uv.xy);
fragColor = color;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.