OPENGL|ES第三天,Compiling Shaders and Drawing to the Screen

we’ll first load and compile the shaders that we’ve defined, and then we’ll link them together into an OpenGL program. We’ll then be able to use this shader program to draw

our air hockey table to the screen.

一.Loading shaders

Now that we’ve written the code for our shaders, the next step is to load them into memory.

1.Loading Text from a Resource

Create a new Java source package in your project, com.airhockey.android.util, and  n that package, create a new class called TextResourceReader. Add the following code

inside the class:

public static String readTextFileFromResource(Context context,int resourceId) {
    StringBuilder body = new StringBuilder();
    try {
        InputStream inputStream =context.getResources().openRawResource(resourceId);
        InputStreamReader inputStreamReader =new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        String nextLine;
        while ((nextLine = bufferedReader.readLine()) != null) {
            body.append(nextLine);
            body.append('\n');
            }
    } catch (IOException e) {
        throw new RuntimeException("Could not open resource: " + resourceId, e);
    } catch (Resources.NotFoundException nfe) {
        throw new RuntimeException("Resource not found: " + resourceId, nfe);
    }
    return body.toString();
}

We’ve defined a method to read in text from a resource, readTextFileFromResource(), and we’ll pass in the current Android context and the resource ID.


2.Reading in the Shader Code

We’re now going to add the calls to actually read in the shader code.

//AirHockeyRender.java
String vertexShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_vertex_shader);
String fragmentShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_fragment_shader);
the following to the top of the class to define a context

private final Context context;

二.Compiling Shaders

The next step is to compile each shader. To begin, create a new class, ShaderHelper, and add the following code inside the class:

//ShaderHelper
private static final String TAG = "ShaderHelper";
public static int compileVertexShader(String shaderCode) {
    return compileShader(GL_VERTEX_SHADER, shaderCode);
}
public static int compileFragmentShader(String shaderCode) {
    return compileShader(GL_FRAGMENT_SHADER, shaderCode);
}
private static int compileShader(int type, String shaderCode) {
}

1.Creating a New Shader Object

//ShaderHelper.java
final int shaderObjectId = glCreateShader(type);
if (shaderObjectId == 0) {
    if (LoggerConfig.ON) {
        Log.w(TAG, "Could not create new shader.");
    }
    return 0;
}
We create a new shader object with a call to glCreateShader() and store the ID of that object in shaderObjectId. The type can be GL_VERTEX_SHADER for a vertex shader,

or GL_FRAGMENT_SHADER for a fragment shader.


2.Uploading and Compiling the Shader Source Code

Add the following code to upload our shader source code into the shader object:

//AirHockey1/src/com/airhockey/android/util/ShaderHelper.java
glShaderSource(shaderObjectId, shaderCode);
This call tells OpenGL to read in the source code defined in the String shaderCode and associate it with the shader object referred to by shaderObjectId. We can then call

glCompileShader(shaderObjectId) to compile the shader:

glCompileShader(shaderObjectId);

This tells OpenGL to compile the source code that was previously uploaded to shaderObjectId.

3.Retrieving the Compilation Status

//ShaderHelper.java
final int[] compileStatus = new int[1];
glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0);

To check whether the compile failed or succeeded.

4.Retrieving the Shader Info Log

不想看


5.Compiling the Shaders from Our Renderer Class

Now it's time to use the code we've just created.

//AirHockey1/src/com/airhockey/android/AirHockeyRenderer.java
int vertexShader = ShaderHelper.compileVertexShader(vertexShaderSource);
int fragmentShader = ShaderHelper.compileFragmentShader(fragmentShaderSource);

三.Linking Shaders Together into an OpenGL Program

Now that we’ve loaded and compiled a vertex shader and a fragment shader, the next step is to bind them together into a single program.

1.Understanding OPENGL programs

An OpenGL program is simply one vertex shader and one fragment shader linked together into a single object. Without a fragment shader, OpenGL wouldn’t know how

to draw the fragments that make up each point, line, and triangle; and without a vertex shader, OpenGL wouldn’t know where to draw these fragments.

