OpenGLES 2.0: gl_VertexID equivalent? - glsl

I'm trying to create a grid of points by calculating vertex positions dynamically, based on their index in the array of vertices sent to the shader. Is there an equivalent of the gl_VertexID variable that I can call from within my shader? Or another way of accessing their position in the array without having to send more data to the GPU? Thank, Josh.
Here's my vertex shader:
attribute vec4 vertexPosition;
uniform mat4 modelViewProjectionMatrix;
vec4 temp;
uniform float width;
void main()
{
temp = vertexPosition;
// Calculate x and y values based on index:
temp.y = floor(gl_VertexID/width);
temp.x = gl_VertexID - width*temp.y;
gl_Position = modelViewProjectionMatrix * temp;
}

Unfortunately there is no gl_VertexID equivalent in GLES2. You must create and pass additional data yourself.

Related

GLSL - per-fragment lighting

I started lighting with several light sources. All the manuals that I saw without taking into account the distance between the light source and the object (for example https://learnopengl.com/Lighting/Basic-Lighting). So I wrote my shader, but I'm not sure about its correctness. Please, analyze this shader, and tell me what's wrong / not correct in it. I will be very grateful for any help! Below I bring the shader itself, and the results of its work for different values of n and k.
Fragment shader:
#version 130
precision mediump float; // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
#define MAX_LAMPS_COUNT 8 // Max lamps count.
uniform vec3 u_LampsPos[MAX_LAMPS_COUNT]; // The position of lamps in eye space.
uniform vec3 u_LampsColors[MAX_LAMPS_COUNT];
uniform vec3 u_AmbientColor = vec3(1, 1, 1);
uniform sampler2D u_TextureUnit;
uniform float u_DiffuseIntensivity = 12;
uniform float ambientStrength = 0.1;
uniform int u_LampsCount;
varying vec3 v_Position; // Interpolated position for this fragment.
varying vec3 v_Normal; // Interpolated normal for this fragment.
varying vec2 v_Texture; // Texture coordinates.
// The entry point for our fragment shader.
void main() {
float n = 2;
float k = 2;
float finalDiffuse = 0;
vec3 finalColor = vec3(0, 0, 0);
for (int i = 0; i<u_LampsCount; i++) {
// Will be used for attenuation.
float distance = length(u_LampsPos[i] - v_Position);
// Get a lighting direction vector from the light to the vertex.
vec3 lightVector = normalize(u_LampsPos[i] - v_Position);
// Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
// pointing in the same direction then it will get max illumination.
float diffuse = max(dot(v_Normal, lightVector), 0.1);
// Add attenuation.
diffuse = diffuse / (1 + pow(distance, n));
// Calculate final diffuse for fragment
finalDiffuse += diffuse;
// Calculate final light color
finalColor += u_LampsColors[i] / (1 + pow(distance, k));
}
finalColor /= u_LampsCount;
vec3 ambient = ambientStrength * u_AmbientColor;
vec3 diffuse = finalDiffuse * finalColor * u_DiffuseIntensivity;
gl_FragColor = vec4(ambient + diffuse, 1) * texture2D(u_TextureUnit, v_Texture);
}
Vertex shader:
#version 130
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.
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_Texture; // Per-vertex texture 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_Texture; // This will be passed into the fragment shader.
void main() {
// Transform the vertex into eye space.
v_Position = vec3(u_MVMatrix * a_Position);
// Pass through the texture.
v_Texture = a_Texture;
// 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;
}
n=2 k=2
n=1 k=3
n=3 k=1
n=3 k=3
And if my shader is correct, then how do I name these parameters (n, k)?
By "correct" I assume you mean is the code working as well as it should. These lighting calculations are not by any means physically accurate. Unless you are going for full compatibility with old devices, I would recommend you use a higher glsl version which allows you to use in and out and some other useful glsl features. The current is version 450 and you are still using 130. The vertex shader looks ok, as it is only passing through values to the fragment shader.
As for the fragment shader there are is one optimisation you could make.
The calculation u_LampsPos[i] - v_Position doesn't have to be repeated twice. Do it once and do the length and normalize on the same result from one calculation.
The code is quite small so there is not much to go wrong glsl wise however I was wondering why you did: finalColor /= u_LampsCount;?
This didn't make sense to me.

Strange dynamic iteration error in OpenGL shader

I'm trying to turn a float array into a vector2 array since a float array is the only array I can pass over from Java code to the shader. I'm turning for example float 3.8 into vec2(3,8). But that's pretty irrelevant. The real problem is that the shader stops working when adding a certain line in the for loop. Here's my code:
attribute vec4 a_color;
attribute vec3 a_position;
attribute vec2 a_texCoord0;
uniform float a_tileCoords[144];
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoord0;
varying vec2 v_tileCoords[144];
int length = 144;
void main(){
v_color = a_color;
v_texCoord0 = a_texCoord0;
for(int i = 0; i < length; i++){
int x = int(a_tileCoords[i]);
int y = int((a_tileCoords[i] - int(a_tileCoords[i])) * 10);
v_tileCoords[i] = vec2(x,y);
}
gl_Position = u_projTrans * vec4(a_position + vec3(0, 1, 0), 1.);
}
It's about this line:
v_tileCoords[i] = vec2(x,y);
When I remove that line from the for loop the shader works again (the texture gets drawn.) But I want this line to work of course. So the question for you is: What could I have done wrong, or is this even possible what I want to achieve?
The maximum number of varying vectors can be determined by MAX_VARYING_VECTORS and limits the number of vectors you can pass to the next shader stage.
I'm very sure you exceeded the limit.
see also the following questions:
WebGL shaders: maximum number of varying variables
Max Varying Vectors and Floats for GLES 2.0

Passing on two rectangles with different meaning from geometry to fragment shader

I've adapted Cinder library signed distance fonthandling to Delphi, and am now implementing a twist to upload all data for multiple texts in a single call, and to and to have some control over relative size when zooming (using an uniform instead of the 1.0001 factor in the geometry shader, not yet working in this code)
The basic signed distance handling is not altered, I only tried to calculate the needed rectangles using the geometry shader. I understand how to create the destination rectangle (where the character must appear) using triangle_strip, but are having problems passing the texcoord to the fragment shader.
destination rectangle : the input topleft.xy + widthheight (dimensions) is used to calculate the destination rectangle of each character on the screen. Using gl_position.
texture source rectangle 2: texcoordtl+texdimens, topleft point + dimensions for the character in the font texture. This is the main point where I'm unsure. Passed to fragment using texcoord in/out param.
I'd be grateful for any pointers or avenues to research and specially wonder about the way I calculate the texcoord coordinates and pass them on
to the fragment shader.
An array of the below record is bound with GL_ARRAY_BUFFER and described using a series of glGetAttribLocation/glEnableVertexAttribArray/glVertexAttribPointer calls)
Drawing is done using
glDrawArrays(GL_POINTS, 0, numberofelements_in_array );
The record:
TGLCharacter = packed record // 5*2* single + 1*4 byte color + 1*4 byte detail. = 48 bytes per character drawn
origin : TGLVectorf2; // origin of text ( = glfloat[2])
topleft : TGLVectorf2; // origin of this character
widthheight: TGLVectorf2; // width and heght this chracter
texcoordtl : TGLVectorf2; // coordinates topleft in texture.
texdimens : TGLVectorf2; // sizes in texture
col : TGLVectorub4; // 4 colors, 1 per rect vertex
detail : integer; // layer. Not used in this example.
end;
geometry code first because I expect the problems here:
#version 150 compatibility
layout(points) in;
layout(triangle_strip, max_vertices = 4) out;
in vec2 gorigin[];
in vec2 gtopleft[];
in vec2 gwidthheight[];
in vec2 gtexcoordtl[];
in vec2 gtexdimens[];
in vec4 gcolor[];
out vec3 fColor;
out vec2 texcoord;
void main() {
// calculate distance cur char - first char of this text
vec2 dxcoordinate = (gtopleft[0]-gorigin[0]);
// now multiply with uniform here and calc new coordinate:
// for now we use uniform slightly close to 1 to make debugging easier and avoid
// nvidia's shadercompiler to optimize gorigin out.
// equal to 1, and the nvidia shader optimizes it out.
vec2 x1y1 = 1.0001*gorigin[0]+dxcoordinate;
vec2 x2y2 = x1y1+gwidthheight[0]*1.0001;
vec2 texx1y1 = gtexcoordtl[0];
vec2 texx2y2 = gtexcoordtl[0]+gtexdimens[0];
fColor = vec3(gcolor[0].rgb);
gl_Position = gl_ModelViewProjectionMatrix * vec4(x1y1,0,1.0);
texcoord = texx1y1.xy;
EmitVertex();
gl_Position = gl_ModelViewProjectionMatrix * vec4(x2y2.x,x1y1.y,0,1.0);
texcoord = vec2(texx2y2.x,texx1y1.y);
EmitVertex();
gl_Position= gl_ModelViewProjectionMatrix * vec4(x1y1.x,x2y2.y,0,1.0);
texcoord = vec2(texx1y1.x,texx2y2.y);
EmitVertex();
gl_Position = gl_ModelViewProjectionMatrix * vec4(x2y2,0,1.0);
texcoord = texx2y2.xy;
EmitVertex();
EndPrimitive();
}
frag code:
#version 150 compatibility
uniform sampler2D font_map;
uniform float smoothness;
const float gamma = 2.2;
in vec3 fColor;
in vec2 texcoord;
void main()
{
// retrieve signed distance
float sdf = texture2D( font_map, texcoord.xy ).r;
// perform adaptive anti-aliasing of the edges
float w = clamp( smoothness * (abs(dFdx(texcoord.x)) + abs(dFdy(texcoord.y))), 0.0, 0.5);
float a = smoothstep(0.5-w, 0.5+w, sdf);
// gamma correction for linear attenuation
a = pow(a, 1.0/gamma);
if (a<0.1)
discard;
// final color
gl_FragColor.rgb = fColor.rgb;
gl_FragColor.a = gl_Color.a * a;
}
vertex code is probably ok I guess.
#version 150 compatibility
in vec2 anorigin;
in vec2 topleft;
in vec2 widthheight;
in vec2 texcoordtl;
in vec2 texdimens;
in vec4 color;
out vec2 gorigin;
out vec2 gtopleft;
out vec2 gwidthheight;
out vec2 gtexcoordtl;
out vec2 gtexdimens;
out vec4 gcolor;
void main()
{
gorigin=anorigin;
gtopleft=topleft;
gwidthheight=widthheight;
gtexcoordtl=texcoordtl;
gtexdimens=texdimens;
gcolor=color;
gl_Position = gl_ModelViewProjectionMatrix * vec4(anorigin.xy,0,1.0);;
}
The above code works. The problem was in the uploading code, so wrong vertex data was uploaded. I did some minor fixes to the above code while debugging and added it to the question, so that the question now shows working code.
Here is some possible code that changes the last 2 lines of the frag shader to create outline fonts. I'm not really happy yet with it though. When zooming out the color of the font seems to change
vec3 othercol; // to be added to declarations
.. rest shader below the discard statement becomes:
othercol=vec3(1.0,1.0,1.0);
if (sqrt(0.299 * fColor.r*fColor.r + 0.587 * fColor.g*fColor.g + 0.114 * fColor.b*fColor.b)>0.5)
{ othercol=vec3(0,0,0);}
// final color
if (sdf>0.25 && sdf<0.75)
{gl_FragColor.rgb = othercol.rgb;}
else
{gl_FragColor.rgb = fColor.rgb;}
gl_FragColor.a = gl_Color.a * a;
}

