C++/OpenGL glm Can't plug matrix into uniform in shader - c++

I can't use my matrix in my OpenGL shader; this is giving me an error:
glUniform4f(matLocation, mat[0], mat[1], mat[2], mat[3]); // glm mat4
no suitable conversion function from "glm::tvec4<float, glm::highp>" to "GLfloat" exists
I don't entirely understand why it's giving me this error message, and as usual, Googling doesn't give me any good results. Why would it want me to convert matrices to floats?

glUniform4f only updates a vec4 with four float values, so you need glUniformMatrix4fv which takes a pointer to an array of 16 float values glm can provide with glm::value_ptr.
mat[n] only yields the nth column, a vec4; thus the compilation error.

Related

GLSL compile error '/' does not operate on 'vec4' and 'vec2'

Part of my fragment shader not compiling
vec2 uv=gl_FragCoord/uTDOutputInfo.res.zw;
returns the following error
'/' does not operate on 'vec4' and 'vec2'
Also tried which gives same error.
vec2 uv=gl_FragCoord/iResolution.xy;
The type of gl_FragCoord is vec4.
It is not possible to divide a vector with 4 components by a vector with 2 components.
Use Swizzling to get the x and y component of gl_FragCoord:
vec2 uv=gl_FragCoord.xy/iResolution.xy;

Compute the cosine of a vector

I'm learning about shader, and I've come across the following GLSL code:
vec3 color = cos(vec3(.5,.3,.4));
How do I compute the cosine of a vector vec3(.5,.3,.4)?
In GLSL most of the functions are overloaded and the argument can be a vector. Operations and functions may operate component wise. In case of cos, the cosine is computed for each component of the vector and the result is stored in a new vector:
The expression statement
vec3 color = cos(vec3(.5,.3,.4));
can be read as
vec3 color = vec3(cos(.5), cos(.3), cos(.4));

Opengl - instanced attributes

I use oglplus - it's a c++ wrapper for OpenGL.
I have a problem with defining instanced data for my particle renderer - positions work fine but something goes wrong when I want to instance a bunch of ints from the same VBO.
I am going to skip some of the implementation details to not make this problem more complicated. Assume that I bind VAO and VBO before described operations.
I have an array of structs (called "Particle") that I upload like this:
glBufferData(GL_ARRAY_BUFFER, sizeof(Particle) * numInstances, newData, GL_DYNAMIC_DRAW);
Definition of the struct:
struct Particle
{
float3 position;
//some more attributes, 9 floats in total
//(...)
int fluidID;
};
I use a helper function to define the OpenGL attributes like this:
void addInstancedAttrib(const InstancedAttribDescriptor& attribDesc, GLSLProgram& program, int offset=0)
{
//binding and some implementation details
//(...)
oglplus::VertexArrayAttrib attrib(program, attribDesc.getName().c_str());
attrib.Pointer(attribDesc.getPerVertVals(), attribDesc.getType(), false, sizeof(Particle), (void*)offset);
attrib.Divisor(1);
attrib.Enable();
}
I add attributes for positions and fluidids like this:
InstancedAttribDescriptor posDesc(3, "InstanceTranslation", oglplus::DataType::Float);
this->instancedData.addInstancedAttrib(posDesc, this->program);
InstancedAttribDescriptor fluidDesc(1, "FluidID", oglplus::DataType::Int);
this->instancedData.addInstancedAttrib(fluidDesc, this->program, (int)offsetof(Particle,fluidID));
Vertex shader code:
uniform vec3 FluidColors[2];
in vec3 InstanceTranslation;
in vec3 VertexPosition;
in vec3 n;
in int FluidID;
out float lightIntensity;
out vec3 sphereColor;
void main()
{
//some typical MVP transformations
//(...)
sphereColor = FluidColors[FluidID];
gl_Position = projection * vertexPosEye;
}
This code as whole produces this output:
As you can see, the particles are arranged in the way I wanted them to be, which means that "InstanceTranslation" property is setup correctly. The group of the particles to the left have FluidID value of 0 and the ones to the right equal to 1. The second set of particles have proper positions but index improperly into FluidColors array.
What I know:
It's not a problem with the way I set up the FluidColors uniform. If I hard-code the color selection in the shader like this:
sphereColor = FluidID == 0? FluidColors[0] : FluidColors1;
I get:
OpenGL returns GL_NO_ERROR from glGetError so there's no problem with the enums/values I provide
It's not a problem with the offsetof macro. I tried using hard-coded values and they didn't work either.
It's not a compatibility issue with GLint, I use simple 32bit Ints (checked this with sizeof(int))
I need to use FluidID as a instanced attrib that indexes into the color array because otherwise, if I were to set the color for a particle group as a simple vec3 uniform, I'd have to batch the same particle types (with the same FluidID) together first which means sorting them and it'd be too costly of an operation.
To me, this seems to be an issue of how you set up the fluidID attribute pointer. Since you use the type int in the shader, you must use glVertexAttribIPointer() to set up the attribute pointer. Attributes you set up with the normal glVertexAttribPointer() function work only for float-based attribute types. They accept integer input, but the data will be converted to float when the shader accesses them.
In oglplus, you apparently have to use VertexArrayAttrib::IPointer() instead of VertexArrayAttrib::Pointer() if you want to work with integer attributes.

