QGLShaderProgramEffect ClassThe QGLShaderProgramEffect class provides applications with the ability to use shader programs written in GLSL as effects for 3D rendering. More... #include <QGLShaderProgramEffect> Inherits: QGLAbstractEffect. This class was introduced in Qt 4.8. Public Functions
Reimplemented Public Functions
Protected Functions
Detailed DescriptionThe QGLShaderProgramEffect class provides applications with the ability to use shader programs written in GLSL as effects for 3D rendering. Writing portable shadersShader programs can be difficult to reuse across OpenGL implementations because of varying levels of support for standard vertex attributes and uniform variables. In particular, GLSL/ES lacks all of the standard variables that are present on desktop OpenGL systems: gl_Vertex, gl_Normal, gl_Color, and so on. Desktop OpenGL lacks the variable qualifiers highp, mediump, and lowp. QGLShaderProgramEffect is built on top of QGLShaderProgram, which makes the process of writing portable shaders easier by prefixing all shader programs with the following lines on desktop OpenGL: #define highp #define mediump #define lowp This makes it possible to run most GLSL/ES shader programs on desktop systems. The programmer should also restrict themselves to just features that are present in GLSL/ES, and avoid standard variable names that only work on the desktop. QGLShaderProgramEffect also defines some standard attribute and uniform variable names that all shaders are expected to use. The following sections define these standard names. AttributesQGLShaderProgramEffect provides a standard set of 8 named vertex attributes that can be provided via QGLPainter::setVertexBundle():
These attributes may be used in the vertexShader(), as in the following example of a simple texture shader: attribute highp vec4 qt_Vertex; attribute highp vec4 qt_MultiTexCoord0; uniform mediump mat4 qt_ModelViewProjectionMatrix; varying highp vec4 qt_TexCoord0; void main(void) { gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex; qt_TexCoord0 = qt_MultiTexCoord0; } Uniform variablesQGLShaderProgramEffect provides a standard set of uniform variables for common values from the QGLPainter environment:
The above variables are usually declared in the shaders as follows (where highp may be replaced with mediump or lowp depending upon the shader's precision requirements): uniform highp mat4 qt_ModelViewProjectionMatrix; uniform highp mat4 qt_ModelViewMatrix; uniform highp mat4 qt_ProjectionMatrix; uniform highp mat3 qt_NormalMatrix; uniform sampler2D qt_Texture0; uniform sampler2D qt_Texture1; uniform sampler2D qt_Texture2; uniform highp vec4 qt_Color; Material parametersQGLShaderProgramEffect will provide information about the front and back materials from QGLPainter::faceMaterial() if the qt_Materials array is present in the shader code. The array should be declared as follows: struct qt_MaterialParameters { mediump vec4 emission; mediump vec4 ambient; mediump vec4 diffuse; mediump vec4 specular; mediump float shininess; }; uniform qt_MaterialParameters qt_Materials[2]; The front material will be provided as index 0 and the back material will be provided as index 1. If the shader only needs a single material, then the qt_Material variable can be declared instead: uniform qt_MaterialParameters qt_Material; The front material will be provided as the value of qt_Material and the back material will be ignored. Note: the emission parameter is actually QGLMaterial::emittedLight() combined with the QGLLightModel::ambientSceneColor() and QGLMaterial::ambientColor(). This helps simplify lighting shaders. Lighting parametersQGLShaderProgramEffect will provide information about the current lights specified on the QGLPainter if the qt_Lights array is present in the shader code. The array should be declared as follows: struct qt_LightParameters { mediump vec4 ambient; mediump vec4 diffuse; mediump vec4 specular; mediump vec4 position; mediump vec3 spotDirection; mediump float spotExponent; mediump float spotCutoff; mediump float spotCosCutoff; mediump float constantAttenuation; mediump float linearAttenuation; mediump float quadraticAttenuation; }; const int qt_MaxLights = 8; uniform qt_LightParameters qt_Lights[qt_MaxLights]; uniform int qt_NumLights; As shown, up to 8 lights can be supported at once. Usually this is more lights than most shaders need, and so the user can change the qt_MaxLights constant to a smaller value if they wish. Be sure to also call setMaximumLights() to tell QGLShaderProgramEffect about the new light count limit. The qt_NumLights uniform variable will be set to the actual number of lights that are active on the QGLPainter when update() is called. Because most shaders will only need a single light, the shader can declare the qt_Light variable instead of the qt_Lights array: struct qt_SingleLightParameters { mediump vec4 position; mediump vec3 spotDirection; mediump float spotExponent; mediump float spotCutoff; mediump float spotCosCutoff; mediump float constantAttenuation; mediump float linearAttenuation; mediump float quadraticAttenuation; }; uniform qt_SingleLightParameters qt_Light; Note that we have omitted the ambient, diffuse, and specular colors for the single light. QGLShaderProgramEffect will combine the material and light colors ahead of time into qt_Material or qt_Materials. This makes lighting shaders more efficient because they do not have to compute material_color * light_color; just material_color is sufficient. Varying variablesThe name and purpose of the varying variables is up to the author of the vertex and fragment shaders, but the following names are recommended for texture co-ordinates:
Lighting shader exampleThe following example demonstrates what a lighting shader that uses a single light, a single material, and a texture might look like. The shader is quite complex but demonstrates most of the features that can be found in the lighting implementation of a fixed-function OpenGL pipeline: attribute highp vec4 qt_Vertex; uniform highp mat4 qt_ModelViewProjectionMatrix; attribute highp vec3 qt_Normal; uniform highp mat4 qt_ModelViewMatrix; uniform highp mat3 qt_NormalMatrix; attribute highp vec4 qt_MultiTexCoord0; varying highp vec4 qt_TexCoord0; struct qt_MaterialParameters { mediump vec4 emission; mediump vec4 ambient; mediump vec4 diffuse; mediump vec4 specular; mediump float shininess; }; uniform qt_MaterialParameters qt_Material; struct qt_SingleLightParameters { mediump vec4 position; mediump vec3 spotDirection; mediump float spotExponent; mediump float spotCutoff; mediump float spotCosCutoff; mediump float constantAttenuation; mediump float linearAttenuation; mediump float quadraticAttenuation; }; uniform qt_SingleLightParameters qt_Light; varying mediump vec4 litColor; varying mediump vec4 litSecondaryColor; void main(void) { gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex; gTexCoord0 = qt_MultiTexCoord0; // Calculate the vertex and normal to use for lighting calculations. highp vec4 vertex = qt_ModelViewMatrix * qt_Vertex; highp vec3 normal = normalize(qt_NormalMatrix * qt_Normal); // Start with the material's emissive color and the ambient scene color, // which have been combined into the emission parameter. vec4 color = ggl_Material.emission; // Viewer is at infinity. vec3 toEye = vec3(0, 0, 1); // Determine the angle between the normal and the light direction. vec4 pli = qt_Light.position; vec3 toLight; if (pli.w == 0.0) toLight = normalize(pli.xyz); else toLight = normalize(pli.xyz - vertex.xyz); float angle = max(dot(normal, toLight), 0.0); // Calculate the ambient and diffuse light components. vec4 adcomponent = qt_Material.ambient + angle * qt_Material.diffuse; // Calculate the specular light components. vec4 scomponent; if (angle != 0.0) { vec3 h = normalize(toLight + toEye); angle = max(dot(normal, h), 0.0); float srm = qt_Material.shininess; vec4 scm = qt_Material.specular; if (srm != 0.0) scomponent = pow(angle, srm) * scm; else scomponent = scm; } else { scomponent = vec4(0, 0, 0, 0); } // Apply the spotlight angle and exponent. if (qt_Light.spotCutoff != 180.0) { float spot = max(dot(normalize(vertex.xyz - pli.xyz), qt_Light.spotDirection), 0.0); if (spot < qt_Light.spotCosCutoff) { adcomponent = vec4(0, 0, 0, 0); scomponent = vec4(0, 0, 0, 0); } else { spot = pow(spot, qt_Light.spotExponent); adcomponent *= spot; scomponent *= spot; } } // Apply attenuation to the colors. if (pli.w != 0.0) { float attenuation = qt_Light.constantAttenuation; float k1 = qt_Light.linearAttenuation; float k2 = qt_Light.quadraticAttenuation; if (k1 != 0.0 || k2 != 0.0) { float len = length(pli.xyz - vertex.xyz); attenuation += k1 * len + k2 * len * len; } color += adcomponent / attenuation; scolor += scomponent / attenuation; } else { color += adcomponent; scolor += scomponent; } // Generate the final output colors to pass to the fragment shader. float alpha = qt_Material.diffuse.a; litColor = vec4(clamp(color.rgb, 0.0, 1.0), alpha); litSecondaryColor = vec4(clamp(scolor.rgb, 0.0, 1.0), 0.0); } The corresponding fragment shader is as follows: varying mediump vec4 litColor; varying mediump vec4 litSecondaryColor; varying highp vec4 qt_TexCoord0; void main(void) { vec4 color = litColor * texture2D(qt_Texture0, qt_TexCoord0.st); gl_FragColor = clamp(color + litSecondaryColor, 0.0, 1.0); } Fixed function operationIf the OpenGL implementation does not support shaders, then QGLShaderProgramEffect will fall back to a flat color effect based on QGLPainter::color(). It is recommended that the application consult QGLPainter::isFixedFunction() to determine if some other effect should be used instead. Member Function Documentation
|