can we use structs for uniforms in GLSL-ES - opengl-es

I am trying to use structs for the uniforms in my vertex shader in ES:
struct temp{
mat4 mvp;
};
uniform temp MP;
in vec2 inPos;
void main() {
vec4 vert = MP.mvp * vec4(inPos.x,inPos.y,0,1);
gl_Position = vert;
}
glGetUniformLocation(program, "MP.mvp");
it does not display any thing on screen, neigther any glerror. is it allowed in glsl es 300?
It works with OpenGL.

From The OpenGL ES Shading Language v3.00, in section 4.3.5 Uniform Variables it states:
The uniform qualifier can be used with any of the basic data types, or when declaring a variable whose type is a structure, or an array of any of these.
If glGetUniformLocation(program, "MP.mvp") is returning 0 or greater then what you've shared so far looks legit. You'll probably have to post more code to get to the bottom of it.
If your struct only has a mat4 in it then I would recommend just eliminating the struct altogether.

Related

How can I pass along an array of floats as a uniform to shaders from Three JS

To clarify I am using Three JS, React-Three-Fiber, React
I have disc with points mapped on it, I have calculated the distance of every point to the center of the desk and stored results in an array. I would like to pass this array to the shaders but I am struggling to understand how to do it. I read in the docs you can also pass along vec3,mat3,float essentially. My array has a length of 1000 so I cannot use it with any of the data types uniforms can be used with, if I store the array as a define how can I go about using it in the shader file?
uniforms
const uniforms = useMemo(() => ({
uTime: {
value: 0.0
},
uRadius: {
value: radius
},
uDistance: {
value: normalDistances
}
}), [])
fragment shader
const fragmentShader = `
uniform vec3 uDistance;
varying float vDistance;
void main() {
float x = uDistance[52];
vec3 color = vec3(0.5, 0.5, x);
gl_FragColor = vec4(color, 1.0);
}
`
export default fragmentShader
I cannot import a uniform without specifying the data type, and I cannot find how to import a define which was passed along from javascript. Does anyone know what my issue is? Thanks!
uniform vec3 uDistance;
This is no valid declaration of a uniform array. You always have to define the length like so:
uniform vec3 uDistance[8];
However, keep in mind that uniform arrays require a uniform vector for each entry. If you want to use a length of 1000, you easily hit the maximum supported uniform vectors on devices.
I suggest you encode your distance data into a texture and then sample it in your shader. In three.js, you can use the DataTexture class for this.

How effectively interpolate between many color attributes in GLSL ES 2.0

I'm working on project with OpenGl ES 2.0. Every vertex in my mesh has fixed number of color attributes (lets say 5). The final per-vertex color is computed as an interpolation between two selected color attributes.
In my implementation, choice of the two colors is based on two given indexes. I'm aware that if statement may by a big performance hit so a choose to put all attributes into one array and use indexing to retrieve wanted colors. Still i see a significant performance drop.
attribute vec4 a_position;
//The GLSL ES 2.0 specification states that attributes cannot be declared as arrays.
attribute vec4 a_color;
attribute vec4 a_color1;
attribute vec4 a_color2;
attribute vec4 a_color3;
attribute vec4 a_color4;
uniform mat4 u_projTrans;
uniform int u_index;
uniform int u_index1;
uniform float u_interp;
varying vec4 v_color;
void main()
{
vec4 colors[5];
colors[0] = a_color;
colors[1] = a_color1;
colors[2] = a_color2;
colors[3] = a_color3;
colors[4] = a_color4;
v_color = mix(colors[u_index], colors[u_index1], u_interp);
gl_Position = u_projTrans * a_position;
}
Is there a better more efficient way of computing the final color interpolation? Or at least a better way to choose interpolation colors?
The indices you use here are uniforms. That means every vertex in each rendering command uses the same indices. If that's the case... why do you bother fetching this stuff in the VS at all?
You should only have 2 color input values. You then use glVertexAttribPointer to pick the two arrays that will be interpolated between.
Your "significant performance drop" likely has nothing to do with how you fetch such values, and everything to do with the fact that you're sending lots of per-vertex data that never gets used for anything.

OpenGL - trouble passing ALL data into shader at once

