我尝试了一个简单的程序,动态生成纹理并使用NDK将其映射到四边形。在模拟器上一切都很好但在真实设备上失败了。 这是我的代码:
private static class Renderer implements GLSurfaceView.Renderer
{
@Override
public void onDrawFrame(GL10 gl)
{
nativeDrawFrame();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
nativeInit(width, height);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
// do nothing...
}
}
和本机代码:
const static GLfloat vertices_f[4][2] =
{
{ 0.0f, 0.0f },
{ 100.0f, 0.0f },
{ 100.0f, 100.0f },
{ 0.0f, 100.0f }
};
const static GLfloat texCoords_f[4][2] =
{
{ 0.0f, 0.0f },
{ 1.0f, 0.0f },
{ 1.0f, 1.0f },
{ 0.0f, 1.0f }
};
JNIEXPORT void JNICALL Java_com_sangfor_gltest_GLView_nativeInit(JNIEnv * env, jobject obj, jint width, jint height)
{
if (!bitmap)
{
// allocate dynamic texture memory
bitmap = memalign(16, 1024*1024);
if (!bitmap)
{
__android_log_print(ANDROID_LOG_ERROR, "native-render", "failed allocation.");
return;
}
}
glViewport(0, 0, width, height);
//glMatrixMode(GL_PROJECTION);
//glLoadIdentity();
//glOrthox(0, 0x10000, 0, 0x10000, 0x10000, -0x10000);
//glClearColorx(0, 0, 0, 0);
glGenTextures(1, &texture);
__android_log_print(ANDROID_LOG_INFO, "native-render", "texture = %d", texture);
// glVertexPointer(2, GL_FIXED, 0, vertices);
// glTexCoordPointer(2, GL_FIXED, 0, texCoords);
//glEnableClientState(GL_COLOR_ARRAY);
glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
glEnable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
JNIEXPORT void JNICALL Java_com_sangfor_gltest_GLView_nativeDrawFrame(JNIEnv * env, jobject obj)
{
struct timeval tv;
unsigned char color_value;
glClear(GL_COLOR_BUFFER_BIT);
// fill texture according to current timestamp
gettimeofday(&tv, NULL);
color_value = (unsigned char)(tv.tv_usec * 0.000255f);
memset(bitmap, color_value, 1024*1024);
__android_log_print(ANDROID_LOG_INFO, "native-render", "color_value = %d", color_value);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, bitmap);
glBindTexture(GL_TEXTURE_2D, texture);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords_f);
glVertexPointer(2, GL_FLOAT, 0, vertices_f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glFlush();
}
在模拟器上,它按照我的预期工作:屏幕上的某个区域不断改变其颜色。 但是,当我在真实设备(三星Galaxy S 2.3.3和华硕Transformer TF101 3.2.1)上运行时,它只显示一个白色块,纹理映射似乎无法正常工作。
我尝试添加并注释掉投影变换,通过调用glEnable(GL_TEXTURE_2D)
启用纹理映射,通过调用glDisable(...)
禁用Alpha混合和测试,将glBindTexture
和glTexImage2D
移至init功能,将纹理大小更改为32 x 32,但这些都不起作用。
任何人都可以帮我弄清楚为什么纹理映射在真实设备上失败了吗?有GPU限制吗?
编辑:我已经尝试过Spoon的建议并找到了真正的问题。无论我绑定哪个纹理,设备都使用名为 0 的纹理来渲染四边形,因此glBindTexture(GL_TEXTURE_2D, 0)
工作正常,但glBindTexture(GL_TEXTURE_2D, 1)
并且glGenTextures(...)
返回的任何内容都会失败。这意味着我只能保存一个纹理,但我必须使用2个或更多。
答案 0 :(得分:0)
白色块意味着纹理正在工作,但纹理未正确加载。
如果实际的映射是个问题,你会看到纹理,但所有颜色都会变形或混乱。
检查glGenTextures()
给出的实际值。我发现在更高版本的android(2.2+)上使用openGL-es 1.x时,glGenTextures()
抛弃了一些非常随机的数字,而不是给出0,1,2,3等的id。可能是你必须手动提供您自己的ID,而不是使用glGenTextures()
或者,检查像素数据是否正在从文件中正确加载。如果您的文件名错误或文件丢失,但可能会出现一些允许应用程序继续运行的错误处理,则可能会出现空白的白色纹理。和/或不要忘记刷新res文件夹,甚至在添加新纹理时清理项目
更新:
我就这样做了:
public class Texture{
private int textureId = -1;
// initialise to -1
public int getTextureId(){
return textureId;
}
public void loadTexture(GL10 gl, Context context){
String[] filenamesplit = filename.split("\\.");
name = filenamesplit[filenamesplit.length-2];
int[] textures = new int[1];
//Generate one texture pointer...
//GLES20.glGenTextures(1, textures, 0);
textures[0] = ((IridianGraphicsEngine)context).texturecount;
((IridianGraphicsEngine)context).texturecount++;
//...and bind it to our array
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
//Create Nearest Filtered Texture
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
//Different possible texture parameters, e.g. GLES20.GL_CLAMP_TO_EDGE
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
Bitmap bitmap = FileUtil.openBitmap(name, context);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
textureId = textures[0];
}
}
然后在绘图时:
public class Mesh{
private Texture texture;
public void draw(GL10 gl){
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// Pass the vertex buffer in
gl.glVertexPointer(3, GL10.GL_FLOAT, 0,
vertices);
int textureId = texture.getTextureId();
if(textureID>=0){
// Enable Textures
gl.glEnable(GL10.GL_TEXTURE_2D);
// Get specific texture.
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);
// Use UV coordinates.
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// Pass in texture coordinates
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureCoordinates);
}
// Pass in vertex normals
gl.glNormalPointer(GL10.GL_FLOAT, 0, normals);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glDrawElements(GL10.GL_TRIANGLES, numindices,GL10.GL_UNSIGNED_SHORT, indices);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
if(textureID>=0){
// Disable buffers
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
然而,这一切都在java中,并且使用了一个奇怪的opengl-es 2.0混合纹理加载和opengl-es 1.1用于绘制
答案 1 :(得分:0)
我将我的JNI本机方法移动到一个单独的包装类,类似于Android NDK中的gl2-jni示例,然后问题解决了。我不知道为什么在包装类中实现静态本机代码会产生差异,但无论如何,它都有效。
<强> GLJNILib.java 强>
// Wrapper for native library
public class GLJNILib {
static {
System.loadLibrary("gljni");
}
/**
* @param width the current view width
* @param height the current view height
*/
public static native void init(int width, int height);
public static native void step();
}
<强> GLJNIView.java 强>
// some other stuff
private class Renderer implements GLSurfaceView.Renderer {
private static final String TAG = "Renderer";
public void onDrawFrame(GL10 gl) {
GLJNILib.step();
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLJNILib.init(width, height);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Do nothing.
}
}
// some other stuff