Using GL_RG_EXT and GL_UNSINGED_BYTE - opengl-es-2.0

I met some problems while using GL_RG_EXT and GL_UNSIGNED_BYTE. Related code:
class TextureBuffer {
public:
GLuint texture;
GLuint frameBuffer;
GLenum internalformat;
GLenum format;
GLenum type;
int w,h;
TextureBuffer() : texture(0), frameBuffer(0) {}
void release() {
if(texture)
{
glDeleteTextures(1, &texture);
texture = 0;
}
if(frameBuffer)
{
glDeleteFramebuffers(1, &frameBuffer);
frameBuffer = 0;
}
}
};
TextureBuffer _maskTexture;
generateRenderToTexture(GL_RG_EXT, GL_RG_EXT, GL_UNSIGNED_BYTE, _maskTexture, _imageWidth, _imageHeight, false);
void SharpenGPU::generateRenderToTexture(GLint internalformat, GLenum format, GLenum type,
TextureBuffer &tb, int w, int h, bool linearInterp)
{
glGenTextures(1, &tb.texture);
glBindTexture(GL_TEXTURE_2D, tb.texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linearInterp ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linearInterp ? GL_LINEAR : GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, NULL);
glGenFramebuffers(1, &tb.frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, tb.frameBuffer);
glClear(_glClearBits);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tb.texture, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
printf("Framebuffer status: %x", (int)status);
tb.internalformat = internalformat;
tb.format = format;
tb.type = type;
tb.w = w;
tb.h = h;
}
When I use the following code to define _maskTexture,
generateRenderToTexture(GL_RG_EXT, GL_RG_EXT, GL_HALF_FLOAT_OES, _maskTexture, _imageWidth, _imageHeight, false);
the code goes well. But if I use the lines below to define the _maskTexture, an error appears,
generateRenderToTexture(GL_RG_EXT, GL_RG_EXT, GL_UNSIGNED_BYTE, _maskTexture, _imageWidth, _imageHeight, false);
Error:
ProgramInfoLog: Validation Failed: Fragment program failed to compile with current context state.
Validation Failed: Vertex program failed to compile with current context state.
I'm really puzzled about it.
I knew that the error info is caused by compiling the vertex and shader function. Here is the shader function I found to cause the error:
{
const GLchar fShaderText[] = FRAGMENT_SHADER_SOURCE
(
uniform sampler2D Distance4d; // unsimilar with version 6, patch distance has been prepared.
uniform sampler2D DistanceCenter;
varying highp vec2 uv0;
void main()
{
highp float u_dx = 1./imageWH.x;
highp float v_dy = 1./imageWH.y;
highp vec2 ItBt = texture2D(DistanceCenter, uv0).yz;
highp vec2 direcXY;
highp float remainX = floor(mod(floor(imageWH.x * uv0.x + 0.6),2.) + 0.5); // 0 or 1
highp float remainY = floor(mod(floor(imageWH.y * uv0.y + 0.6),2.) + 0.5); // 0 or 1;
{
//center
highp float sum0 = texture2D(DistanceCenter, uv0).x;
highp float sumMin = sum0;
direcXY = vec2(0.,0.);
highp vec4 sum4d = texture2D(Distance4d, uv0);
//left
if(sum4d.x < sumMin)
{
sumMin = sum4d.x;
direcXY = vec2(-u_dx,0.);
}
//up
if(sum4d.y < sumMin)
{
sumMin = sum4d.y;
direcXY = vec2(0.,v_dy);
}
//right
if(sum4d.z < sumMin)
{
sumMin = sum4d.z;
direcXY = vec2(u_dx,0.);
}
//down
if(sum4d.w < sumMin) // when i disable this line, the error info will disappear
{
sumMin = sum4d.w;
direcXY = vec2(0.,-v_dy);
}
direcXY = (sumMin/sum0 > 0.7)? vec2(0.,0.):direcXY;// Section 4.1.1. thresholding. for that center position is preferred
}
gl_FragColor = vec4(ItBt.x, ItBt.x - ItBt.y, direcXY.x, direcXY.y);
//vec4(It, It - Bt, dx, dy);
}
);
// Store the progrm, compute uniform locations
ProgramUniforms &pu = (_programs["findP2SpeedUpforS7"] = ProgramUniforms());
pu.program = compileShaders(gVertexShaderText, fShaderText);
pu.uniformMap["mvpMatrix"] = glGetUniformLocation(pu.program, "mvpMatrix");
pu.uniformMap["Distance4d"] = glGetUniformLocation(pu.program, "Distance4d");
pu.uniformMap["DistanceCenter"] = glGetUniformLocation(pu.program, "DistanceCenter");
pu.uniformMap["imageWH"] = glGetUniformLocation(pu.program, "imageWH");
}
I have marked out the related line causing the error.
Did someone meet a similar case?
Thanks.

Related

Moving a variable in my fragment shader makes it either not work or completely crash my PC