//AirHockey1/src/com/airhockey/android/util/ShaderHelper.java
public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
}

2.Creating a New Program Object and Attaching Shaders

The first thing we’ll do is create a new program object with a call to glCreateProgram() and store the ID of that object in programObjectId. Let’s add the following code:

//AirHockey1/src/com/airhockey/android/util/ShaderHelper.java
final int programObjectId = glCreateProgram();if (programObjectId == 0) { if (LoggerConfig.ON) { Log.w(TAG, "Could not create new program"); } return 0;}

The next step is to attach our shaders:

//AirHockey1/src/com/airhockey/android/util/ShaderHelper.java
glAttachShader(programObjectId, vertexShaderId);
glAttachShader(programObjectId, fragmentShaderId);
Using glAttachShader(), we attach both our vertex shader and our fragment shader to the program object.

3.Linking the Program

We’re now ready to join our shaders together.  To check whether the link failed or succeeded

//AirHockey1/src/com/airhockey/android/util/ShaderHelper.java
final int[] linkStatus = new int[1];
glGetProgramiv(programObjectId, GL_LINK_STATUS, linkStatus, 0);

//AirHockey1/src/com/airhockey/android/util/ShaderHelper.java
if (LoggerConfig.ON) {
    // Print the program info log to the Android log output.
    Log.v(TAG, "Results of linking program:\n"+ glGetProgramInfoLog(programObjectId));
}

4.Verifying the Link Status and Returning the Program Object ID

We now need to check the link status: if it’s 0, that means that the link failed and we can’t use this program object, so we should delete it and return 0 to the calling code:

//AirHockey1/src/com/airhockey/android/util/ShaderHelper.java
if (linkStatus[0] == 0) {
    // If it failed, delete the program object.
    glDeleteProgram(programObjectId);
    if (LoggerConfig.ON) {
        Log.w(TAG, "Linking of program failed.");
    }
    return 0;
}

We’re now done, so let’s return the new program object ID to our calling code:

//AirHockey1/src/com/airhockey/android/util/ShaderHelper.java
return programObjectId;

5.Adding the Code to Our Renderer Class

let’s go ahead and call that from our program. First let’s add the following member variable to the top of AirHockeyRenderer:

//AirHockey1/src/com/airhockey/android/AirHockeyRenderer.java
private int program;

This integer will store the ID of the linked program. Let’s link the shaders together by adding the following call to the end of onSurfaceCreated():

//AirHockey1/src/com/airhockey/android/AirHockeyRenderer.java
program = ShaderHelper.linkProgram(vertexShader, fragmentShader);

四.Making the Final Connections

Now it’s time to start building on this foundation and making the final connections. we’re going to put the pieces together.

1.Validate Our OpenGL Program Object

Before we start using an OpenGL program, we should validate it first to see if the program is valid for the current OpenGL state.

//AirHockey1/src/com/airhockey/android/util/ShaderHelper.java
public static boolean validateProgram(int programObjectId) {
    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));
    return validateStatus[0] != 0;
}

We call glValidateProgram() to validate the program, and then we check the results with a call to glGetProgramiv(), using GL_VALIDATE_STATUS as the parameter name.

2.Getting the Location of a Uniform

The next step is to get the location of the uniform that we defined in our shader earlier on. we’ll need the location for u_Color so that we can set the color when we’re about

to draw.

We’ll use this uniform called u_Color to set the color of what we’re drawing. Add the following definitions to the top of AirHockeyRenderer:

//AirHockey1/src/com/airhockey/android/AirHockeyRenderer.java
private static final String U_COLOR = "u_Color";
private int uColorLocation;

Add the following to the end of onSurfaceCreated():

//AirHockey1/src/com/airhockey/android/AirHockeyRenderer.java
uColorLocation = glGetUniformLocation(program, U_COLOR);

We call glGetUniformLocation() to get the location of our uniform, and we store that location in uColorLocation. We’ll use that when we want to update the value of this

uniform later on.

3.Getting the Location of an Attribute





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值