Multi-Texturing with Shaders

BlitzMax Forums/MiniB3D Module/Multi-Texturing with Shaders

FBEpyon(Posted 2014) [#1]
Hello,

Can someone help me out with some multi-texturing with shaders, I'm trying to do a 2d style transportation simulator with a modern 3d twist, and I have gotten my shader module to work, but I don't understand how to get multi-texturing to work correctly. Does anyone have an example of this working..?

Thanks,

FBEpyon


Kryzon(Posted 2014) [#2]
To perform multi-texturing in a shader you just have to use more than one texture sampler simultaneously. One texture is uploaded to texture unit zero, another to one, two etc. and you assign each uniform sampler an index from the texture unit that it should sample.
https://www.opengl.org/wiki/Sampler_(GLSL)#Binding_textures_to_samplers

Then you sample the textures with the same vertex UV and blend between the samples in any way you want. You can add them, multiply, subtract, interpolate etc.
Take care not to surpass the maximum amount of texture units given by the GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS constant.

You will find information on this throughout the web.
http://www.ozone3d.net/tutorials/glsl_texturing_p03.php
http://www.clockworkcoders.com/oglsl/tutorial8.htm
https://www.opengl.org/discussion_boards/showthread.php/126089-glActiveTextureARB-and-glClientActiveTextureARB?p=955928&viewfull=1#post955928


FBEpyon(Posted 2014) [#3]
Thanks Kryzon,

My major concern is that in order to use multitexturing and thing you have to assign the MultiTexture and I'm not sure where to place that when using MiniB3d..

https://www.opengl.org/sdk/docs/man2/xhtml/glMultiTexCoord.xml

Thanks,

FBEpyon


Kryzon(Posted 2014) [#4]
What do you mean with "assign the MultiTexture?"

The glMutiTexCoord function is an immediate mode function, it is placed between glBegin() and glEnd().
MiniB3D uses the retained mode. It renders objects with DrawElements(), so that function can't be used.

MiniB3D already implements multitexturing like Blitz3D does. A brush can have several layers of textures that are blended with each other. In TMesh.Update(), it takes care of uploading each texture that a brush has before rendering the surface painted with it.
The only thing needed for multitexturing with a shader is to use your shader program and assign the texture unit indexes for each uniform sampler of your shader, like I described in post #2.

First of all, you need to decide if you will use the ARB versions of the functions to keep in line with MiniB3D, as it also uses the ARB version of other functions so it supports older versions of OpenGL down to 1.1, or if you will use the OpenGL 2.0 versions of the functions.
The name and the usage is slightly different. If you don't know which to use, you can check if the major version of the OpenGL context is "2" or higher and use the 2.0 functions, and if not you use the ARB functions. This you can find out with THardwareInfo.GetInfo() -> THardwareInfo.OGLVersion (it's a string where the first character is the number for the major version).

You can resort to the LightHouse3D guide to know how to operate the ARB or the 2.0 versions.
Make sure to read this: http://www.lighthouse3d.com/opengl/glsl/index.php/index.php?ogloverview

The fragment shader for the code that follows:
uniform sampler2D texture0;
uniform sampler2D texture1;
uniform sampler2D texture2;

void main (void)
{
	vec4 color0 = texture2D( texture0, gl_TexCoord[0].st);
	vec4 color1 = texture2D( texture1, gl_TexCoord[0].st);
	vec4 color2 = texture2D( texture2, gl_TexCoord[0].st);
	
	// ADDing the sampled colours together. They could also be multiplied, alpha blended etc.

	gl_FragColor = color0 + color1 + color2;
}

You will create the shader object and the program object and retrieve the uniform locations in BlitzMax.
Below is the 2.0 version:
'[...] After you have created the shader object, compiled the source, attached to a program object and linked the program.
 
'Getting the uniform locations.

Local layer0Loc:Int = glGetUniformLocation( program, "texture0") 'Uniform names as in the shader code.
Local layer1Loc:Int = glGetUniformLocation( program, "texture1")
Local layer2Loc:Int = glGetUniformLocation( program, "texture2")

'Setting the texture unit indexes for the uniforms.

glUniform1i( layer0Loc, 0) 'Each number is the texture unit index.
glUniform1i( layer1Loc, 1)
glUniform1i( layer2Loc, 2)

Then when rendering your shaded mesh you need to use your shader program. You don't need to restore, modify or update the uniform values if they are the same.
When you use a program, the uniform values for that program are restored.
glUseProgram( program )
The mesh for this has one or more surfaces, and each surface has a brush with exactly THREE LAYERED TEXTURES, starting from the first index (zero). If this is not properly set up there will be errors since the shader code is expecting the first three texture units to be available.

A brush is set with three textures like the following:

myBrush.BrushTexture( textureA, 0, 0 )
myBrush.BrushTexture( textureB, 0, 1 )
myBrush.BrushTexture( textureC, 0, 2 )
'Then PaintEntity() or PaintSurface()

Or you can set on the mesh directly:

EntityTexture( myMesh, textureA, 0, 0 )
EntityTexture( myMesh, textureB, 0, 1 )
EntityTexture( myMesh, textureC, 0, 2 )

But I'm not sure if mixing MiniB3D directly with shaders is going to work.


FBEpyon(Posted 2014) [#5]
OKay well I got it working, but whats funny the shader for the textures only works on my Intel 4000 Graphics card, and won't work on my GTX660 on my desktop


Kryzon(Posted 2014) [#6]
http://www.opengl.org/wiki/Shader_Compilation#Shader_error_handling
http://www.opengl.org/wiki/OpenGL_Error

SetGraphicsDriver GLMax2DDriver()
Graphics( 800, 600 )

Local maxUnits:Int
glGetIntegerv( GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, Varptr( maxUnits ) )

Print maxUnits 'Maximum combined textures at once for this graphics card.

End



FBEpyon(Posted 2014) [#7]
Error Code:

fragment: 0(1) : error C0000: syntax error, unexpected identifier, expecting '{' at token "grass"




UPDATE

I was able to fix it finally!! It was a typo with the sampler2d it was suppose to be sampler2D. Sorry :(


Kryzon(Posted 2014) [#8]
Good job.

If you're on Windows or Linux, you can use this shader IDE to help debugging and avoid keyword case problems:
http://www.opengl.org/sdk/tools/ShaderDesigner/

It is simple and easy to use.