When running on a Radeon HD 7750 and declaring thisMaterialsource at (A), the program either crashes or freezes the PC to the point I have to power cycle the machine. It works fine when it's declared at position (B). When running on a Geforce GTX 1070, it works fine in both cases.
void main()
{
vec3 ambientSum = vec3(0);
vec3 diffuseSum = vec3(0);
vec3 specSum = vec3(0);
vec3 ambient, diffuse, spec;
// (A) - doesn't work when declared/set here <----------------------------------------
// Material thisMaterialsource = materialBanks[0].bank.materials[materialId];
if (gl_FrontFacing)
{
for (int i=0; i<light.activeLights; ++i)
{
calculateLight(i, inWorldPos.xyz, inNormal.xyz, ambient, diffuse, spec);
ambientSum += ambient;
diffuseSum += diffuse;
specSum += spec;
}
}
else
{
for (int i=0; i<light.activeLights; ++i)
{
calculateLight(i, inWorldPos.xyz, -inNormal.xyz, ambient, diffuse, spec);
ambientSum += ambient;
diffuseSum += diffuse;
specSum += spec;
}
}
ambientSum /= light.activeLights;
// (B) - works when declared/set here <----------------------------------------
Material thisMaterialsource = materialBanks[0].bank.materials[materialId];
vec4 texColor = thisMaterialsource.baseColorFactor;
if(thisMaterialsource.colorTextureIndex > -1){ texColor = texture(texSampler[thisMaterialsource.colorTextureIndex], inUV0) * thisMaterialsource.baseColorFactor; }
vec4 emissive = thisMaterialsource.emissiveFactor;
if (thisMaterialsource.unlitTextureIndex > -1) {
emissive = texture(texSampler[thisMaterialsource.unlitTextureIndex], inUV0) * thisMaterialsource.emissiveFactor;
}
outColor = vec4(ambientSum + diffuseSum, 1) * texColor + vec4(specSum, 1) + emissive;
}
Full shader code:
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_nonuniform_qualifier : require
struct LightInfo
{
vec3 Position;//Light Position in eye-coords
vec3 La;//Ambient light intensity
vec3 Ld;//Diffuse light intensity
vec3 Ls;//Specular light intensity
};
struct MaterialInfo
{
vec3 Ka;//Ambient reflectivity
vec3 Kd;//Diffuse reflectivity
vec3 Ks;//Specular reflectivity
float Shininess;//Specular shininess factor
};
struct Material{
vec4 baseColorFactor;
vec4 emissiveFactor;
float metallicFactor;
float roughnessFactor;
float normalScale;
float occlusionStrength;
int colorTextureIndex;
int normalTextureIndex;
int unlitTextureIndex;
int ambientOcclusionTextureIndex;
int metallicRoughnessTextureIndex;
int isTwoSided;
int alphaMode;
float alphaCutoff;
};
struct MaterialBank{
Material materials[80];
};
struct LightData{
vec4 pos;
vec4 color;
};
#define MAX_CAMERAS 16
struct CameraData{
vec4 pos;
mat4 mat;
mat4 view;
mat4 proj;
mat4 clip;
};
layout(push_constant) uniform PushConsts {
uint cameraIndex;
uint time;
} pushConsts;
layout(binding = 0) uniform UniformBufferCamera {
CameraData cameras[MAX_CAMERAS];
uint cameraCount;
uint cameraMax;
} cam;
layout(binding = 1) uniform UniformBufferLight {
LightData lights[16];
vec4 ambientColor;
int activeLights;
} light;
layout(set=1, binding = 0) uniform sampler2D texSampler[32];
layout(set=2, binding = 0) uniform UniformBufferMat {
MaterialBank bank;
} materialBanks[1];
layout(location = 0) in vec4 inNormal;
layout(location = 1) in vec2 inUV0;
layout(location = 2) in vec2 inUV1;
layout(location = 3) in vec4 inWorldPos;
layout(location = 4) in flat uint materialId;
layout(location = 0) out vec4 outColor;
void calculateLight(int lightIndex, vec3 position, vec3 norm, out vec3 ambient, out vec3 diffuse, out vec3 spec)
{
LightData thisLightSource = light.lights[lightIndex];
Material thisMaterialsource = materialBanks[0].bank.materials[materialId];
LightInfo thisLight;
thisLight.Position = thisLightSource.pos.xyz;//Light Position in eye-coords
thisLight.La = light.ambientColor.rgb;//Ambient light intensity
thisLight.Ld = thisLightSource.color.rgb;//Diffuse light intensity
thisLight.Ls = thisLightSource.color.rgb;//Specular light intensity
MaterialInfo thisMaterial;
vec4 texColor = thisMaterialsource.baseColorFactor;
if (thisMaterialsource.colorTextureIndex > -1){ texColor = texture(texSampler[thisMaterialsource.colorTextureIndex], inUV0) * thisMaterialsource.baseColorFactor; }
vec4 mrSample = vec4(1);
if (thisMaterialsource.metallicRoughnessTextureIndex > -1) { mrSample = texture(texSampler[thisMaterialsource.metallicRoughnessTextureIndex], inUV0); }
float perceptualRoughness = mrSample.g * thisMaterialsource.roughnessFactor;
float metallic = mrSample.b * thisMaterialsource.metallicFactor;
thisMaterial.Ka= texColor.rgb * (metallic+perceptualRoughness)/2;//Ambient reflectivity
thisMaterial.Kd= texColor.rgb * (perceptualRoughness);//Diffuse reflectivity
thisMaterial.Ks= texColor.rgb * (metallic-perceptualRoughness);//Specular reflectivity
thisMaterial.Shininess= (metallic);//Specular shininess factor
vec3 n = normalize(norm);
vec3 s = normalize(thisLight.Position - position);
vec3 v = normalize(-position);
vec3 r = reflect(-s, n);
ambient = thisLight.La * thisMaterial.Ka;
if (thisMaterialsource.ambientOcclusionTextureIndex > -1){
float ao = texture(texSampler[thisMaterialsource.ambientOcclusionTextureIndex], inUV0).r;
ambient = ambient * ao;
}
float sDotN = max(dot(s, n), 0.0);
diffuse = thisLight.Ld * thisMaterial.Kd * sDotN;
spec = thisLight.Ls * thisMaterial.Ks * pow(max(dot(r, v), 0.0), thisMaterial.Shininess);
}
void main()
{
vec3 ambientSum = vec3(0);
vec3 diffuseSum = vec3(0);
vec3 specSum = vec3(0);
vec3 ambient, diffuse, spec;
// (A) - doesn't work when declared/set here <----------------------------------------
// Material thisMaterialsource = materialBanks[0].bank.materials[materialId];
if (gl_FrontFacing)
{
for (int i=0; i<light.activeLights; ++i)
{
calculateLight(i, inWorldPos.xyz, inNormal.xyz, ambient, diffuse, spec);
ambientSum += ambient;
diffuseSum += diffuse;
specSum += spec;
}
}
else
{
for (int i=0; i<light.activeLights; ++i)
{
calculateLight(i, inWorldPos.xyz, -inNormal.xyz, ambient, diffuse, spec);
ambientSum += ambient;
diffuseSum += diffuse;
specSum += spec;
}
}
ambientSum /= light.activeLights;
// (B) - works when declared/set here <----------------------------------------
Material thisMaterialsource = materialBanks[0].bank.materials[materialId];
vec4 texColor = thisMaterialsource.baseColorFactor;
if(thisMaterialsource.colorTextureIndex > -1){ texColor = texture(texSampler[thisMaterialsource.colorTextureIndex], inUV0) * thisMaterialsource.baseColorFactor; }
vec4 emissive = thisMaterialsource.emissiveFactor;
if (thisMaterialsource.unlitTextureIndex > -1) {
emissive = texture(texSampler[thisMaterialsource.unlitTextureIndex], inUV0) * thisMaterialsource.emissiveFactor;
}
outColor = vec4(ambientSum + diffuseSum, 1) * texColor + vec4(specSum, 1) + emissive;
}
Please excuse the quality of my shader code, I'm just experimenting and cobbling stuff together, and came upon this issue that, aside from being annoying to debug, completely blindsided me.
It's fixed now, but I'd like to know why it happened and honestly, unlike lots of other issues I've dealt with while learning, I don't even know where to start looking.
Is this simply a bug in GPU/drivers or a manifestation of some profound and arcane machinations that dictate how shaders work? How can I debug this sort of issues? Is there a way to see this is going to fail, other than running it? I'd really like to know, I care much more about learning from this than just getting it to run.
If you don't mind going through one or two more power-off-on cycles, try the following simplification for your shader:
void main()
{
... variables
// (A) - doesn't work when declared/set here <----------------------------------------
// Material thisMaterialsource = materialBanks[0].bank.materials[materialId];
/// Instead of doing two almost identical loops, extract the normal inversion
vec3 normal = (gl_FrontFacing ? inNormal : -inNormal).xyz;
for (int i=0; i<light.activeLights; ++i)
{
calculateLight(i, inWorldPos.xyz, normal, ambient, diffuse, spec);
ambientSum += ambient;
diffuseSum += diffuse;
specSum += spec;
}
ambientSum /= light.activeLights;
// (B) - works when declared/set here <----------------------------------------
Material thisMaterialsource = materialBanks[0].bank.materials[materialId];
... all the rest
}
A wild guess might be the following: the HD7750 is relatively old and two loops over (dynamic number) of active lights can generate too much shader bytecode, if the GLSL compiler does something strange. So you get an overflow of available thread memory. The GTX 1070 is obviously much more powerful and would not suffer from an "abuse" like this.
Other than this, the shader should be fine and the above change is still a workaround, not a must. We have encountered strange behavior (i.e., somehting not working contrary to the spec) of GLSL even on newer Radeons, but it was not similar to your problem.

