Shader Uniforms

BlitzMax Forums/OpenGL Module/Shader Uniforms

DI(Posted 2016) [#1]
Hi!

How do you programmatically set the values of a uniform sampler2D?

I have tested some examples I've found, but I couldn't get any of them to work :(

Thanks for any help! ^^


col(Posted 2016) [#2]
Hiya,

Rather than parrot from the manual...
This may help, there's a code example near the bottom of the page.

If you get stuck feel free to ask for more info.


DI(Posted 2016) [#3]
Hi Col! Thanks so much for your answer!

I guess you are referring to:



The problem is: I'm really confused...

I have a special shader type called TShader(Which I got from this forum post, thank you tomToad!). And in that type there's some cool functions which allows me to fetch the position of a uniform and set the value of a float uniform, that looks like this:
'Get the location of a shader uniform type
Method GetUniform:Int(UniformName:String)
	Local CString:Byte Ptr = UniformName.ToCString()
	Local Uniform:Int = glGetUniformLocationARB(ProgramObject,CString)
	MemFree CString
	Return Uniform
End Method

'Will set a uniform float to specified value
Method SetUniform1f(Uniform:Int,Value:Float)
	glUniform1fARB(Uniform,Value)
End Method


If it's not to much to ask for, would you mind providing me with similar function(s) for setting a uniform sampler2D?
It would mean the world to me :)

I have worked a lot with glsl shaders before, I have even made some ray marching examples!
But I'm very new to working on the layer above: openGL. So this is very exciting and scary at the same time!

~ DI


col(Posted 2016) [#4]
Hiya

TomToads example is using the deprecated 'fixed-function' approach. In fact Blitzmax uses the fixed function stuff throughout and fortunately, to some degree, you can use the old with some of the new.

If you want to use newer versions of glsl then you're probably better off to use Bruceys NG version of BlitzMax as most of the donkey work has is done with regards to setting up the gl context, anyway...

Using the 'fixed-function' pipeline approach a sampler2D is bound to the pipeline state via glActiveTexture - it sets the currently bound texture unit ( the sampler ), then you bind the current texture for that texture unit to use via glBindTexture. Max2D pretty much sets up the pipeline state for you so you can just bind your shader and use DrawImage. ( I don't think Max2D even uses glActiveTexture as there is a default texture unit already bound )

To do things in line with your example using the TShader from the linked post...




DI(Posted 2016) [#5]
Hi!

But if my fragment shader contained multiple uniform sampler2Ds? How would I go about binding different TImages to specific samplers?

For example: the folowing shader:

uniform sampler2D texture0;
uniform sampler2D texture1;
uniform sampler2D texture2;
varying vec2 texcoord;
void main(void) {
    gl_FragColor = (texture2D(texture0, texcoord) +
                    texture2D(texture1, texcoord) +
                    texture2D(texture2, texcoord)) / 3.0;

}


I have noticed that blitzmax will automatically bind the textures between Shader.Start() and Shader.Stop() to texture0. But how do I bind TImages to texture1 and texture2?

Thank you so much for your time!
I appreciate it! :)


col(Posted 2016) [#6]
Hey,

In your case of multi-texturing then yes you will need to set each sampler via extracting the uniform locations.

I think your confusion comes from getting a 'sampler' mixed up with a 'texture'. You should change your mindset of the sampler2D being a texture as its not actually a texture, its a texture sampling unit. In the gpu a sampler unit can sample a texture in a variety of ways which is set using the glTexParameteri function. The point being that a sampler and a texture are 2 completely different enitities. You set up the sampler and then give it ( or bind in gl terms ) a texture that it will sample from.

In your example you would use

' set the shader to the current bound shader
Shader.Start

' get the uniform locations
Local sampler0:Int = Shader.GetUniform("texture0")
Local sampler1:Int = Shader.GetUniform("texture1")
Local sampler2:Int = Shader.GetUniform("texture2")

' set the sampler uniforms to the texture units
glUniform1i(sampler0, 0)
glUniform1i(sampler1, 1)
glUniform1i(sampler2, 2)

' activate texture unit 0
glActiveTexture( GL_TEXTURE_0 )
' and bind mytexture0 to texture unit 0 ( or sampler unit 0 )
glBindTexture( GL_TEXTURE_2D, mytexture0 )

glActiveTexture( GL_TEXTURE_1 )
glBindTexture( GL_TEXTURE_2D, mytexture1 )

glActiveTexture( GL_TEXTURE_2 )
glBindTexture( GL_TEXTURE_2D, mytexture2 )


So now of course the trick is where do you get mytexture0, mytexture1 and mytexture2 from? :p
They will be the handles in the image frame created by a DrawImage call. DrawImage will create the gpu texture upon its first call and with some casting you can get the image handle ( or 'name' as gl prefers to call it ) using...

Local gltexturename:Int = TGLImageFrame(myimage.frames[0]).name


Putting everything together and building on the previous example you get...







I guess you could comment out the texture0 and sampler0 stuff as they are by set by Max2D but yeah, they are here for completeness.

I'll leave you to create your own methods/functions to tuck the relevant code bits into as you see fit :O)


DI(Posted 2016) [#7]
Thank you so much Col!
Everything seems so clear and simple now!

This is why I love this community! ^^

Thank you yet again for your time Col!

~ DI