I'm making game in Android OpenGL 2.0. And I need to refresh UVs and Vertices buffers every frame. I draw on Surface with this code:
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTexture);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glEnableVertexAttribArray ( mTexCoordLoc );
GLES20.glVertexAttribPointer(mPositionHandle, 3,
GLES20.GL_FLOAT, false,
0, vertexBuffer);
GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT,
false,
0, uvBuffer);
GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, matrix, 0);
GLES20.glUniform1i ( mSamplerLoc, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, mIndices.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);
Refresh buffers with:
private void updateVerticesBuffer()
{
ByteBuffer bb = ByteBuffer.allocateDirect(mVertices.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(mVertices);
vertexBuffer.position(0);
}
private void updateUvsBuffer()
{
ByteBuffer bb = ByteBuffer.allocateDirect(mUvs.length * 4);
bb.order(ByteOrder.nativeOrder());
uvBuffer = bb.asFloatBuffer();
uvBuffer.put(mUvs);
uvBuffer.position(0);
}
And use this shaders:
/* SHADER Solid
*
* This shader is for rendering a colored primitive.
*
*/
public static final String vs_SolidColor =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
public static final String fs_SolidColor =
"precision mediump float;" +
"void main() {" +
" gl_FragColor = vec4(0.5,0,0,1);" +
"}";
/* SHADER Image
*
* This shader is for rendering 2D images straight from a texture
* No additional effects.
*
*/
public static final String vs_Image =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 a_texCoord;" +
"varying vec2 v_texCoord;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
" v_texCoord = a_texCoord;" +
"}";
public static final String fs_Image =
"precision mediump float;" +
"varying vec2 v_texCoord;" +
"uniform sampler2D s_texture;" +
"void main() {" +
" gl_FragColor = texture2D( s_texture, v_texCoord );" +
"}";
Is possible to refresh buffers faster? Is VBOs faster than this?
How can I use VBOs in this code? I searched internet but I didn't find any good tutorial. I need to transform this code to use VBOs.
Related
Hi I am developing an OpenGLES based android application, and I need rotate the texture on z-axis on real time. But the image skewed while I add a rotation to the model matrix.
The first image below is the original one, and the second one is the skewed image after rotation on z-axis.
Here are my shaders:
private final String mVertexShader = "" +
"attribute vec4 position;\n" +
"attribute vec2 textureCoordinate;\n" +
"varying vec2 textureCoordinateVarying;\n" +
"uniform mat4 modelMat;\n" +
"uniform mat4 viewMat;\n" +
"uniform mat4 projectionMat;\n" +
"" +
"void main() {\n" +
" gl_Position = projectionMat * viewMat * modelMat*position ;\n" +
" textureCoordinateVarying = textureCoordinate;\n" +
"}";
private final String mFragmentShader = "precision highp float;\n" +
"uniform sampler2D textureBackground;\n" +
"uniform sampler2D textureNumbers;" +
"varying highp vec2 textureCoordinateVarying;\n" +
"void main() {\n" +
" vec4 background = texture2D(textureBackground, textureCoordinateVarying);" +
" vec4 foreground = texture2D(textureNumbers, textureCoordinateVarying);" +
" gl_FragColor = mix(background, foreground, 0.2);\n" +
"}\n";
And with respect to projection, view and model matrix, here is their init function:
Matrix.setIdentityM(model, 0);
Matrix.setIdentityM(rotation, 0);
Matrix.setIdentityM(view, 0);
Matrix.setIdentityM(projection, 0);
Matrix.translateM(view, 0,0,0,-3.0f);
Matrix.perspectiveM(projection,0,45,(float)mBackground.getHeight()/(float)mBackground.getWidth(), 0.1f, 100f);
And in onDraw function, I will update the value of the model matrix;
public void onDrawFrame(GL10 gl) {
//some function
//update model matrix, and rotation is just a 4*4 identity matrix, and the degree is the z-axis rotation degree.
Matrix.setRotateM(rotation, 0, degree, 0, 0, 1);
Matrix.multiplyMM(model, 0, rotation, 0, model, 0);
Matrix.setIdentityM(rotation,0);
//draw my texture
}
I am pretty desperate now, any help will be highly appreciated.
It seems I have to kill this question on my own, actually I just made a stupid mistake, the ratio of projection matrix should be the width of surface view divided by the height of the same surface view, which should not be the ratio of your texture image width/height.
I'm trying to implement lookup texture to my live camera preview.Everything looks fine except shine and shadows. The shine appears blueish and shadow sometimes has red spot.
I'm using Grafika's Camera Capture. I have referred GpuImage's Shader. I was able to load second texture (lookup texture) using following load texture function,
public int createTextureObjectN() {
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
GlUtil.checkGlError("glGenTextures");
int texId = textures[0];
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
GlUtil.checkGlError("glBindTexture " + texId);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GlUtil.checkGlError("glTexParameter");
return texId;
}
public int loadTexture(final int resourceId) {
final int texId = createTextureObjectN();
if (texId != 0) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Decode
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeResource(MyApplication.getAppContext().getResources(), resourceId, options);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
return texId;
}
my vertex shader is
private static final String VERTEX_SHADER =
"uniform mat4 uMVPMatrix;\n" +
"uniform mat4 uTexMatrix;\n" +
"attribute vec4 aPosition;\n" +
"attribute vec4 aTextureCoord;\n" +
"varying vec2 vTextureCoord;\n" +
"void main() {\n" +
" gl_Position = uMVPMatrix * aPosition;\n" +
" vTextureCoord = (uTexMatrix * aTextureCoord).xy;\n" +
"}\n";
and fragment shader is
shown below.
The stexture2 is a lookup and stexture is camera preview frame of dimension 1920x1080
And vTextureCoord is cordinates of camera frames
#extension GL_OES_EGL_image_external : require
uniform samplerExternalOES sTexture;
uniform sampler2D sTexture2;
varying vec2 vTextureCoord;
//uniform vec3 iResolution;
//uniform float iGlobalTime;
//highp float aspectRatio = iResolution[1] / iResolution[0];
lowp float intensity = 1.0;
void main()
{
highp vec4 textureColor = texture2D(sTexture, vTextureCoord);
highp float blueColor = textureColor.b * 63.0;
highp vec2 quad1;
quad1.y = floor(floor(blueColor) / 8.0);
quad1.x = floor(blueColor) - (quad1.y * 8.0);
highp vec2 quad2;
quad2.y = floor(ceil(blueColor) / 8.0);
quad2.x = ceil(blueColor) - (quad2.y * 8.0);
highp vec2 texPos1;
texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
highp vec2 texPos2;
texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) *textureColor.g);
lowp vec4 newColor1 = texture2D(sTexture2, texPos1);
lowp vec4 newColor2 = texture2D(sTexture2, texPos2);
lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));
gl_FragColor = gl_FragColor = mix(textureColor, vec4(newColor.rgb, textureColor.w), intensity);
}
I have been trying to fix this problem since two weeks , hoping to find solution and also have exhausted google searches with all possible keywords. I am new to opengl, and would request help in this particular part.
Thank you for helping me!
I have successfully bind 2 external OES texture to my shader. Now I want each texture to take 1/2 of the screen(Left for one texture right for another). How do I go about doing it? Example:
http://vicceskep.hu/kepek/vicces_funny_007445.jpg
random image from google
Showing a full picture of each picture. It will be nice to have an efficient method to do it. The code that I am currently referencing from is the bikflake/ grafika code from github.
Visit http://bigflake.com/mediacodec/CameraToMpegTest.java.txt
To check the code out.
Okay I think i will really give in depth clarification for my question as I do not have much knowledge about 3d projections in open GL. Sorry for the numerous edits on the question.
This is my Vertex Shader code currently
private static final String VERTEX_SHADER =
// UMVPMATRIX IS AN IDENTITY MATRIX
"uniform mat4 uMVPMatrix;\n" +
//These are surfacetexture.getTransformationMatrix
"uniform mat4 uSTMatrixOne;\n" +
"uniform mat4 uSTMatrixTwo;\n" +
"attribute vec4 aPosition;\n" +
"attribute vec4 aTextureCoord;\n" +
"varying vec2 vTextureCoord;\n" +
"varying vec2 vTextureCoordTwo;\n" +
"void main() {\n" +
" gl_Position = uMVPMatrix * aPosition;\n" +
" vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
" vTextureCoordTwo = (uSTMatrixTwo* aTextureCoord).xy ;\n" +
"}\n";
This is my Fragment Shader code currently which does a overlay currently.
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;\n" + // highp here doesn't seem to matter
"varying vec2 vTextureCoord;\n" +
"varying vec2 vTextureCoordTwo;\n" +
"uniform samplerExternalOES sTextureOne;\n" +
"uniform samplerExternalOES sTextureTwo;\n" +
"void main() {\n" +
" lowp vec4 pixelTop = texture2D(sTextureOne, vTextureCoord);\n" +
" lowp vec4 pixelBot = texture2D(sTextureTwo, vTextureCoordTwo);" +
" gl_FragColor = pixelTop + pixelBot;\n" +
"}\n";
As for the aPosition and the a texture coordinate it is currently referenced from. It would be nice if someone explained how mTraingleVerticesData works too.
private final float[] mTriangleVerticesData = {
// X, Y, Z, U, V
-1.0f, -1.0f, 0, 0.f, 0.f,
1.0f, -1.0f, 0, 1.f, 0.f,
-1.0f, 1.0f, 0, 0.f, 1.f,
1.0f, 1.0f, 0, 1.f, 1.f,
};
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
checkGlError("glVertexAttribPointer maPosition");
GLES20.glEnableVertexAttribArray(maPositionHandle);
checkGlError("glEnableVertexAttribArray maPositionHandle");
mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false,
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
My 2 external projection binding currently
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
//Cam Code
//Set texture to be active
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTwoTextureID);
You can do it the way #Sung suggested but conditional statements and loops in shaders, especialy fragment, are slow. It's better to render 2 different polygons.
Yea I finally got it.I used 2 different programs to draw and used mTriangleVerticesData to edit the image proportions and use gl_position to shift the image.
i am trying to combine surface texture(external basically camera feed ) and ordinary texture , when i run this the screen becomes black i tried in galaxy s5,s6 got the same results,searched online but couldn't find any resources for this,Any feedback is welcome.
shaders
private final String vertexShaderCodeCamera ="uniform mat4 uMVPMatrix;" +
"attribute vec4 position;" +
"attribute vec2 inputTextureCoordinate;" +
"varying vec2 textureCoordinate;" +
"attribute vec3 a_normal;"+ //new line
"varying vec3 v_normal;"+//new line
"uniform mat4 u_MVMatrix;" +
"void main()" +
"{" +
" gl_Position = uMVPMatrix * position;" +
"textureCoordinate = inputTextureCoordinate;" +
"v_normal = vec3(u_MVMatrix * vec4(a_normal, 0.0));"+
"}";
private final String fragmentShaderCodeCamera =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;" +
"varying vec2 textureCoordinate; \n" +
"uniform samplerExternalOES s_texture; \n" +
"uniform sampler2D Texture;" +
"void main(void) {" +
"gl_FragColor = texture2D(s_texture, textureCoordinate );\n" +
"gl_FragColor = texture2D(Texture, textureCoordinate);" +
"}";
camera draw method:
public void display_Camera(int texture){
GLES20.glUseProgram(cam_mProgram);
GLES20.glActiveTexture(GL_TEXTURE_EXTERNAL_OES);
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
cam_mPositionHandle = GLES20.glGetAttribLocation(cam_mProgram, "position");
GLES20.glEnableVertexAttribArray(cam_mPositionHandle);
GLES20.glVertexAttribPointer(cam_mPositionHandle, CAM_COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStrideSquare, vertexBuffer);
cam_mTextureCoordHandle = GLES20.glGetAttribLocation(cam_mProgram, "inputTextureCoordinate");
GLES20.glEnableVertexAttribArray(cam_mTextureCoordHandle);
GLES20.glVertexAttribPointer(cam_mTextureCoordHandle, CAM_COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStrideSquare, textureVerticesBuffer);
cam_mColorHandle = 2;//GLES20.glGetAttribLocation(cam_mProgram, "s_texture");
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(cam_mPositionHandle);
GLES20.glDisableVertexAttribArray(cam_mTextureCoordHandle);
}
model draw method:
public void draw1(float[] mvpMatrix) {
// Add program to OpenGL environment
GLES20.glUseProgram(cam_mProgram);
// get handle to shape's transformation matrix
mPositionHandle = 0;//GLES20.glGetAttribLocation(cam_mProgram, "vPosition");
// get handle to vertex shader's vPosition member
mMVPMatrixHandle = GLES20.glGetUniformLocation(cam_mProgram, "uMVPMatrix");
MainActivity.checkGLError("glGetUniformLocation");
fsTexture = GLES20.glGetUniformLocation(cam_mProgram, "Texture");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glUniform1i(fsTexture, 0);
vsTextureCoord = 1;//GLES20.glGetAttribLocation(cam_mProgram, "texCoord");
mNormalHandle = 3;//GLES20.glGetAttribLocation(cam_mProgram, "a_normal");//new line
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
GLES20.glVertexAttribPointer(vsTextureCoord, COORDS_PER_TEXTURE,
GLES20.GL_FLOAT, false,
TextureStride, texBuffer);
GLES20.glEnableVertexAttribArray(vsTextureCoord);
GLES20.glVertexAttribPointer(mNormalHandle, COORDS_PER_NORMAL, GLES20.GL_FLOAT, false,
12, normalbuffer);//new line
GLES20.glEnableVertexAttribArray(mNormalHandle);//new line
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
MainActivity.checkGLError("glUniformMatrix4fv");
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, tablelamp21NumVerts);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(vsTextureCoord);
GLES20.glDisableVertexAttribArray(mNormalHandle);
}
linking of shaders:
cam_mProgram = GLES20.glCreateProgram(); // create empty OpenGL Program
if (cam_mProgram != 0)
{
// Bind the vertex shader to the program.
GLES20.glAttachShader(cam_mProgram, cameravertexShader);
// Bind the fragment shader to the program.
GLES20.glAttachShader(cam_mProgram, camerafragmentShader);
// Bind attributes
GLES20.glBindAttribLocation(cam_mProgram, 0, "position");
GLES20.glBindAttribLocation(cam_mProgram, 1, "inputTextureCoordinate");
GLES20.glBindAttribLocation(cam_mProgram, 2, "s_texture");//new line
GLES20.glBindAttribLocation(cam_mProgram, 3, "a_normal");//new line
// Link the two shaders together into a program.
GLES20.glLinkProgram(cam_mProgram);
// Get the link status.
final int[] linkStatus = new int[1];
GLES20.glGetProgramiv(cam_mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
// If the link failed, delete the program.
if (linkStatus[0] == 0)
{
GLES20.glDeleteProgram(cam_mProgram);
cam_mProgram = 0;
}
}
My code:
public void draw1(float[] mvpMatrix) {
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
// get handle to shape's transformation matrix
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// get handle to vertex shader's vPosition member
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");
mNormalHandle = GLES20.glGetAttribLocation(mProgram, "a_normal");//new line
fsTexture = GLES20.glGetUniformLocation(mProgram, "Texture");
vsTextureCoord = GLES20.glGetAttribLocation(mProgram, "texCoord");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glUniform1i(fsTexture, 0);
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
MyGLRenderer.checkGlError("glUniformMatrix4fv");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
GLES20.glVertexAttribPointer(vsTextureCoord, COORDS_PER_TEXTURE,
GLES20.GL_FLOAT, false,
TextureStride, texBuffer);
GLES20.glEnableVertexAttribArray(vsTextureCoord);
GLES20.glVertexAttribPointer(mNormalHandle, COORDS_PER_NORMAL, GLES20.GL_FLOAT, false,
12, normalbuffer);//new line
GLES20.glEnableVertexAttribArray(mNormalHandle);//new line
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, tablelamp21NumVerts);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(vsTextureCoord);
GLES20.glDisableVertexAttribArray(mNormalHandle);//new line
}
so i am getting a glGetUniformLocation: glError 1281 at MyGLRenderer.checkGlError("glGetUniformLocation"); code line
after debugging i found that my mNormalHandle is -1 i.e GLES20.glGetAttribLocation(mProgram, "a_normal"); is returning -1, even though i using it in the vertex shader and i am using GLES20.glBindAttribLocation(mProgram, 2, "a_normal"); before linking please help.
shaders code:
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"uniform mat4 u_MVMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 texCoord;" +
"attribute vec3 a_normal;"+ //new line
"varying vec3 v_normal;"+//new line
"varying vec2 texCoordOut;" +
"void main() {" +
" v_normal = vec3(u_MVMatrix * vec4(a_normal, 0.0));"+
" texCoordOut = texCoord;" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D Texture;" +
"varying vec2 texCoordOut;"+
"void main() {" +
" gl_FragColor = texture2D(Texture, texCoordOut);" +
"}";
Sorry to answer to an outdated question, but if that can help other developers: I think the GLSL compiler is pretty good to strip unused variables.
For example, with the follow vertex and fragment shader compiled with the OpenGL/ES driver of an Android emulator:
private val vertexShaderCode = """attribute vec4 in_position;
attribute vec2 in_texcoord;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
varying vec2 var_texcoord;
void main() {
var_texcoord = in_texcoord;
gl_Position = projection * view * model * in_position;
}
"""
private val fragmentShaderCode = """
precision mediump float;
varying vec2 var_texcoord;
uniform sampler2D texture;
uniform vec4 color;
void main() {
gl_FragColor = color;
}
"""
GLES20.glGetAttribLocation(program, "in_texcoord"); will return -1
Now if we use var_texcoord to compute the color in the fragment shader:
private val fragmentShaderCode = """
precision mediump float;
varying vec2 var_texcoord;
uniform sampler2D texture;
uniform vec4 color;
void main() {
gl_FragColor = texture2D(texture, var_texcoord);
}
"""
GLES20.glGetAttribLocation(program, "in_texcoord"); will return a valid id, > -1
Apparently the GLSL compiler can strip variable and varying variable, if they are not used, so it's seems possible that your a_normal variable is removed too.