How to color individual pixels with OpenGL ES 2.0?

Is there possible to change the color of an individual pixel with OpenGL ES 2.0? Right now, I have found that I can manage that using a vertex. I've used this method to draw it:
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);
The size of the point was set to minimum in order to be a single pixel painted.
All good, until I've needed to draw 3 to 4 millions of them! It takes 5-6 seconds to initialize only one frame. This is time-inefficient as long as the pixels will be updated constantly. The update/ refresh would be preferable to be as close as possible to 60 fps.
How can I paint them in a more efficient way?
Note: It's a must to paint them individually only!
My attempt is here (for a screen of 1440x2560 px):
package com.example.ctelescu.opengl_pixel_draw;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class PixelDrawRenderer implements GLSurfaceView.Renderer {
private float[] mModelMatrix = new float[16];
private float[] mViewMatrix = new float[16];
private float[] mProjectionMatrix = new float[16];
private float[] mMVPMatrix = new float[16];
private final FloatBuffer mVerticesBuffer;
private int mMVPMatrixHandle;
private int mPositionHandle;
private int mColorHandle;
private final int mBytesPerFloat = 4;
private final int mStrideBytes = 7 * mBytesPerFloat;
private final int mPositionOffset = 0;
private final int mPositionDataSize = 3;
private final int mColorOffset = 3;
private final int mColorDataSize = 4;
public PixelDrawRenderer() {
// Define the vertices.
// final float[] vertices = {
// // X, Y, Z,
// // R, G, B, A
// -1f, 1f, 0.0f,
// 1.0f, 0.0f, 0.0f, 1.0f,
//
// -0.9f, 1.2f, 0.0f,
// 0.0f, 0.0f, 1.0f, 1.0f,
//
// -0.88f, 1.2f, 0.0f,
// 0.0f, 1.0f, 0.0f, 1.0f,
//
// -0.87f, 1.2f, 0.0f,
// 0.0f, 1.0f, 0.0f, 1.0f,
//
// -0.86f, 1.2f, 0.0f,
// 0.0f, 1.0f, 0.0f, 1.0f,
//
// -0.85f, 1.2f, 0.0f,
// 0.0f, 1.0f, 0.0f, 1.0f};
// Initialize the buffers.
mVerticesBuffer = ByteBuffer.allocateDirect(22579200 * mBytesPerFloat)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
// mVerticesBuffer.put(vertices);
}
#Override
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
// Set the background clear color to gray.
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
// Position the eye behind the origin.
final float eyeX = 0.0f;
final float eyeY = 0.0f;
final float eyeZ = 1.5f;
// We are looking toward the distance
final float lookX = 0.0f;
final float lookY = 0.0f;
final float lookZ = -5.0f;
// Set our up vector. This is where our head would be pointing were we holding the camera.
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
// Set the view matrix. This matrix can be said to represent the camera position.
// NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and
// view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose.
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
final String vertexShader =
"uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix.
+ "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
+ "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in.
+ "varying vec4 v_Color; \n" // This will be passed into the fragment shader.
+ "void main() \n" // The entry point for our vertex shader.
+ "{ \n"
+ " v_Color = a_Color; \n" // Pass the color through to the fragment shader.
// It will be interpolated across the vertex.
+ " gl_Position = u_MVPMatrix \n" // gl_Position is a special variable used to store the final position.
+ " * a_Position; \n" // Multiply the vertex by the matrix to get the final point in
+ " gl_PointSize = 0.1; \n"
+ "} \n"; // normalized screen coordinates.
final String fragmentShader =
"#ifdef GL_FRAGMENT_PRECISION_HIGH \n"
+ "precision highp float; \n"
+ "#else \n"
+ "precision mediump float; \n" // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
+ "#endif \n"
+ "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the
// vertex per fragment.
+ "void main() \n" // The entry point for our fragment shader.
+ "{ \n"
+ " gl_FragColor = v_Color; \n" // Pass the color directly through the pipeline.
+ "} \n";
// Load in the vertex shader.
int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
if (vertexShaderHandle != 0) {
// Pass in the shader source.
GLES20.glShaderSource(vertexShaderHandle, vertexShader);
// Compile the shader.
GLES20.glCompileShader(vertexShaderHandle);
// Get the compilation status.
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
// If the compilation failed, delete the shader.
if (compileStatus[0] == 0) {
GLES20.glDeleteShader(vertexShaderHandle);
vertexShaderHandle = 0;
}
}
if (vertexShaderHandle == 0) {
throw new RuntimeException("Error creating vertex shader.");
}
// Load in the fragment shader shader.
int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
if (fragmentShaderHandle != 0) {
// Pass in the shader source.
GLES20.glShaderSource(fragmentShaderHandle, fragmentShader);
// Compile the shader.
GLES20.glCompileShader(fragmentShaderHandle);
// Get the compilation status.
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
// If the compilation failed, delete the shader.
if (compileStatus[0] == 0) {
GLES20.glDeleteShader(fragmentShaderHandle);
fragmentShaderHandle = 0;
}
}
if (fragmentShaderHandle == 0) {
throw new RuntimeException("Error creating fragment shader.");
}
// Create a program object and store the handle to it.
int programHandle = GLES20.glCreateProgram();
if (programHandle != 0) {
// Bind the vertex shader to the program.
GLES20.glAttachShader(programHandle, vertexShaderHandle);
// Bind the fragment shader to the program.
GLES20.glAttachShader(programHandle, fragmentShaderHandle);
// Bind attributes
GLES20.glBindAttribLocation(programHandle, 0, "a_Position");
GLES20.glBindAttribLocation(programHandle, 1, "a_Color");
// Link the two shaders together into a program.
GLES20.glLinkProgram(programHandle);
// Get the link status.
final int[] linkStatus = new int[1];
GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
// If the link failed, delete the program.
if (linkStatus[0] == 0) {
GLES20.glDeleteProgram(programHandle);
programHandle = 0;
}
}
if (programHandle == 0) {
throw new RuntimeException("Error creating program.");
}
// Set program handles. These will later be used to pass in values to the program.
mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");
mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");
// Tell OpenGL to use this program when rendering.
GLES20.glUseProgram(programHandle);
}
#Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
// Set the OpenGL viewport to the same size as the surface.
GLES20.glViewport(0, 0, width, height);
// Create a new perspective projection matrix. The height will stay the same
// while the width will vary as per aspect ratio.
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 1.0f;
final float far = 10.0f;
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
float[] vertices = new float[22579200];
int counter = 0;
for (float i = -width / 2; i < width / 2; i++) {
for (float j = height / 2; j > -height / 2; j--) {
// Initialize the buffers.
vertices[counter++] = 2f * i * (1f / width); //X
vertices[counter++] = 2f * j * (1.5f / height); //Y
vertices[counter++] = 0; //Z
vertices[counter++] = 1f; //blue
vertices[counter++] = 1f; //green
vertices[counter++] = 0f; //blue
vertices[counter++] = 1f; //alpha
}
}
mVerticesBuffer.put(vertices);
mVerticesBuffer.clear();
}
#Override
public void onDrawFrame(GL10 glUnused) {
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
// Draw the vertices facing straight on.
Matrix.setIdentityM(mModelMatrix, 0);
drawVertices(mVerticesBuffer);
}
private void drawVertices(final FloatBuffer aVertexBuffer) {
// Pass in the position information
aVertexBuffer.position(mPositionOffset);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
mStrideBytes, aVertexBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Pass in the color information
aVertexBuffer.position(mColorOffset);
GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false,
mStrideBytes, aVertexBuffer);
GLES20.glEnableVertexAttribArray(mColorHandle);
// This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 3225600);
}
}