Skeletal Animation ussing ASSIMP and GLSL: bone uniform array size

I'm working on an ASSIMP skeletal animation loader and renderer and right now all the data is correctly loaded and interpolated at its current timeframe. However, there is still one part that isn't working as it should and that's the vertex shader stage.
Via a VBO I pass in two vec4s that contain the bone IDs and the weights for each vertex (up to a maximum of 4 bones/weights per vertex) and the vertex shader has a matrix array of 100 bone transformations (pre-calculated per frame) that are indexed via the bone IDs.
However, it seems that the bones uniform doesn't contain the proper transformations. For debugging purposes I colored the model with the weight values and the bone IDs value and they contain a color (and thus valid values). However, when I transform my vertex via the bone transformation and color the model with the result, the entire model is colored black, meaning the transformation matrices are all 0.0. So they're not initialized properly.
I think the problem is with passing the matrices to the uniform array, or perhaps the maximum size of uniforms allowed (I also tried setting the number of uniform matrices to 32 (number of bones on current model) but without effect)?
Before passing the information to the shader, the transformation matrices are indeed valid matrices (not identity/empty matrices) so the fault should probably be in the GLSL shader or the passing of the uniforms.
The following code is from the vertex shader:
#version 330
layout (location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 tangent;
layout(location = 3) in vec3 color;
layout(location = 4) in vec2 texCoord;
layout(location = 5) in ivec4 boneIDs;
layout(location = 6) in vec4 weights;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat4 bones[100];
out vec2 TexCoord;
out vec4 colorz;
void main()
{
vec4 newPos = vec4(position, 1.0);
colorz = vec4(0.0, 1.0, 0.0, 1.0);
if (weights != vec4(0.0, 0.0, 0.0, 0.0))
{
mat4 boneTransform = bones[boneIDs[0]] * weights[0];
boneTransform += bones[boneIDs[1]] * weights[1];
boneTransform += bones[boneIDs[2]] * weights[2];
boneTransform += bones[boneIDs[3]] * weights[3];
// newPos = boneTransform * vec4(position, 1.0);
vec4 test = vec4(1.0);
colorz = boneTransform * test;
// newPos = boneTransform * newPos;
}
TexCoord = texCoord;
gl_Position = projection * view * model * newPos;
}
The following snippet of code pass the matrix data to the GLSL shader:
// Sets bone transformation matrices
void Shader::SetBoneMatrix(GLint index, aiMatrix4x4 matrix)
{
glm::mat4 mat = glm::transpose(glm::make_mat4(&matrix.a1));
glUniformMatrix3fv(boneLocations[index], 1, GL_FALSE, glm::value_ptr(mat));
}
Also the code that gets all the uniform locations of the bones array:
for(unsigned int i = 0; i < 100; i++)
{
string name = "bones[";
string number;
stringstream ss;
ss << i;
ss >> number;
name += number;
name += ']';
boneLocations[i] = glGetUniformLocation(this->program, name.c_str());
}
Oké, via glslDevil I came across a continous GL_INVALID_OPERATION error when setting the bone matrix to the shader via glUniformMatrix. The origin of the problem was indeed at the stage where the program passes the information along to the shader.
It is quite a stupid mistake actually since I'm using glUniformMatrix3f instead of glUniformMatrix4f. Changing this did indeed solve the problem and the animations are working perfectly right now.

How can order of input attributes affect result of rendering?

Swapping order of two input variables corrupts rendering result. Why is that?
Little info about it's usage:
vertexPosition_modelspace has location 0 and vertexColor has location 1
I bind buffer storing vertex positions and set vertex attrib pointer, then I bind and set buffer for color
Right one:
#version 130
// Input vertex data, different for all executions of this shader.
in vec3 vertexColor;
in vec3 vertexPosition_modelspace;
// Output data ; will be interpolated for each fragment.
out vec3 fragmentColor;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
void main(){
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
// The color of each vertex will be interpolated
// to produce the color of each fragment
fragmentColor = vertexColor;
}
Wrong one:
#version 130
// Input vertex data, different for all executions of this shader.
in vec3 vertexPosition_modelspace; // <-- These are swapped.
in vec3 vertexColor; // <--
// Output data ; will be interpolated for each fragment.
out vec3 fragmentColor;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
void main(){
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
// The color of each vertex will be interpolated
// to produce the color of each fragment
fragmentColor = vertexColor;
}
Same problem is with texcoords and it took me hour to discover the problem. Why result gets corrupted if I put texcoord or color input after position? The order should not matter.
It's because of the order you use when you pass your data to shaders. In your OpenGL C or C++ code you are certainly sending the vertex color as the first vertex attrib, and then you send the position. If you intent to swap the order of parameters in the shader, you must swap the order of their initialization too.