java - Android 版 OpenGL ES 2.0 中的纹理

标签 java android opengl-es sprite glsl

我是 OpenGL 的新手,我正在通过使用 ES 2.0 为 Android 制作 2D 游戏来自学。我首先创建一个“Sprite”类,该类创建一个平面并为其渲染纹理。为了练习,我在同一个地方交替绘制了两个 Sprite 对象。我在 ES 1.0 上工作得很好,但现在我已经切换到 2.0,我得到了一个没有错误的黑屏。我已经筋疲力尽地想弄清楚我做错了什么,但我有一种强烈的感觉,这与我的着色器有关。我将在这里转储所有相关代码,希望有人可以就我做错了什么给我一个答案或一些建议。如果不是很明显我做错了什么,也许有一些关于如何解决的建议?预先感谢您查看我将要发布的所有代码。

我发布的三个类(class)是:
GameRenderer - 我的 GLSurfaceView 的渲染器
Shader - 创建一个着色器程序对象
Sprite - 创建一个正方形并在其上绘制纹理
另外,我将发布我的顶点和 fragment 着色器源代码。

我认为相关的类(class)不够相关,无法发布:
游戏 Activity
GameView - 一个 GLSurfaceView
GameLoopThread - 我的主要游戏循环
FPSCounter - 每 100 帧将平均 FPS 输出到 logcat。

GameRender 类:

package com.detour.raw;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLU;
import android.opengl.Matrix;
import android.opengl.GLSurfaceView;

public class GameRenderer implements GLSurfaceView.Renderer{

private static final String LOG_TAG = GameRenderer.class.getSimpleName();
Context mContext;
Bitmap bitmap;

private float red = 0.0f;
private float green = 0.0f;
private float blue = 0.0f;

Shader shader;
FPSCounter fps;
Sprite sprite;
Sprite sprite2;
int x = 0;
private float[] mProjMatrix = new float[16];
private float[] mVMatrix = new float[16];

//int[] vertexShader;
//int[] fragmentShader;
//int program;
//String vShaderSource = "";
//String fShaderSource = "";


public GameRenderer(Context context){
    mContext = context;

    //create objects/sprites
    sprite = new Sprite(mContext);
    sprite2 = new Sprite(mContext);
    fps = new FPSCounter();
}

@Override
public void onDrawFrame(GL10 gl) {

    GLES20.glClearColor(red, green, blue, 1.0f);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    if(x>3){
        x=0;
    }
    if(x%2==0){
        sprite.draw(gl);
    }else{
        sprite2.draw(gl);
    }
    x++;

    fps.calculate();
    //fps.draw(gl);
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {

    GLES20.glViewport(0, 0, width, height);
    float ratio = (float)(width/height);
    Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 0.5f, 10);
}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    // TODO Auto-generated method stub

    GLES20.glEnable(GLES20.GL_TEXTURE_2D);
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    GLES20.glClearDepthf(1.0f);
    GLES20.glDepthFunc(GLES20.GL_LEQUAL);
    GLES20.glDepthMask(true);
    GLES20.glEnable(GLES20.GL_CULL_FACE);
    GLES20.glCullFace(GLES20.GL_BACK);
    GLES20.glClearColor(red, green, blue, 1.0f);

    //load sprite/object textures (preferably loop through an array of all sprites).
    sprite.loadGLTexture(gl, mContext, R.drawable.raw1);
    sprite2.loadGLTexture(gl, mContext, R.drawable.raw2);

    Matrix.setLookAtM(mVMatrix, 0, 0, 0, -5.0f, 0.0f, 0f, 0f, 0f, 0.0f, 0.0f);

    System.gc();
}

}

着色器类:

package com.detour.raw;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import android.content.Context;
import android.opengl.GLES20;
import android.util.Log;

public class Shader {

public static final String TAG = Shader.class.getSimpleName();  
int program;
int vertexShader;
int fragmentShader;

String vShaderSource;
String fShaderSource;

public Shader(){
    //blank constructor
    //createProgram();
}

public Shader(String vs_source, String fs_source){
    this.vShaderSource = vs_source;
    this.fShaderSource = fs_source;

    createProgram();
}

public Shader(int vs_source_id, int fs_source_id, Context context) {

    StringBuffer vs = new StringBuffer();
    StringBuffer fs = new StringBuffer();

    try{
        InputStream inputStream = context.getResources().openRawResource(vs_source_id);
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));

        String read = in.readLine();
        while (read != null) {
            vs.append(read + "\n");
            read = in.readLine();
        }
        vs.deleteCharAt(vs.length() - 1);

        inputStream = context.getResources().openRawResource(fs_source_id);
        in = new BufferedReader(new InputStreamReader(inputStream));

        read = in.readLine();
        while (read != null) {
            fs.append(read + "\n");
            read = in.readLine();
        }
        fs.deleteCharAt(fs.length() - 1);
    }catch (Exception e){
        Log.d("ERROR-readingShader", "Could not read shader: " + e.getLocalizedMessage());
    }

    this.vShaderSource = vs.toString();
    this.fShaderSource = fs.toString();

    createProgram();
}

private void createProgram(){

    program = GLES20.glCreateProgram();
    if(program!=0){
        vertexShader = createShader(GLES20.GL_VERTEX_SHADER, vShaderSource);
        fragmentShader = createShader(GLES20.GL_FRAGMENT_SHADER, fShaderSource);

        GLES20.glAttachShader(program, vertexShader);
        GLES20.glAttachShader(program, fragmentShader);
        GLES20.glLinkProgram(program);
    }else{
        Log.e(TAG, "Couldn't create program.");
    }


}

