WebGL - How to pass unsigned byte vertex attribute colour values? - opengl-es

My vertices are made up of an array with this structure:
[ Position ][ colour ]
[float][float][float][byte][byte][byte][byte]
Passing the vertex position is no problem:
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
gl.vertexAttribPointer(this.material.aVertexPosition, 3, gl.FLOAT, false, 4, 0);
But I can't figure out how I can pass the colours to the shader. Unfortunately, it's not possible to use integers inside the glsl shader so I have to use floats.
How can I get my unsigned byte colour value into the glsl float colour value? I tried it like this for r, g and b sepperately but the colours are all messed up:
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
gl.vertexAttribPointer(this.material.aR, 1, gl.BYTE, false, 15, 12);
Vertex Shader (colouredPoint.vs)
precision highp float;
attribute vec3 aVertexPosition;
attribute float aR;
attribute float aG;
attribute float aB;
uniform mat4 world;
uniform mat4 view;
uniform mat4 proj;
varying vec3 vVertexColour;
void main(void){
gl_PointSize = 4.0;
gl_Position = proj * view * world * vec4(aVertexPosition, 1.0);
vVertexColour = vec3(aR, aG, aB);
}
Pixel Shader (colouredPoint.fs)
precision highp float;
varying vec3 vVertexColour;
void main(void){
gl_FragColor = vec4(vVertexColour, 1);
}

gl.vertexAttribPointer(this.material.aVertexPosition, 3, gl.FLOAT, false, 4, 0);
gl.vertexAttribPointer(this.material.aR, 1, gl.BYTE, false, 15, 12);
Your stride should be 16, not 15 and certainly not 4.
Also, each individual color does not need to be a separate attribute. The four bytes can be a vec4 input. Oh, and your colors should be normalized, unsigned bytes. That is, the values on the range [0, 255] should be scaled to [0, 1] when the shader gets them. Therefore, what you want is:
gl.vertexAttribPointer(this.material.aVertexPosition, 3, gl.FLOAT, false, 16, 0);
gl.vertexAttribPointer(this.material.color, 4, gl.UNSIGNED_BYTE, true, 16, 12);
Oh, and attributes are not materials. You shouldn't call them that.

GLfloat red=(GLfloat)red/255;
I hope that's what you are looking for ^^

Related

OpenGL ES 2.0. Indices for each vertex attrib array

I need to draw graph.
I have to arrays of vertex attributes:
array of x coordinates: xPos
array of y coordinates: yPos
But X doesn't match Y.
I need to create separate arrays of indices and link them to the corresponding arrays of coordinates.
What i need
glEnableVertexAttribArray(opglp->xPositionLocation);
glBindBuffer(GL_ARRAY_BUFFER, opglp->vbo1);
glVertexAttribPointer(opglp->xPositionLocation, 1, GL_FLOAT, GL_FALSE, 0 , 0 );
glEnableVertexAttribArray(opglp->yPositionLocation);
glBindBuffer(GL_ARRAY_BUFFER, opglp->vbo2);
glVertexAttribPointer(opglp->yPositionLocation, 1, GL_FLOAT, GL_FALSE, 0 , 0 );
glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, NULL);
Vertex shader:
attribute float xPosition;
attribute float yPosition;
uniform mat4 projection;
uniform mat4 modelView;
void main()
{
vec4 pos;
pos = vec4(xPosition, yPosition, 0.0, 1.0);
gl_Position = projection * modelView * pos;
}

Jittering vertices

