Passing values from my Java program into GLSL using lwjgl
Lets say I have a fairly complex frag shader for figuring out just how much light goes to each pixel:
//shaders/screen.frag
varying vec4 vertColor; //unlit color
float intensity = 1.0; //lighting intensity.
//parameters vary from material to material:
float roughness_rms; //root-mean-square roughness (um).
float peak_angle; //how steep peaks are on average.
/* more parameters */
void main(){
/* complex shader code to calculate intensity */
gl_FragColor = intensity*vertColor; //set the light strength
}
Here is how I initialize the shaders:
//something.java
import <needed crap>
int shader, fragShader;
shader=ARBShaderObjects.glCreateProgramObjectARB();
fragShader=createFragShader("shaders/screen.frag");
ARBShaderObjects.glAttachObjectARB(shader, fragShader);
ARBShaderObjects.glLinkProgramARB(shader);
ARBShaderObjects.glValidateProgramARB(shader);
And how I use them:
//something.java
ARBShaderObjects.glUseProgramObjectARB(shader);
GL11.glBegin(GL11.GL_QUADS);
//etc.
My java code calculates roughness_rms and other parameters form vario开发者_如何学Pythonus materials. Furthermore, these parameters change when there are impacts with bullets, etc. My question is: How can I pass variables from my java to the shader language without regenerating the whole shader and recompiling it (that would be slow). Ideally, every quad I draw I would like to update the shader parameters.
You need to have a look at "Uniforms" in the GLSL Specs.
Basically, it's a storage qualifier for shader variables that indicates it will be set from outside of the shader (i.e. the CPU side) and changed less often than your inputs (at most once per geometry batch, not once per vertex).
This variable exists at the scope of the entire program (i.e. vertex shader + fragment shader + optional geometry and tessellation shaders); if you want to use it in, say, the vertex shader AND the fragment shader, you'll need to declare it in both but you'll only have to set it once in your client-side code.
In order to actually set the variable, you need to query the location of the uniform (by name) while your program is active. This location is stable as long as the program isn't recompiled so you can cache it and reuse it if you want. The value you set will also stick as long as the program isn't recompiled.
For example, to set a single float (this is OpenGL 3+; I'm not sure if the syntax is exactly the same below that level).
In your shader:
uniform float my_value;
In your client-side code:
glUseProgram(program_id);
GLint my_value_loc = glGetUniformLocation(program_id, "my_value");
glUniform1f(my_value_loc, 1.0);
glUseProgram(0);
Here's the reference for glGetUniformLocation (which is easy to use) and glUniformXX, which is a little more complex (lots of variants to set ints, floats, arrays, matrices, etc.).
精彩评论