I'm trying to display textures on quads (2 triangles) using opengl 3.3
Drawing a texture on a quad works great; however when I have ONE textures (sprite atlas) but using 2 quads(objects) to display different parts of the atlas. When in draw loop, they end up switching back and fourth(one disappears than appears again, etc) at their individual translated locations.
The way I'm drawing this is not the standard DrawElements for each quad(or object) but I package all quads, uv, translations, etc send them up to the shader as one big chunk (as "in" variables): Vertex shader:
#version 330 core
// Input vertex data, different for all executions of this shader.
in vec3 vertexPosition_modelspace;
in vec3 vertexColor;
in vec2 vertexUV;
in vec3 translation;
in vec4 rotation;
in vec3 scale;
// Output data ; will be interpolated for each fragment.
out vec2 UV;
// Output data ; will be interpolated for each fragment.
out vec3 fragmentColor;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
...
void main(){
mat4 Model = mat4(1.0);
mat4 t = translationMatrix(translation);
mat4 s = scaleMatrix(scale);
mat4 r = rotationMatrix(vec3(rotation), rotation[3]);
Model *= t * r * s;
gl_Position = MVP * Model * vec4 (vertexPosition_modelspace,1); //* MVP;
// The color of each vertex will be interpolated
// to produce the color of each fragment
fragmentColor = vertexColor;
// UV of the vertex. No special space for this one.
UV = vertexUV;
}
Is the vertex shader working as I think it would with a large chunk of data - that it draws each segment passed up as uniform individually because it does not seem like it? Is my train of thought correct on this?
For completeness this is my fragment shader:
#version 330 core
// Interpolated values from the vertex shaders
in vec3 fragmentColor;
// Interpolated values from the vertex shaders
in vec2 UV;
// Ouput data
out vec4 color;
// Values that stay constant for the whole mesh.
uniform sampler2D myTextureSampler;
void main()
{
// Output color = color of the texture at the specified UV
color = texture2D( myTextureSampler, UV ).rgba;
}
A request for more information was made so I will put how i bind this data up to the vertex shader. The following code is just one I use for my translations. I have more for color, rotation, scale, uv, etc:
gl.BindBuffer(gl.ARRAY_BUFFER, tvbo)
gl.BufferData(gl.ARRAY_BUFFER, len(data.Translations)*4, gl.Ptr(data.Translations), gl.DYNAMIC_DRAW)
tAttrib := uint32(gl.GetAttribLocation(program, gl.Str("translation\x00")))
gl.EnableVertexAttribArray(tAttrib)
gl.VertexAttribPointer(tAttrib, 3, gl.FLOAT, false, 0, nil)
...
gl.DrawElements(gl.TRIANGLES, int32(len(elements)), gl.UNSIGNED_INT, nil)
You have just single sampler2D
which means you have just single texture at your disposal
regardless on how many of them you bind.
If you really need to pass the data as single block
then you should add sampler per each texture you got
not sure how many objects/textures you have
but you are limited by gfx hw limit on texture units with this way of data passing
also you need to add another value to your data telling which primitive use which texture unit
and inside fragment then select the right texture sampler ...
You should add stuff like this:
// vertex
in int usedtexture;
out int txr;
void main()
{
txr=usedtexture;
}
// fragment
uniform sampler2D myTextureSampler0;
uniform sampler2D myTextureSampler1;
uniform sampler2D myTextureSampler2;
uniform sampler2D myTextureSampler3;
in vec2 UV;
in int txr;
out vec4 color;
void main
{
if (txr==0) color = texture2D( myTextureSampler0, UV ).rgba;
else if (txr==1) color = texture2D( myTextureSampler1, UV ).rgba;
else if (txr==2) color = texture2D( myTextureSampler2, UV ).rgba;
else if (txr==3) color = texture2D( myTextureSampler3, UV ).rgba;
else color=vec4(0.0,0.0,0.0,0.0);
}
This way of passing is not good for these reasons:
number of used textures is limited to HW texture units limit
if your rendering would need additional textures like normal/shininess/light maps
then you need more then 1 texture per object type and your limit is suddenly divided by 2,3,4...
You need if/switch statements inside fragment which can slow things down considerably
Yes you can do it brunch less but then you would need to access all textures all the time increasing heat stress on gfx without reason...
This kind of passing is suitable for
all textures inside single image (as you mentioned texture atlas)
which can be faster this way and reasonable for scenes with small number of object types (or materials) but large object count...
Since I needed more input on this matter, I linked this page to reddit and someone was able to help me with one response! Anyways the reddit link is here:
https://www.reddit.com/r/opengl/comments/3gyvlt/opengl_passing_all_scene_data_into_shader_each/
The issue of seeing two individual textures/quads after passing all vertices as one data structure over to vertex shader was because my element indices were off. I needed to determine the correct index of each set of vertices for my 2 triangle(quad) objects. Simply had to do something like this:
vertexInfo.Elements = append(vertexInfo.Elements, uint32(idx*4), uint32(idx*4+1), uint32(idx*4+2), uint32(idx*4), uint32(idx*4+2), uint32(idx*4+3))

SceneKit painting on texture with texture coordinates