Ping-pong rendering between two FBOs fails after first frame.

I am trying to create two FBOs and implement a ping-pong render. But, I only get the first frame to work properly. I am trying to simulate a game-of-life and, after the first frame, I only get a black screen. Could you help me check it? I have spent hours on this issue.
Edit
Maybe I didn't describe clearly. Actually, I want to use the textureB as the texture and render it to textureA, then use the textureA to render to screen, then vice versa.
Edit
I can see the first frame, which is the textureB. After it go through the fragment shader, it become black. At first, I suspect the fragment shader, I change it to only revert the black to white and white to black. It still becomes all black.
Set up the fbo and texture
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &textureA);
glBindTexture(GL_TEXTURE_2D, textureA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA,
GL_UNSIGNED_BYTE, NULL);
glGenTextures(1, &textureB);
glBindTexture(GL_TEXTURE_2D, textureB);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
data=(GLubyte*)malloc(256*256*4*sizeof(GLubyte));
GLubyte val;
for (int i = 0; i < 256 * 256 * 4; i+=4) {
if (rand()%10 ==1)
{ val = 0; }
else
{ val = 255; }
data[i] = data[i+1] = data[i+2] = val;
data[i+3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenFramebuffers(1, &fboA);
glBindFramebuffer(GL_FRAMEBUFFER, fboA);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureA, 0);
glGenFramebuffers(1, &fboB);
glBindFramebuffer(GL_FRAMEBUFFER, fboB);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureB, 0);
Render Loop
if ([context API] == kEAGLRenderingAPIOpenGLES2) {
if(counter%2==0)
{
glUseProgram(automateProg);
glBindFramebuffer(GL_FRAMEBUFFER, fboA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureB);
glUniform1i(AUTOMATE_TEXT, 0);
glUniform1f(DU, 1.0/256);
glUniform1f(DV, 1.0/256);
// Update attribute values.
glVertexAttribPointer(ATTRIB_VERTEX_2, 2, GL_FLOAT, 0, 0, squareVertices);
glEnableVertexAttribArray(ATTRIB_VERTEX_2);
glVertexAttribPointer(ATTRIB_TEXCOORD_2, 2, GL_FLOAT, GL_FALSE, 0, texCoord);
//glEnableVertexAttribArray(ATTRIB_TEXCOORD_2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (![self validateProgram:automateProg]) {
NSLog(#"Failed to validate program: %d", automateProg);
return;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(0);
}
else
{
glUseProgram(automateProg);
glBindFramebuffer(GL_FRAMEBUFFER, fboB);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureA);
glUniform1i(AUTOMATE_TEXT, 0);
glUniform1f(DU, 1.0/256);
glUniform1f(DV, 1.0/256);
// Update attribute values.
glVertexAttribPointer(ATTRIB_VERTEX_2, 2, GL_FLOAT, 0, 0, squareVertices);
glEnableVertexAttribArray(ATTRIB_VERTEX_2);
glVertexAttribPointer(ATTRIB_TEXCOORD_2, 2, GL_FLOAT, GL_FALSE, 0, texCoord);
//glEnableVertexAttribArray(ATTRIB_TEXCOORD_2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (![self validateProgram:automateProg]) {
NSLog(#"Failed to validate program: %d", automateProg);
return;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(0);
}
[(EAGLView *)self.view setFramebuffer];
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (counter % 2 == 0) {
glUseProgram(normalProg);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureB);
glUniform1i(NORMAL_TEXT, 0);
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoord);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (![self validateProgram:normalProg]) {
NSLog(#"Failed to validate program: %d", normalProg);
return;
}
glUseProgram(0);
} else {
glUseProgram(normalProg);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureA);
glUniform1i(NORMAL_TEXT, 0);
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoord);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (![self validateProgram:normalProg]) {
NSLog(#"Failed to validate program: %d", normalProg);
return;
}
glUseProgram(0);
}
counter++;
[(EAGLView *)self.view presentFramebuffer];
Fragment Shader
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D tex; //the input texture
uniform float du; //the width of the cells
uniform float dv; //the height of the cells
void main() {
int count = 0;
vec4 C = texture2D( tex, v_texCoord );
vec4 E = texture2D( tex, vec2(v_texCoord.x + du, v_texCoord.y) );
vec4 N = texture2D( tex, vec2(v_texCoord.x, v_texCoord.y + dv) );
vec4 W = texture2D( tex, vec2(v_texCoord.x - du, v_texCoord.y) );
vec4 S = texture2D( tex, vec2(v_texCoord.x, v_texCoord.y - dv) );
vec4 NE = texture2D( tex, vec2(v_texCoord.x + du, v_texCoord.y + dv) );
vec4 NW = texture2D( tex, vec2(v_texCoord.x - du, v_texCoord.y + dv) );
vec4 SE = texture2D( tex, vec2(v_texCoord.x + du, v_texCoord.y - dv) );
vec4 SW = texture2D( tex, vec2(v_texCoord.x - du, v_texCoord.y - dv) );
if (E.r == 1.0) { count++; }
if (N.r == 1.0) { count++; }
if (W.r == 1.0) { count++; }
if (S.r == 1.0) { count++; }
if (NE.r == 1.0) { count++; }
if (NW.r == 1.0) { count++; }
if (SE.r == 1.0) { count++; }
if (SW.r == 1.0) { count++; }
if ( (count == 2 || count == 3)) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); //cell lives...
} else {
gl_FragColor = vec4(0.0,0.0,0.0, 1.0); //cell dies...
}
}
Do I understand your code right, that you want to render a result to a texture in the first if-else-block and render that result to screen in the second if-else-block?
If so, then it looks like you have a mistake in how you organize your input and output to begin with.
This is what happens in your first pass (I reduced your code):
if(counter%2==0)
{
glBindFramebuffer(GL_FRAMEBUFFER, fboA); // will render to textureA
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureB); // textureB is our input
} else {
...
}
if (counter % 2 == 0) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureB); // textureB still as input? not textureA?
} else {
...
}
...and this is what happens in the second pass:
if(counter%2==0)
{
...
} else {
glBindFramebuffer(GL_FRAMEBUFFER, fboB); // will render to textureB
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureA); // textureA as input
}
if (counter % 2 == 0) {
...
} else {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureA); // textureA as input again?
}
The reason why you see something in the first frame is, because you actually render your input data, but not the result of your first pass. And the reason why you have black screen in your second pass may be that your fragment shader does not work correctly. Judging from your shader code, a mistake in accessing the neighbor texels seems to be the most plausible cause for that. Can you provide the values of duand dv?
Also I don't think that using only one texture unit should make any trouble, as Brad pointed out earlier. I'm not sure about that though.
On a side note: for ping-ponging you should consider creating your FBOs as an array to make your code a lot more readable.
EDIT:
I you have problems setting your uniforms du and dv with glUniform1f(), try glUniform1i() (you need to cast with float() in your shader then) or glUniform1fv() instead. I once had the same problem with the PowerVR GLES2 drivers, where this function didn't do anything and caused the uniform to be 0.0.
You have two textures that you'd like to deal with, yet I see only one texture unit being used here. Perhaps if you bound your FBO texture to texture unit one using code like the following:
glBindFramebuffer(GL_FRAMEBUFFER, fboA);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureB);
or
glBindFramebuffer(GL_FRAMEBUFFER, fboB);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureB);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureA);
before you render each frame, it would properly read from the one texture bound to unit 0 and output via the FBO to the other texture on unit 1.
As an alternative, you could permanently bind one texture to one unit and the other to the other unit, and alternate values for your AUTOMATE_TEXT uniform to indicate which unit to pull from. This would be a little more efficient, because it would avoid the overhead of binding the textures on every render.
If a color plane of a frame has to be accessed, the a texture has to be attached to the frame buffer, which is written to. If a texture, which is attached to a frame buffer, has to be read in a shader, then the textue has to be bound to a textur unit and the index of the textue unit has to be set toa texture sampler uniform of the shader.
Since you can't read from a frame buffer and write to the same frame buffer at once (this would cause undefined behavior) you have to draw to read from one frame buffer and to write to a second frame buffer.
After a each frame the frame buffers have to change their place. The buffer which was read from will become the buffer which will be written to and the buffer which was written to will become the buffer which will be read from.
Create the textures for the frame buffer attachments:
GLuint colorTexture[2];
glGenTextures( 2, &colorTexture[0] );
glBindTexture( GL_TEXTURE_2D, colorTexture[0] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
glBindTexture( GL_TEXTURE_2D, colorTexture[1] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
Create the frame buffers:
GLuint frameBuffer[2];
glGenFramebuffers( 2, &frameBuffer[0] );
glBindFramebuffer( GL_FRAMEBUFFER, frameBuffer[0] );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture[0], 0 );
glBindFramebuffer( GL_FRAMEBUFFER, frameBuffer[1] );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture[1], 0 );
Note, if a depth buffer or even a stencil buffer is required, then a GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT or GL_DEPTH_STENCIL_ATTACHMENT has to be attached to the frame buffer.
Since every frame is drawn to a frame buffer you have to implement a post process, which brings the color plane from the frame buffer to the drawing buffer. This can be done by glBlitFramebuffer, which transfer a rectangle of pixel values from one region of a read framebuffer to another region of a draw framebuffer.
glBindFramebuffer( GL_READ_FRAMEBUFFER, frameBuffer[ ... ] );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
glBlitFramebuffer( 0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST );
Your render main loop should look somehow like this:
int drawFB = 0;
while ( /* ... */ )
{
int readFB = 1 - drawFB;
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer[drawFB]);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, colorTexture[readFB]);
glProgramUse( /* shader program object */ );
glUniform1i( /* texture sampler 2D location */, 1 );
// do the drawing
// ...
// post processing
glBindFramebuffer( GL_READ_FRAMEBUFFER, frameBuffer[drawFB] );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
glBlitFramebuffer( 0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST );
drawFB = 1 - drawFB;
}
As an alternative, you can also use 1 frame buffer with 2 color planes and 2 textures attached. Activate alternately the first or the second color plane:
GLuint frameBuffer;
glGenFramebuffers( 1, &frameBuffer );
glBindFramebuffer( GL_FRAMEBUFFER, frameBuffer );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture[0], 0 );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, colorTexture[1], 0 );
int drawFB = 0;
while ( /* ... */ )
{
int readFB = 1 - drawFB;
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glDrawBuffer( drawFB == 0 ? GL_COLOR_ATTACHMENT0 : GL_COLOR_ATTACHMENT1 );
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, colorTexture[readFB]);
glProgramUse( /* shader program object */ );
glUniform1i( /* texture sampler 2D location */, 1 );
// do the drawing
// ...
// post processing
glBindFramebuffer( GL_READ_FRAMEBUFFER, frameBuffer[drawFB] );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
glBlitFramebuffer( 0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST );
drawFB = 1 - drawFB;
}
See following simple WebGL example for demonstration of the process:
var ShaderProgram = {};
ShaderProgram.Create = function( shaderList, uniformNames ) {
var shaderObjs = [];
for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {
var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage );
if ( shderObj == 0 )
return 0;
shaderObjs.push( shderObj );
}
var progObj = this.LinkProgram( shaderObjs )
if ( progObj != 0 ) {
progObj.unifomLocation = {};
for ( var i_n = 0; i_n < uniformNames.length; ++ i_n ) {
var name = uniformNames[i_n];
progObj.unifomLocation[name] = gl.getUniformLocation( progObj, name );
}
}
return progObj;
}
ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); }
ShaderProgram.SetUniformInt = function( progObj, name, val ) { gl.uniform1i( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniform2i = function( progObj, name, arr ) { gl.uniform2iv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformFloat = function( progObj, name, val ) { gl.uniform1f( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniform2f = function( progObj, name, arr ) { gl.uniform2fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniform3f = function( progObj, name, arr ) { gl.uniform3fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformMat44 = function( progObj, name, mat ) { gl.uniformMatrix4fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.CompileShader = function( source, shaderStage ) {
var shaderScript = document.getElementById(source);
if (shaderScript) {
source = "";
var node = shaderScript.firstChild;
while (node) {
if (node.nodeType == 3) source += node.textContent;
node = node.nextSibling;
}
}
var shaderObj = gl.createShader( shaderStage );
gl.shaderSource( shaderObj, source );
gl.compileShader( shaderObj );
var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS );
if ( !status ) alert(gl.getShaderInfoLog(shaderObj));
return status ? shaderObj : 0;
}
ShaderProgram.LinkProgram = function( shaderObjs ) {
var prog = gl.createProgram();
for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh )
gl.attachShader( prog, shaderObjs[i_sh] );
gl.linkProgram( prog );
status = gl.getProgramParameter( prog, gl.LINK_STATUS );
if ( !status ) alert("Could not initialise shaders");
gl.useProgram( null );
return status ? prog : 0;
}
var FrameBuffer = {};
FrameBuffer.Create = function( vp, texturePlan ) {
var texPlan = texturePlan ? new Uint8Array( texturePlan ) : null;
var fb = gl.createFramebuffer();
fb.width = vp[0];
fb.height = vp[1];
gl.bindFramebuffer( gl.FRAMEBUFFER, fb );
fb.color0_texture = gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, fb.color0_texture );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, fb.width, fb.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, texPlan );
fb.renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer( gl.RENDERBUFFER, fb.renderbuffer );
gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, fb.width, fb.height );
gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fb.color0_texture, 0 );
gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fb.renderbuffer );
gl.bindTexture( gl.TEXTURE_2D, null );
gl.bindRenderbuffer( gl.RENDERBUFFER, null );
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
fb.Bind = function( clear ) {
gl.bindFramebuffer( gl.FRAMEBUFFER, this );
if ( clear ) {
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
//gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
gl.clear( gl.DEPTH_BUFFER_BIT );
}
};
fb.Release = function( clear ) {
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
if ( clear ) {
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
//gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
gl.clear( gl.DEPTH_BUFFER_BIT );
}
};
fb.BindTexture = function( textureUnit ) {
gl.activeTexture( gl.TEXTURE0 + textureUnit );
gl.bindTexture( gl.TEXTURE_2D, this.color0_texture );
};
return fb;
}
var curBufInx = 0;
var tick = 0;
var signal = 0;
function drawScene(){
var canvas = document.getElementById( "glow-canvas" );
var vp = [canvas.width, canvas.height];
var currentTime = Date.now();
var deltaMS = currentTime - startTime
testTick = Tick( currentTime, 0.05 )
signal = testTick > tick ? 1 : 0;
tick = testTick
var srcBufInx = curBufInx == 0 ? 1 : 0;
gl.viewport( 0, 0, drawFB[curBufInx].width, drawFB[curBufInx].height );
gl.enable( gl.DEPTH_TEST );
drawFB[curBufInx].Bind( true );
// set up draw shader
ShaderProgram.Use( progDraw );
var texUnitSource = 2;
drawFB[srcBufInx].BindTexture( texUnitSource );
ShaderProgram.SetUniformInt( progDraw, "u_colorAttachment0", texUnitSource );
ShaderProgram.SetUniform2i( progDraw, "u_textureSize", [drawFB[curBufInx].width, drawFB[curBufInx].height] );
ShaderProgram.SetUniformInt( progDraw, "u_signal", signal );
gl.enableVertexAttribArray( progDraw.inPos );
gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
gl.vertexAttribPointer( progDraw.inPos, 2, gl.FLOAT, false, 0, 0 );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
gl.drawElements( gl.TRIANGLES, bufQuad.inxLen, gl.UNSIGNED_SHORT, 0 );
gl.disableVertexAttribArray( progDraw.inPos );
drawFB[curBufInx].Release( true );
gl.viewport( 0, 0, canvas.width, canvas.height );
var texUnitDraw = 2;
drawFB[curBufInx].BindTexture( texUnitDraw );
ShaderProgram.Use( progScreenSpace );
ShaderProgram.SetUniformInt( progScreenSpace, "u_colorAttachment0", texUnitDraw );
gl.enableVertexAttribArray( progScreenSpace.inPos );
gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
gl.vertexAttribPointer( progScreenSpace.inPos, 2, gl.FLOAT, false, 0, 0 );
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
gl.drawElements( gl.TRIANGLES, bufQuad.inxLen, gl.UNSIGNED_SHORT, 0 );
gl.disableVertexAttribArray( progScreenSpace.inPos );
curBufInx = curBufInx == 0 ? 1 : 0;
}
function Tick( currentTime, intervall ) {
return Math.trunc( (currentTime - startTime) / intervall );
}
var plot_download_request = false;
var drawFB;
var sliderScale = 100.0
var gl;
var progDraw;
var progScreenSpace;
var bufCube = {};
var bufQuad = {};
function sceneStart() {
var canvas = document.getElementById( "glow-canvas");
var vp = [canvas.width, canvas.height];
gl = canvas.getContext( "experimental-webgl" );
if ( !gl )
return;
progDraw = ShaderProgram.Create(
[ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
],
[ "u_colorAttachment0", "u_textureSize", "u_signal" ] );
progDraw.inPos = gl.getAttribLocation( progDraw, "inPos" );
if ( progDraw == 0 )
return;
progScreenSpace = ShaderProgram.Create(
[ { source : "screen-shader-vs", stage : gl.VERTEX_SHADER },
{ source : "screen-shader-fs", stage : gl.FRAGMENT_SHADER }
],
[ "u_colorAttachment0" ] );
progScreenSpace.inPos = gl.getAttribLocation( progDraw, "inPos" );
if ( progDraw == 0 )
return;
// create frame buffers
var texCX = Math.floor(vp[0] / 4);
var texCY = Math.floor(vp[1] / 4);
var texPlan = [];
for (ix = 0; ix < texCX; ++ix) {
for (iy = 0; iy < texCY; ++iy) {
texPlan.push( 0, 0, 0, 0 );
}
}
for (ip = 0; ip < texCX * texCY / 20; ++ip) {
var inx_tex = Math.floor( Math.random() * texCY ) * texCX + Math.floor( Math.random() * texCX );
texPlan[inx_tex * 4 + 0] = 255 * Math.random();
texPlan[inx_tex * 4 + 1] = 255 * Math.random();
texPlan[inx_tex * 4 + 2] = 127;
texPlan[inx_tex * 4 + 3] = 255;
}
drawFB = [ FrameBuffer.Create( [texCX, texCY], texPlan ), FrameBuffer.Create( [texCX, texCY], texPlan ) ];
bufQuad.pos = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ] ), gl.STATIC_DRAW );
bufQuad.inx = gl.createBuffer();
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ), gl.STATIC_DRAW );
bufQuad.inxLen = 6;
startTime = Date.now();
setInterval(drawScene, 50);
}
<script id="draw-shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec2 inPos;
varying vec2 vertPos;
void main()
{
vertPos.xy = inPos.xy;
gl_Position = vec4( inPos, 0.0, 1.0 );
}
</script>
<script id="draw-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vertPos;
uniform sampler2D u_colorAttachment0;
uniform ivec2 u_textureSize;
uniform int u_signal;
vec3 Merge( in vec2 texC, in vec2 dir )
{
vec2 testC = texC + dir;
vec2 rangeTest = step( vec2(0.0), testC ) * step( testC, vec2(1.0) );
vec3 texCol = texture2D( u_colorAttachment0, testC ).rgb;
vec2 tempDir = texCol.xy * 2.0 - 1.0;
vec2 pDir = tempDir;
pDir.x *= step( abs(tempDir.y * 0.7), abs( tempDir.x ) );
pDir.y *= step( abs(tempDir.x * 0.7), abs( tempDir.y ) );
pDir = sign( pDir );
vec2 tDir = sign( dir );
//vec2 dirTestTemp = step( vec2(0.5), -tDir * pDir );
//float dirTest = dirTestTemp.x * dirTestTemp.y;
vec2 dirTestTemp = tDir + pDir;
float dirTest = 1.0 - step( 0.5, abs( dirTestTemp.x ) + abs( dirTestTemp.y ) );
return rangeTest.x * rangeTest.y * dirTest * texCol;
}
void main()
{
ivec2 texSize = u_textureSize;
vec2 texStep = vec2( 1.0 / float( texSize.x ), 1.0 / float( texSize.y ) );
vec2 texC = vertPos.st * 0.5 + 0.5;
vec3 texCol = vec3(0.0);
if ( u_signal == 0 )
{
texCol = texture2D( u_colorAttachment0, texC ).rgb;
}
else
{
texCol += Merge( texC, -texStep );
texCol += Merge( texC, vec2( -texStep.x, 0.0 ) );
texCol += Merge( texC, vec2( -texStep.x, texStep.y ) );
texCol += Merge( texC, vec2( 0.0, -texStep.y ) );
texCol += Merge( texC, vec2( 0.0, texStep.y ) );
texCol += Merge( texC, vec2( texStep.x, -texStep.y ) );
texCol += Merge( texC, vec2( texStep.x, 0.0 ) );
texCol += Merge( texC, texStep );
}
if ( texCol.b > 0.0 )
{
vec2 colDir = texCol.rg * 2.0 - 1.0;
vec2 pDir = sign( colDir );
vec2 nextTexC = texC + pDir * texStep;
if ( nextTexC.x <= texStep.x/2.0 || nextTexC.x >= 1.0-texStep.x/2.0 )
colDir.x = -colDir.x;
if ( nextTexC.y <= texStep.y/2.0 || nextTexC.y >= 1.0-texStep.y/2.0 )
colDir.y *= -1.0;
texCol.rg = colDir * 0.5 + 0.5;
}
vec3 col = texCol.rgb;
gl_FragColor = vec4( col, 1.0 );
}
</script>
<script id="screen-shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec2 inPos;
varying vec2 vertPos;
void main()
{
vertPos.xy = inPos.xy;
gl_Position = vec4( inPos, 0.0, 1.0 );
}
</script>
<script id="screen-shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vertPos;
uniform sampler2D u_colorAttachment0;
void main()
{
vec4 texCol = texture2D( u_colorAttachment0, vertPos.st * 0.5 + 0.5 );
gl_FragColor = vec4( texCol.rgb, 1.0 );
}
</script>
<body onload="sceneStart();">
<canvas id="glow-canvas" style="border: none;" width="256" height="256"></canvas>
</body>