private int createShader(int type, String source){
    int shader = GLES20.glCreateShader(type);
    if(shader!=0){
        GLES20.glShaderSource(shader, source);
        GLES20.glCompileShader(shader);
    }

    return shader;
}

public int getProgram(){
    return program;
}

Sprite 类:

package com.detour.raw;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;

public class Sprite {

//public static final int FRAME_WIDTH = 64;
//public static final int FRAME_HEIGHT = 64;
private static final String LOG_TAG = Sprite.class.getSimpleName();
Context mContext;
Bitmap bitmap;

private int textureLoc;
private int vertexLoc;
private int[] textures = new int[1];
//private int[] pixels;

/*private float textureCoordinates[] = {
        0.0f, 0.0f,
        0.0f, 1.0f,
        1.0f, 1.0f,
        1.0f, 0.0f};*/

private float vertices[] = {
          -1.0f,  1.0f,// 0.0f,
          -1.0f, -1.0f,// 0.0f,
           1.0f, -1.0f,// 0.0f,
           1.0f,  1.0f// 0.0f
           };

private short[] indices = {
        0, 1, 2,
        0, 2, 3};

private FloatBuffer vertexBuffer;
//private IntBuffer textureBuffer;
private ShortBuffer indexBuffer;

Shader shader;
int program;
String vShaderSource = "";
String fShaderSource = "";

public Sprite(Context context){

    mContext = context;

    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
    vbb.order(ByteOrder.nativeOrder());
    vertexBuffer = vbb.asFloatBuffer();
    vertexBuffer.put(vertices);
    vertexBuffer.position(0);



    ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
    ibb.order(ByteOrder.nativeOrder());
    indexBuffer = ibb.asShortBuffer();
    indexBuffer.put(indices);
    indexBuffer.position(0);

}

public void draw(GL10 gl) {

    GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_FLOAT, indexBuffer);

}

public void loadGLTexture(GL10 gl, Context context, int id){

    shader = new Shader(R.raw.sprite_vs, R.raw.sprite_fs, mContext);
    program = shader.getProgram();

    GLES20.glUseProgram(program);

    vertexLoc = GLES20.glGetAttribLocation(program, "a_position");
    textureLoc = GLES20.glGetUniformLocation(program, "u_texture"); //texture

    InputStream is = context.getResources().openRawResource(id);
    try {
        bitmap = BitmapFactory.decodeStream(is);
    } finally {
        try {
            is.close();
            is = null;
        } catch (IOException e) {
        }
    }

    //pixels = new int[(bitmap.getWidth()*bitmap.getHeight())];
    //bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());

    /*ByteBuffer byteBuf = ByteBuffer.allocateDirect(pixels.length * 4);
    byteBuf.order(ByteOrder.nativeOrder());
    textureBuffer = byteBuf.asIntBuffer();
    textureBuffer.put(pixels);
    textureBuffer.position(0);*/

    GLES20.glDeleteTextures(1, textures, 0);
    GLES20.glGenTextures(1, textures, 0);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
    GLES20.glUniform1i(textureLoc, 0);

    GLES20.glEnableVertexAttribArray(vertexLoc);
    GLES20.glVertexAttribPointer(vertexLoc, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer);

    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    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);

    //GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, FRAME_WIDTH, FRAME_HEIGHT, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuf);//(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

    bitmap.recycle();
}

}

顶点着色器(sprite_vs.txt):

#version 110

attribute vec2 a_position;

varying vec2 v_texcoord;

void main()
{
    gl_Position = vec4(a_position, 0.0, 1.0);
    v_texcoord = a_position * vec2(0.5) + vec2(0.5);
}

fragment (像素)着色器(sprite_fs.txt):

#version 110

uniform sampler2D u_texture;

varying vec2 v_texcoord;

void main()
{
    gl_FragColor = texture2D(u_texture, v_texcoord);
}

非常感谢您真的花时间浏览了这篇文章!希望其他人将来也可以将其用作自己的资源。

最佳答案

几个观察/问题:

  1. 我不知道您是如何更改 fragment 着色器的,但是当前发布的版本需要一个精度说明符。只需添加:

    precision mediump float;
    

    到顶部,它应该可以工作。现在关于黑屏这里有一些问题:

  2. 当您将 glClearColor 更改为非黑色并注释掉所有绘制命令时,它看起来仍然是黑色吗?如果是这样,那么您遇到的问题比纹理更大。

  3. 其次,如果您忽略纹理输出并尝试将每个 Sprite 绘制为没有纹理数据的平面彩色矩形,您会得到什么?您应该能够在屏幕上看到一些彩色矩形。

  4. 最后,您需要在调用 glDrawElements 之前绑定(bind)纹理。 (不过在本例中这应该无关紧要,因为您还没有更改状态。)

关于java - Android 版 OpenGL ES 2.0 中的纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6197081/

相关文章:

Android Studio - 多个屏幕的图像使 apk 的大小变得异常大

ios - 代码 : No matching function for call to glGenBuffers

java - 从 Java 中的字符串中删除非 ASCII 字符

java - VLCJ从不同文件夹加载32位和64位库

java - Android POST 请求到 PHP

android - 具有多个倒数计时器的 Recyclerview 会导致闪烁

c++ - 我可以用 Android 制作一个相当原生的 C++ 应用程序吗?

android - iOS 和 Android 的 OpenGL ES 区别

java - 如何在 Java 中处理时间

java - 如何获取HashMap中存在对应关系的计数?