My (fragment) shader has a uniform array containing 12 structs:
struct LightSource
{
vec3 position;
vec4 color;
float dist;
};
uniform LightSource lightSources[12];
In my program I have 12 buffer objects that each contain the data for one light source. (They need to be seperate buffers.)
How can I bind these buffers to their respective position inside the shader?
I'm not even sure how to retrieve the location of the array.
glGetUniformLocation(program,"lightSources");
glGetUniformLocation(program,"lightSources[0]");
These run without invoking an error, but the location is definitely wrong(4294967295). (The array is being used inside the shader, so I don't think it's being optimized out)
As glGetUniformLocation docs say:
name must be an active uniform variable
name in program that is not a structure,
an array of structures, or a subcomponent of a vector or a
matrix.
...
Uniform variables that are structures or arrays of
structures may be queried by calling
glGetUniformLocation for each field within
the structure.
So, you can only query one field at a time.
Like this:
glGetUniformLocation(program,"lightSources[0].position")
glGetUniformLocation(program,"lightSources[0].color")
glGetUniformLocation(program,"lightSources[0].dist")
Hope it helps.
Edit:
You can make your life easier (at a cost of old hardware/drivers compatibility) by using Interface Blocks, Uniform Buffer Objects and glGetUniformBlockIndex. This will be more like DirectX constant buffers. Required hardware/drivers support for that: either OpenglGL 3.1 core or ARB_uniform_buffer_object extension.
Related
I know that each time a vertex shader is run it basically accesses part of the buffer (VBO) being drawn, when drawing vertex number 7 for example it's basically indexing 7 vertices into that VBO, based on the vertex attributes and so on.
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec3 texCoords; // This may be running on the 7th vertex for example.
What I want to do is have access to an earlier part of the VBO for example, so when it's drawing the 7th Vertex I would like to have access to vertex number 1 for example, so that I can interpolate with it.
Seeing that at the time of running the shader it's already indexing into the VBO already, I would think that this is possible, but I don't know how to do it.
Thank you.
As you can see in the documentation, vertex attributes are expected to change on every shader run. So no, you can't access attributes defined for other vertices in a vertex shader.
You can probably do this:
Define a uniform array and pass in the values you need. But keep in mind that you are using more memory this way, you need to pass more data etc.
As #Reaper said you can use a uniform buffer, which can be accessed freely. But the GPU doesn't like random access, it's usually more efficient to stream the data.
You can solve this as well by just adding the data for later/earlier vertices into the array, because in C++ all vertices are at your disposal.
For example if this is the "normal" array:
{
vertex1_x, vertex1_y, vertex1_z, normal1_x, normal1_y, normal1_z, texCoord1_x, texCoord1_y,
...
}
Then you could extend it with data for the other vertex to interpolate with:
{
vertex1_x, vertex1_y, vertex1_z, normal1_x, normal1_y, normal1_z, texCoord1_x, texCoord1_y, vertex2_x, vertex2_y, vertex2_z, normal2_x, normal2_y, normal2_z, texCoord2_x, texCoord2_y,
...
}
Actually you can pass any data per vertex. Just make sure that the stride size and other parameters are adjusted in the glVertexAttribPointer parameters.
Most GLSL shaders are using a attribute for the color in the vertex shader, which will be forwarded as varying to the fragment shader. Like this:
attribute vec4 position;
attribute vec4 color;
uniform mat4 mvp;
varying vec4 destinationColor;
void main(){
destinationColor = color;
gl_Position = mvp * position;
};
Setting the color can be done with glVertexAtribPointer() to pass one color per vertex or with glVertexAttrib4fv() to pass a global color for all vertexes. I try to understand the difference to the predefined variable gl_Color in the vertex shader (if there is any difference at all). i.e.
attribute vec4 position;
uniform mat4 mvp;
varying vec4 destinationColor;
void main(){
destinationColor = gl_Color;
gl_Position = mvp * position;
};
and using glColorPointer() to pass one color per vertex or glColor4fv() to use a global color for all vertexes. To me the second shader looks better (= more efficient?), because it uses less attributes. But all tutorials & online resources are using the first approach - so I wonder if I missed anything or if there is no difference at all.
What is better practice when writing GLSL shaders?
To me the second shader looks better (= more efficient?), because it uses less attributes.
It does not use fewer attributes. It just uses fewer explicit attribute declarations. All of the work needed to get that color value to OpenGL is still there. It's still being done. The hardware is still fetching data from a buffer object or getting it from the glColor context value or whatever.
You just don't see it in your shader's text. But just because you don't see it doesn't mean that it happens for free.
User-defined attributes are preferred for the following reasons:
User-defined attributes make it clear how many resources your shaders are using. If you want to know how many attributes you need to provide to a shader, just look at the global declarations. But with predefined attributes, you can't do this; you have to scan through the entire vertex shader for any gl_* names that name a predefined attribute.
User-defined attributes can do more things. If you want to pass integer values as integers to the vertex shader, you must use a user-defined attribute. If you need to pass a double-precision float to the vertex shader, again, a predefined attribute cannot help you.
Predefined attributes were removed from core OpenGL contexts. OSX, for example, does not allow the compatibility profile. You can still use OpenGL 2.1, but if you want to use any OpenGL version 3.2 or greater on OSX, you cannot use removed functionality. And the built-in vertex attributes were removed in OpenGL 3.1.
Predefined attributes were never a part of OpenGL ES 2.0+. So if you want to write shaders that can work in OpenGL ES, you again cannot use them.
So basically, there's no reason to use them these days.
if I remember correctly gl_Color is deprecated remnant from the old style API without VAO/VBO using glBegin() ... glEnd(). If you go to core profile there is no gl_Color anymore ... so I assume you use old OpenGL version or compatibility profile.
If you try to use gl_Color in core profile (for example 4.00) you got:
0(35) : error C7616: global variable gl_Color is removed after version 140
Which means gl_Color was removed from GLSL 1.4
It is not entirely matter of performance but the change in graphic rendering SW architecture or hierarchy of the GL calls if you want.
I'd like to implement instanced rendering to my opengl engine but I've just learned that the maximum number of inputs supported by vertex shader is only 16 for my GPU.
These are the following matrices I need to move to input:
uniform mat4 MVP;
uniform mat4 modelMatrix;
uniform mat3 normalMatrix;
uniform mat4 DepthBiasMVP;
If I understand correctly I will need an attribute for every column of each matrix, so I'll need 4+4+3+4 = 15 attribute space. 19 with the attributes that I already use ( pos, color, texCoord, normal ), and it will grow up to 20+ if I add tangents and other stuff.
Is there a way to deal with this or will I have to forget the instanced drawing ? Let's say I managed to get rid of one of these matrices (modelMatrix) and I have about 15 - 16 attributes, will it work on different GPU's ? the 16 limit is the minimum for all GPU's right ?
Note that 16 is the minimum amount of vertex attributes that your implementation actually has; most of the time more are allowed that you can query via:
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &n).
Now, when trying to store all your data in instanced arrays you should try and organize what the data actually is that you want to differ per instance. Do you have a lot of instanced objects that only differ in location and/or orientation? Then you probably only need to set your uniform modelMatrix as an instanced array (which requires 4 vertex attributes, an acceptable value). Do you really need a different view and projection matrix for each instance? Probably not. The same holds for DepthBiasMVP.
The normalMatrix is required if you perform non-uniform scaling and if you plan to do that for each instance you also need to set a normalMatrix per instance. You could calculate those on the CPU beforehand and send them as vertex attributes costing you another 4 vertex attributes. Another option is to calculate normalMatrix in the vertex shader, but that this might slow your vertex shader down a little (perhaps an acceptable tradeoff?).
These should reduce the information you need per instance to just the modelMatrix and perhaps the normalMatrix, already reducing it by half. Maybe you only have a different position per instance? In that case even a simple vec4 will do.
Basically, try to think about what data you actually need to update per instance and you'll most likely be surprised as to how much data you actually need for each instance.
One can store the per-instance data in uniform arrays, uniform buffer objects or texture buffer objects and use the gl_InstanceID variable in GLSL to access the data in the buffer object. Uniform arrays might seem the easiest, but are most limited in size and hence are only applicable for a low number of instances. UBOs can be a bit bigger, but are also quite limited. TBOs on the other hand will allow you many megabytes of data, but you have to appropriately pack your data there. In your case, it seems that you only need float types, so a base format with 32 bit floats should suffice.
What is the purpose of semantics?
if I had a vertex layout like this:
struct VS_Input
{
float4 position : COLOR;
float4 color : POSITION;
};
Would it actually matter that I reversed the semantics on the two members?
If I have to send Direct3D a struct per vertex, why couldn't it just copy my data as is?
If I provide direct3D with a vertex with a layout that doesn't match that of the shader, what will happen? for example, if I pass the following vertex into the above shader?
struct MyVertex
{
Vec4 pos;
Vec2 tex;
Vec4 col;
};
In the D3D documentation, it said that a warning will be produced, and that my data will be "reinterpreted"
Does that mean "reinterpreted" as in reinterpret_cast<>? like, my shader will try to use the texture coordinates and half of the color as the color in the shader? or will it search my vertex layout for the element that matches each semantic and shuffle the input into the right places to make the shader work?
And if the above is not true, then why does D3D require an explicit vertex layout?
Semantics are used to bind your vertex buffers to your shader inputs. In D3D11 you have buffers which are just chunks of memory to store data in, shaders which have an input signature describing the inputs they expect and input layouts which represent the binding between buffers and shaders and describe how the data in your buffers is to be interpreted. The role of the semantic is just to match elements in the buffer layout description with the corresponding shader inputs, the names are not really important as long as they match up.
It's up to you to correctly specify the layout of your vertex data when you create an input layout object. If your input layout doesn't match the actual layout in memory of your data then it will be effectively like using reinterpret_cast and you'll render garbage. Providing your semantics match up correctly between your input elements and your shader input however they will be correctly bound and things like the order of elements don't matter. It's the semantics that describe how data elements from the vertex buffer are to be passed to the inputs of a shader.
I'm trying to write a shader using cg (for ogre3d). I can't seem to parse a working shader that I'd like to use as a starting point for my own code.
Here's the declaration for the shader:
void main
(
float2 iTexCoord0 : TEXCOORD0,
out float4 oColor : COLOR,
uniform sampler2D covMap1,
uniform sampler2D covMap2,
uniform sampler2D splat1,
uniform sampler2D splat2,
uniform sampler2D splat3,
uniform sampler2D splat4,
uniform sampler2D splat5,
uniform sampler2D splat6,
uniform float splatScaleX,
uniform float splatScaleZ
)
{...}
My questions:
iTexCoord0 is obviously an input parameter. Why is it not declared uniform?
(oColor is obviously an output parameter. No question)
covMap1 - splat6 are textures. Are these parameters or something loaded into the graphics card memory (like globals)? The ogre definition for the shader program doesn't list them as parameters.
Are splatScaleX and splatScaleZ also parameters? The ogre definition for the shader program also doesn't list these as parameters.
Does the order of declaration mean anything when sending values from an external program?
I'd like to pass in an array of floats (the height map). I assume that would be
uniform float splatScaleZ,
uniform float heightmap[1024]
)
{...}
If I don't pass one of the parameters will the shader just not be executed (and my object will be invisible because it has no texture)?
Is there a better way to debug these than just hit/miss and guess?
iTexCoord0 is obviously an input parameter. Why is it not declared uniform?
Uniforms are not the same things as input parameters. iTexCoord is a varying input, which is to say that for every vertex, it can have a unique value. This is set with commands like glVertexAttribPointer. Things like vertex coordinates, normals, texcoords, vertex colors, are examples of what you might use a varying input for.
Uniforms are the other hand are intended to be static for an entire draw call, or potentially for the entire frame or life of the program. They are set with glUniform* commands. A uniform might be something like the modelview matrix for an object, or the position of the sun for a lighting calculation. They don't change very often.
[edit] These specific commands I think actually work with GLSL, but the theory should be the same for CG. Lookup a cg specific tutorial to figure out the exact commands to set varyings and uniforms.
covMap1 - splat6 are textures. Are these parameters or something loaded into the graphics card memory (like globals)? The ogre definition for the shader program doesn't list them as parameters.
My CG is a little rusty, but if its the same as GLSL then the sampler2d is a uniform that takes an index that represent which sampler you want to sample from. When you do something like glActiveTexture(GL_TEXTURE3), glBindTexture(n), then you set the sampler uniform to "3" you can sample from that texture.
Does the order of declaration mean anything when sending values from an external program?
No, the variables are referred to in the external program by their string variable names.
If I don't pass one of the parameters will the shader just not be executed (and my object will be invisible because it has no texture)?
Unknown. They will likely have "some" initial value, though whether that makes any sense and will generate anything visible is hard to guess.
Is there a better way to debug these than just hit/miss and guess?
http://http.developer.nvidia.com/CgTutorial/cg_tutorial_appendix_b.html
See section B.3.8