CG Shader Semantics with OpenGL 3.x?

I used to have CG shaders working with vertex arrays in OpenGL 2.x, but I've updated to use VBOs and VAOs in OpenGL 3.x and now the semantics don't seem to be working, except for POSITION. CG doesn't throw up any compile errors, but if I set my output color in my fragment shader to my input normal value, I just get solid black. There's another answer that links to a page saying to use cgGLEnableClientState (which did nothing by itself) and cgGLSetParameterPointer (which seems crazy since I'm already sending the data to OpenGL, why send another copy through CG). So what am I missing?
Vertex Shader:
struct input
{
in uniform float4x4 worldViewProjMatrix;
in uniform float4x4 invTransWorldMatrix;
in uniform float4x4 worldMatrix;
in uniform float3 lightDir;
in uniform float3 eyePosition;
in varying float4 position : POSITION;
in varying float4 normal : NORMAL;
in varying float2 texCoord : TEXCOORD;
};
struct output
{
out varying float4 position : POSITION;
out varying float2 texCoord : TEXCOORD0;
out varying float3 light : TEXCOORD1;
out varying float3 normal : TEXCOORD2;
out varying float3 view : TEXCOORD3;
};
output main(input IN)
{
output OUT = output(0);
OUT.position = mul(IN.worldViewProjMatrix, IN.position);
OUT.texCoord = IN.texCoord;
OUT.light = IN.lightDir;
float3 worldPosition = normalize(mul(IN.worldMatrix, IN.position)).xyz;
OUT.view = IN.eyePosition - worldPosition;
OUT.normal = normalize(mul(IN.invTransWorldMatrix, IN.normal)).xyz;
return OUT;
}
Fragment Shader:
struct input {
in varying float2 texCoord : TEXCOORD0;
in varying float3 light : TEXCOORD1;
in varying float3 normal : TEXCOORD2;
in varying float3 view : TEXCOORD3;
in uniform float3 diffuse;
in uniform float3 ambient;
in uniform float3 specular;
in uniform float shininess;
in uniform sampler2D colorMapSampler;
};
float4 main(input IN) : COLOR
{
float4 color = tex2D(IN.colorMapSampler, IN.texCoord);
float3 normal = normalize(IN.normal);
float3 lightDir = normalize(IN.light);
float3 viewDir = normalize(IN.view);
float3 diff = saturate(dot(normal, lightDir));
float3 reflect = normalize(2 * diff * normal - lightDir);
float3 specular = pow(saturate(dot(reflect, viewDir)), IN.shininess);
float4 result;
//result = float4(color.rgb * (IN.ambient + IN.diffuse * diff) + IN.specular * specular, 1.0f);
result = float4(IN.normal, 1.0f);
return result;
}
I found someplace that listed these as the indices for glVertexAttribPointer, but they could easily be wrong (these are the Shader::POSITION, Shader::NORMAL, etc in the VBO setup function):
enum GenericVertexInputIndices
{
POSITION = 0,
BLENDWEIGHT = 1,
NORMAL = 2,
DIFFUSE = 3, COLOR0 = 3,
SPECULAR = 4, COLOR1 = 4,
TESSFACTOR = 5, FOGCOORD = 5,
PSIZE = 6,
BLENDINDICES = 7,
TEXCOORD0 = 8,
TEXCOORD1 = 9,
TEXCOORD2 = 10,
TEXCOORD3 = 11,
TEXCOORD4 = 12,
TEXCOORD5 = 13,
TEXCOORD6 = 14, TANGENT = 14,
TEXCOORD7 = 15, BINORMAL = 15,
};
VBO setup function below:
void MeshObject::initVBO(const unsigned int&_indexVBO, unsigned int& _indexOffset)
{
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
//sub in this section of the index data
m_indexOffset = _indexOffset;
_indexOffset = _indexOffset + m_indices.size();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexVBO);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, m_indexOffset * sizeof(unsigned short), m_indices.size() * sizeof(unsigned short), &(m_indices[0]));
//init vertex data
glGenBuffers(1, &m_vertexVBO);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexVBO);
{
glBufferData(GL_ARRAY_BUFFER, m_data.size() * sizeof(VertexData), &(m_data[0]), GL_STATIC_DRAW);
glEnableVertexAttribArray(Shader::POSITION);
glVertexAttribPointer(Shader::POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char*)0);
glEnableVertexAttribArray(Shader::NORMAL);
glVertexAttribPointer(Shader::NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char*)12);
glEnableVertexAttribArray(Shader::TEXCOORD0);
glVertexAttribPointer(Shader::TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char*)24);
}
}
Shader bind function below:
void Shader::bind(const matrix4 &_worldTransform, const Material::MaterialInfo &_info)
{
CGerror error;
//bind to the shader
CGprofile profile = renderGlobals.shaderMgr.getProfile(static_cast<Shader::ShaderType>(m_shaderType));
cgGLEnableProfile(profile);
error = cgGetError();
cgGLBindProgram(m_program);
error = cgGetError();
switch (m_shaderType)
{
case VERTEX:
{
//get vertex parameters
CGparameter worldMatrix = cgGetNamedParameter(m_program, "IN.worldMatrix");
CGparameter worldViewProjMatrix = cgGetNamedParameter(m_program, "IN.worldViewProjMatrix");
CGparameter invTransWorldMatrix = cgGetNamedParameter(m_program, "IN.invTransWorldMatrix");
CGparameter light = cgGetNamedParameter(m_program, "IN.lightDir");
CGparameter eyePosition = cgGetNamedParameter(m_program, "IN.eyePosition");
error = cgGetError();
//set vertex parameters
matrix4 worldViewProj = *(renderGlobals.debugCamera.getViewProjectionMatrix()) * _worldTransform;
cgGLSetMatrixParameterfc(worldViewProjMatrix, worldViewProj.m16);
matrix4 invTransWorld = _worldTransform.getInverse().getTranspose();
if (invTransWorldMatrix != NULL)
{
cgGLSetMatrixParameterfc(invTransWorldMatrix, invTransWorld.m16);
}
if (worldMatrix != NULL)
{
cgGLSetMatrixParameterfc(worldMatrix, _worldTransform.m16);
}
vector3 lightPos = *renderGlobals.debugCamera.getPosition();
//vector3 lightPos = vector3(0.0f, 0.0f, 0.0f);
vector3 lightDir = lightPos - _worldTransform.wAxis;
if (light != NULL)
{
cgGLSetParameter3fv(light, lightDir.v);
}
if (eyePosition != NULL)
{
cgGLSetParameter3fv(eyePosition, renderGlobals.debugCamera.getPosition()->v);
}
error = cgGetError();
break;
}
case FRAGMENT:
{
//set up material info
CGparameter diffuse = cgGetNamedParameter(m_program, "IN.diffuse");
CGparameter ambient = cgGetNamedParameter(m_program, "IN.ambient");
CGparameter specular = cgGetNamedParameter(m_program, "IN.specular");
CGparameter shininess = cgGetNamedParameter(m_program, "IN.shininess");
if (diffuse != NULL)
{
cgGLSetParameter3fv(diffuse, _info.diffuse.rgb);
}
if (ambient != NULL)
{
cgGLSetParameter3fv(ambient, _info.ambient.rgb);
}
if (specular != NULL)
{
cgGLSetParameter3fv(specular, _info.specular.rgb);
}
if (shininess != NULL)
{
cgGLSetParameter1f(shininess, _info.shininess);
}
//set up textures
CGparameter colorMapSampler = cgGetNamedParameter(m_program, "IN.colorMapSampler");
if (colorMapSampler != NULL)
{
if (_info.textureInfo[0].size() > 0)
{
Index<Texture> texture = _info.textureInfo[0][0].texture;
cgGLSetTextureParameter(colorMapSampler, texture->getID());
cgGLEnableTextureParameter(colorMapSampler);
} else {
cgGLDisableTextureParameter(colorMapSampler);
}
}
break;
}
default:
{
//ERROR: tryin to bind a shader with an unknown type
assert(0);
unbind();
return;
}
}
}
Changed the semantics in the vertex input structure to use ATTR* matching what I have in the GenericVertexInputIndices and voila, it works. I had tried changing all my semantics to ATTR* in both the vertex and fragment shader before and gotten a bunch of domain conflict errors, but didn't notice that it didn't complain about the ones in the vertex input structure. Apparently they're only for vertex input. Another small detail that totally screws everything up.