I'm trying to get rid of spatial jitter. To be more precise, I'm trying to replicate Three.js behavior concerning matrix manipulation.
My current rendering pipeline (WebGL with m4.js)
There is a scene object, a camera and a mesh. The mesh has its position (mesh.position) set to position and the camera is floating somewhere near it.
Vertices have positions relative to mesh.position:
new Float32Array([
-5, 0, -5,
5, 0, -5,
0, 0, 5
])
Important part of render loop:
const position = {x: 6428439.8443510765, y: 0, z: 4039717.5286310893}; // mesh is located there
camera.updateMatrixWorld();
camera.updateMatrixWorldInverse();
let modelViewMatrix = m4.multiply(camera.matrixWorldInverse, mesh.matrixWorld);
material.uniforms.projectionMatrix = {type: 'Matrix4fv', value: camera.projectionMatrix};
material.uniforms.modelViewMatrix = {type: 'Matrix4fv', value: modelViewMatrix};
material.use();
mesh.draw(material);
Vertex shader:
#version 300 es
precision highp float;
in vec3 position;
in vec3 color;
out vec3 vColor;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
void main() {
vColor = color;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
Fragment shader:
#version 300 es
precision highp float;
out vec4 FragColor;
in vec3 vColor;
uniform float uSample;
void main() {
FragColor = vec4(vColor * uSample, 1);
}
Result:
When moving or rotating the camera around the mesh spatial jitter effect is observed, which is not the expected behavior.
I've implemented the same scene using Three.js, and as expected you can see no jitter while moving vertices or camera: Codepen link. Three.js must work exactly the same as my implemetation, but obviously I'm missing something.
It turns out that m4.js which is a part of webgl-3d-math library used on webgl2fundamentals.org utilizes Float32Array objects for storing matrices. Maybe this approach positively affects performance, but it also causes some confusion as JavaScript's Number uses 64-bit floats.

Weird behaviour with OpenGL Uniform Buffers on OSX

I am having some weird behaviour with uniform buffers in my hobby OpenGL4.1 engine.
On windows everything works fine (both Intel and Nvidia GPUs) but on my MacBook (also Intel) this isn't working.
So to explain what is happening on OSX: if I hardcode all my Uniform Buffer variables in the actual fragment shader code then I am able to render perfectly fine but if I set them back to the variables - I get nothing.
Had a look at the OpenGL state using apitrace and all the variables values are perfect so I am a bit confused as to what is going on here.
I am hoping this is just a code bug and not some underlying issue with the drivers.
Below is the fragment shader code where if I hardcode all the DirectionLight variables everything works fine.
#version 410
struct DirectionalLightData
{
vec4 Colour;
vec3 Direction;
float Intensity;
};
layout(std140) uniform ObjectBuffer
{
mat4 Model;
};
layout(std140) uniform FrameBuffer
{
mat4 Projection;
mat4 View;
DirectionalLightData DirectionalLight;
vec3 ViewPos;
};
uniform sampler2D PositionMap;
uniform sampler2D NormalMap;
uniform sampler2D AlbedoSpecMap;
layout(location = 0) in vec2 TexCoord;
out vec4 FinalColour;
float CalcDiffuseContribution(vec3 lightDir, vec3 normal)
{
return max(dot(normal, -lightDir), 0.0f);
}
float CalcSpecularContribution(vec3 lightDir, vec3 viewDir, vec3 normal, float specularExponent)
{
vec3 reflectDir = reflect(lightDir, normal);
vec3 halfwayDir = normalize(lightDir + viewDir);
return pow(max(dot(normal, halfwayDir), 0.0f), specularExponent);
}
float CalcDirectionLightFactor(vec3 viewDir, vec3 lightDir, vec3 normal)
{
float diffuseFactor = CalcDiffuseContribution(lightDir, normal);
float specularFactor = CalcSpecularContribution(normal, viewDir, normal, 1.0f);
return diffuseFactor * specularFactor;
}
void main()
{
vec3 position = texture(PositionMap, TexCoord).rgb;
vec3 normal = texture(NormalMap, TexCoord).rgb;
vec3 albedo = texture(AlbedoSpecMap, TexCoord).rgb;
vec3 viewDir = normalize(ViewPos - position);
float directionLightFactor = CalcDirectionLightFactor(viewDir, DirectionalLight.Direction, normal) * DirectionalLight.Intensity;
FinalColour.rgb = albedo * directionLightFactor * DirectionalLight.Colour.rgb;
FinalColour.a = 1.0f * DirectionalLight.Colour.a;
}
Here is the order of where I update and bind the UBO (I have pulled these from apitrace as there is too much code to copy paste here):
glGetActiveUniformBlockName(5, 0, 255, NULL, FrameBuffer);
glGetUniformBlockIndex(5, FrameBuffer) = 0;
glGetActiveUniformBlockName(5, 1, 255, NULL, ObjectBuffer);
glGetUniformBlockIndex(5, ObjectBuffer) = 1;
glBindBuffer(GL_UNIFORM_BUFFER, 1);
glMapBufferRange(GL_UNIFORM_BUFFER, 0, 172,GL_MAP_WRITE_BIT);
memcpy(0x10b9f8000, [binary data, size = 172 bytes], 172);
glUnmapBuffer(GL_UNIFORM_BUFFER);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, 2);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, 1);
glBindBuffer(GL_UNIFORM_BUFFER, 2);
glMapBufferRange(GL_UNIFORM_BUFFER, 0, 64, GL_MAP_WRITE_BIT);
memcpy(0x10b9f9000, [binary data, size = 64 bytes], 64);
glUnmapBuffer(GL_UNIFORM_BUFFER);
glUniformBlockBinding(5, 1, 0);
glUniformBlockBinding(5, 0, 1);
glDrawArrays(GL_TRIANGLES, 0, 6);
Note that the FrameBuffer UBO has ID 1 and ObjectBuffer UBO has ID 2
I think when you are using std140 layout your data members should be byte aligned so you cannot mix vec4 and vec3 or float keep all variables mat4 and vec4 else dnt use std140 layout and in application side calculate ubo alignment and offsets of your variables on ubo and set values. See usage of GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT.
As experiment change all variables to mat4 and vec4 and see your issue should go away.
If you did not use the std140 layout for a block, you will need to query the byte offset for each uniform within the block. The OpenGL specification explains the storage of each of the basic types, but not the alignment between types. Struct members, just like regular uniforms, each have a separate offset that must be individually queried.
After a few days of digging I seem to have found the issue.
I was not calling glBindBufferBase() after binding a different shader program.
Such a silly mistake caused me so much grief.
Thanks everyone for the help.