I have a Collada model that I load into SceneKit. When I perform a hittest on the model I am able to retrieve the texture coordinates of the model that was hit.
With these texture coordinates I should be able to replace texture coordinates with a color.
So this way I should be able to draw on the model
Correct me if I am wrong so far.
I read a lot of articles till now but I just don't get my shaders right.
( Though I did get some funky effects ;-)
My vertex shader :
precision highp float;
attribute vec4 position;
attribute vec2 textureCoordinate;
attribute vec2 aTexureCoordForColor; //coordinates from the hittest
uniform mat4 modelViewProjection;
varying vec2 aTexureCoordForColorVarying; // passing to the fragment shader here
varying vec2 texCoord;
void main(void) {
// Pass along to the fragment shader
texCoord = textureCoordinate;
aTexureCoordForColorVarying = aTexureCoordForColor; //assigning here
// output the projected position
gl_Position = modelViewProjection * position;
}
my fragment shader
precision highp float;
uniform sampler2D yourTexture;
uniform vec2 uResolution;
uniform int uTexureCoordsCount;
varying vec2 texCoord;
varying vec2 aTexureCoordForColorVarying;
void main(void) {
// ??????????? no idea anymore what to do here
gl_FragColor = texture2D(yourTexture, texCoord);
}
If you need more code please let me know.
First, shaders aren't the only way to draw onto an object's material. One other option that might work well for you is to use a SpriteKit scene as the material's contents — see this answer for some help with that.
If you stick to the shader route, you don't need to rewrite the whole shader program just to paint on top of the existing texture. (If you do, you lose things that SceneKit's program provides for you, like lighting and bump mapping. No sense reinventing those wheels unless you really want to.) Instead, use a shader modifier — a little snippet of GLSL that gets inserted into the SceneKit shader program. The SCNShadable reference explains how to use those.
Third, I'm not sure you're providing the texture coordinates to your shader in the best way. You want every fragment to get the same texcoord value for the clicked point, so there's little point to passing it into GL as an attribute and interpolating it between the vertex and fragment stages. Just pass it as a uniform, and set that uniform on your material with key-value coding. (See the SCNShadable reference again for info on binding shader parameters with KVC.)
Finally, to get at the main point of your question... :)
To change the output color of the fragment shader (or shader modifier) at or near a particular set of texture coordinates, just compare your passed-in click coordinates to the current set of texcoords that'd be used for the regular texture lookup. Here's an example that does that, going the shader modifier route:
uniform vec2 clickTexcoord;
// set this from ObjC/Swift code with setValue:forKey:
// and an NSValue with CGPoint data
uniform float radius = 0.01;
// change this to determine how large an area to highlight
uniform vec3 paintColor = vec4(0.0, 1.0, 0.0);
// nice and green; you can change this with KVC, too
#pragma body
if (distance(_surface.diffuseTexcoord.x, clickTexcoord.x) < radius) {
_surface.diffuse.rgb = paintColor
}
Use this example as a SCNShaderModifierEntryPointSurface shader modifier and lighting/shading will still be applied to the result. If you want your paint to override lighting, use a SCNShaderModifierEntryPointFragment shader modifier instead, and in the GLSL snippet set _output.color.rgb instead of _surface.color.rgb.

GLSL: gl_FragCoord issues

I am experimenting with GLSL for OpenGL ES 2.0. I have a quad and a texture I am rendering. I can successfully do it this way:
//VERTEX SHADER
attribute highp vec4 vertex;
attribute mediump vec2 coord0;
uniform mediump mat4 worldViewProjection;
varying mediump vec2 tc0;
void main()
{
// Transforming The Vertex
gl_Position = worldViewProjection * vertex;
// Passing The Texture Coordinate Of Texture Unit 0 To The Fragment Shader
tc0 = vec2(coord0);
}
//FRAGMENT SHADER
varying mediump vec2 tc0;
uniform sampler2D my_color_texture;
void main()
{
gl_FragColor = texture2D(my_color_texture, tc0);
}
So far so good. However, I'd like to do some pixel-based filtering, e.g. Median. So, I'd like to work in pixel coordinates rather than in normalized (tc0) and then convert the result back to normalized coords. Therefore, I'd like to use gl_FragCoord instead of a uv attribute (tc0). But I don't know how to go back to normalized coords because I don't know the range of gl_FragCoords. Any idea how I could get it? I have got that far, using a fixed value for 'normalization', though it's not working perfectly as it is causing stretching and tiling (but at least is showing something):
//FRAGMENT SHADER
varying mediump vec2 tc0;
uniform sampler2D my_color_texture;
void main()
{
gl_FragColor = texture2D(my_color_texture, vec2(gl_FragCoord) / vec2(256, 256));
}
So, the simple question is, what should I use in the place of vec2(256, 256) so that I could get the same result as if I were using the uv coords.
Thanks!
gl_FragCoord is in screen coordinates, so to get normalized coords you need to divide by the viewport width and height. You can use a uniform variable to pass that information to the shader, since there is no built in variable for it.
You can also sample the texture by un-normalized coordinates if:
sampling by texture() from GL_TEXTURE_RECTANGLE
sampling by texelFetch() from a regular texture or texture buffer

Resources