Why am I getting a redefinition error?

I'm following the tutorial here: http://iphone-3d-programming.labs.oreilly.com/ch01.html#ch01_id36002837
When I try to run the program, I get an error saying "Redefinition of 'void RenderingEngine1::OnRotate(DeviceOrientation)"
Here's the code. The function is at the end of it:
#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#include "IRenderingEngine.hpp"
class RenderingEngine1 : public IRenderingEngine {
public:
RenderingEngine1();
void Initialize(int width, int height);
void Render() const;
void UpdateAnimation(float timeStep) {}
void OnRotate(DeviceOrientation orientation) {}
private:
float m_currentAngle;
GLuint m_framebuffer;
GLuint m_renderbuffer;
};
IRenderingEngine* CreateRenderer1()
{
return new RenderingEngine1();
}
struct Vertex {
float Position[2];
float Color[4];
};
// Define the positions and colors of two triangles.
const Vertex Vertices[] = {
{{-0.5, -0.866}, {1, 1, 0.5f, 1}},
{{0.5, -0.866}, {1, 1, 0.5f, 1}},
{{0, 1}, {1, 1, 0.5f, 1}},
{{-0.5, -0.866}, {0.5f, 0.5f, 0.5f}},
{{0.5, -0.866}, {0.5f, 0.5f, 0.5f}},
{{0, -0.4f}, {0.5f, 0.5f, 0.5f}},
};
RenderingEngine1::RenderingEngine1()
{
glGenRenderbuffersOES(1, &m_renderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_renderbuffer);
}
void RenderingEngine1::Initialize(int width, int height)
{
// Create the framebuffer object and attach the color buffer.
glGenFramebuffersOES(1, &m_framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_framebuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
GL_COLOR_ATTACHMENT0_OES,
GL_RENDERBUFFER_OES,
m_renderbuffer);
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
// Initialize the projection matrix.
const float maxX = 2;
const float maxY = 3;
glOrthof(-maxX, +maxX, -maxY, +maxY, -1, 1);
glMatrixMode(GL_MODELVIEW);
}
void RenderingEngine1::Render() const
{
glClearColor(0.5f, 0.5f, 0.5f, 1);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(m_currentAngle, 0, 0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &Vertices[0].Position[0]);
glColorPointer(4, GL_FLOAT, sizeof(Vertex), &Vertices[0].Color[0]);
GLsizei vertexCount = sizeof(Vertices) / sizeof(Vertex);
glDrawArrays(GL_TRIANGLES, 0, vertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glPopMatrix();
}
void RenderingEngine1::OnRotate(DeviceOrientation orientation)
{
float angle = 0;
switch (orientation) {
case DeviceOrientationLandscapeLeft:
angle = 270;
break;
case DeviceOrientationPortraitUpsideDown:
angle = 180;
break;
case DeviceOrientationLandscapeRight:
angle = 90;
break;
}
m_currentAngle = angle;
}
remove the body
class RenderingEngine1 : public IRenderingEngine {
public:
...
void OnRotate(DeviceOrientation orientation) {}
...
-> void OnRotate(DeviceOrientation orientation);