OpenGl basic Vertex Shader

I am new in shader concepts and I am trying to implement a sprite of 8x8 in OpenGL ES.
I want to move the texture in the vertex shader but I cant figure out how to this, my code may be wrong, feel free to correct me
If I change this line in the vertex shader, the texture scale but I want to move not scale!:
v_TexCoordinate = a_TexCoordinate*vec2(1.5,1.5);
So I should apply adition but I dont know how to do it( maybe there is another way)
Vertex shader:
uniform mat4 u_MVPMatrix; // A constant representing the combined model/view/projection matrix.
uniform mat4 u_MVMatrix; // A constant representing the combined model/view matrix.
uniform mat4 u_TextureMatrix;
attribute vec4 a_Position; // Per-vertex position information we will pass in.
attribute vec3 a_Normal; // Per-vertex normal information we will pass in.
attribute vec2 a_TexCoordinate; // Per-vertex texture coordinate information we will pass in.
varying vec3 v_Position; // This will be passed into the fragment shader.
varying vec3 v_Normal; // This will be passed into the fragment shader.
varying vec2 v_TexCoordinate; // This will be passed into the fragment shader.
// The entry point for our vertex shader.
void main()
{
// Transform the vertex into eye space.
v_Position = vec3(u_MVMatrix * a_Position);
// Pass through the texture coordinate.
v_TexCoordinate = a_TexCoordinate;
// Transform the normal's orientation into eye space.
v_Normal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));
// gl_Position is a special variable used to store the final position.
// Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
gl_Position = u_MVPMatrix * a_Position;
}
This is my draw fuction
private void drawMagia()
{
GLES20.glUseProgram(mMagiaProgramHandle);
mTextureMatrixHandle = GLES20.glGetUniformLocation(mMagiaProgramHandle, "u_TextureMatrix");
mMagiaTextureCoordinateHandle = GLES20.glGetAttribLocation(mMagiaProgramHandle, "a_TexCoordinate");
mMagiaPositions.position(0);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
0, mMagiaPositions);
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Pass in the normal information
mMagiaNormals.position(0);
GLES20.glVertexAttribPointer(mNormalHandle, mNormalDataSize, GLES20.GL_FLOAT, false,
0, mMagiaNormals);
GLES20.glEnableVertexAttribArray(mNormalHandle);
// Pass in the texture coordinate information
mMagiaTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false,
0, mMagiaTextureCoordinates);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
// 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);
// Pass in the modelview matrix.
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mTextureMatrixHandle, 1, false, mTextureMatrix, 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);
// Pass in the combined matrix.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Pass in the light position in eye space.
GLES20.glUniform3f(mLightPosHandle, mLightPosInEyeSpace[0], mLightPosInEyeSpace[1], mLightPosInEyeSpace[2]);
// Draw the square.
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}
You can add some offsets instead of multiplying.
v_TexCoordinate = a_TexCoordinate + vec2(1.5,1.5);
Also your texture should be clamped

orthographic projection matrix in Opengl-es 2.0

float pfIdentity[] =
{
-1.0f,0.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,0.0f,
0.0f,0.0f,1.0f,0.0f,
0.0f,0.0f,0.0f,1.0f
};
==================================================================================
const char* pszVertShader = "\
attribute highp vec4 myVertex;\
uniform mediump mat4 myPMVMatrix;\
invariant gl_Position;\
void main(void)\
{\
gl_Position = myPMVMatrix * myVertex;\
}";
=====================================================================
for(int i = 0; i < 80000; ++i)
{
glClear(GL_COLOR_BUFFER_BIT);
int i32Location = glGetUniformLocation(uiProgramObject, "myPMVMatrix");
glUniformMatrix4fv( i32Location, 1, GL_FALSE, pfIdentity);
glEnableVertexAttribArray(VERTEX_ARRAY);
glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0,i);
eglSwapBuffers(eglDisplay, eglSurface);
}
return 0;
}
p.s : i am doing opengl-es in ubuntu 10.10 with kronos headers , its an emulator for opengl-es 2.0 in linux.
You don't have a projection at all. The Projection-Model-View matrix you're setting the myPMVMatrix uniform to is
float pfIdentity[] =
{
-1.0f,0.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,0.0f,
0.0f,0.0f,1.0f,0.0f,
0.0f,0.0f,0.0f,1.0f
};
/* ... */
glUniformMatrix4fv( i32Location, 1, GL_FALSE, pfIdentity);
BTW: The idea of uniforms is, that you don't set them at each primitive iteration.
Anyway, this is a identity matrix, and since it's the only transformation applied it will just pass through the vertices as they are to the fragment stage. The solution for your problem is applying a orthographic projection to it, i.e. multiply that matrix with a ortho projection matrix and use the result of that operation instead. http://www.songho.ca/opengl/gl_projectionmatrix.html

Resources