fragment shader if statment and loading array of mat4 into uniform

I have problem with if here, for reasons uknown to me, it dosnt work.
When i delete if statment or malualy write shadowMap[0] 1 or 2 it works fine, but with if i just get set of white triangles and squares.
here is part of my frag shader
float shadow(float bias)
{
float visibility = 0;
int index=1;
if(gl_FragCoord.z<1.0){
index=0;
}
vec4 shadowCoord=depthPV*vPos;
if ( texture(shadowMap[index], shadowCoord.xy).z < shadowCoord.z+bias){
visibility = -1;
}
return visibility;
}
Other problem i have is with loading array of mat4 into uniform here is code i tried, but it dosnt work, i use lwjgl 3 libery in java
shadowPVs=GL20.glGetUniformLocation(pId, "shadowPVs");
ByteBuffer shadowPVbuff=BufferUtils.createByteBuffer(shadePV.length*16*4);
for(int i=0;i<shadePV.length;i++){
for(int v=0;v<16;v++){
shadowPVbuff.putFloat(shadePV[i].val[v]);
}
}
shadowPVbuff.flip();
GL20.glUniformMatrix4f(shadowPVs, shadePV.length, false, shadowPVbuff);
and in shader
uniform mat4 shadowPVs[3];
What you are trying to do is not possible with current GL.
As #gemse already pointed out in the comments, the relevant part of the GLSL 3.30 spec is:
Samplers aggregated into arrays within a shader (using square brackets
[ ]) can only be indexed with integral constant expressions (see
section 4.3.3 “Constant Expressions”).
In GL 4, this constraint has been somehwat relaxed, but not far enough. In the most current GLSL 4.50 spec, the statement is:
When aggregated into arrays within a shader, samplers can only be
indexed with a dynamically uniform integral expression, otherwise
results are undefined.
With dynamically uniform being defined as
A fragment-shader expression is dynamically uniform if all fragments
evaluating it get the same resulting value. When loops are involved,
this refers to the expression's value for the same loop iteration.
When functions are involved, this refers to calls from the same call
point. This is similarly defined for other shader stages, based on the
per-instance data they process. Note that constant expressions are
trivially dynamically uniform. It follows that typical loop counters
based on these are also dynamically uniform.
Your index depends on data which can vary per fragment, so you are getting undefined results.

Multiplying a matrix and a vector in GLM (OpenGL)

I have a transformation matrix, m, and a vector, v. I want to do a linear transformation on the vector using the matrix. I'd expect that I would be able to do something like this:
glm::mat4 m(1.0);
glm::vec4 v(1.0);
glm::vec4 result = v * m;
This doesn't seem to work, though. What is the correct way to do this kind of operation in GLM?
Edit:
Just a note to anyone who runs into a similar problem. GLM requires all operands to use the same type. Don't try multiplying a dvec4 with a mat4 and expect it to work, you need a vec4.
glm::vec4 is represented as a column vector. Therefore, the proper form is:
glm::vec4 result = m * v;
(note the order of the operands)
Since GLM is designed to mimic GLSL and is designed to work with OpenGL, its matrices are column-major. And if you have a column-major matrix, you left-multiply it with the vector.
Just as you should be doing in GLSL (unless you transposed the matrix on upload).