Graphics Multi Texture Shader for use in 3D

Discussion in 'Tutorials' started by Kentae, Aug 8, 2017.

  1. Kentae

    Kentae Member

    Sep 24, 2016
    GM version: Game Maker Studio 1.4
    Target Platform: Windows, but can probably be used for more than that.
    Last Updated: 08 / 08 / 2017

    For so long did I try to find a multi texture code or shader or tutorial or whatever but I could never find one for Game Maker. However, not to long ago I found a tutorial on how to create a multi texture shader on youtube. It was for use with java though so I needed to convert it for use in Game Maker and I have fianlly succeded.

    Here I will show you the code needed and some images to help me explain how it all works.
    (Not quite sure if this can be called a tutorial but I didn't really find any place more suited for this on the forum)

    First I want to show you guys what to expect, in other words an image that shows the shader in use:

    Pretty neat huh? These are just some textures I found on google for testing btw, you can of course use your own if you want. Just make sure that the resolution is a power of 2,
    and so on...
    and also all you textures, including the blendmap, must have the Used for 3D box checked.

    What do you need:
    To use this shader you need 4 textures, like grass, dirt, stone and road as in the image above or anything else you might want.
    You also need a blendMap, wich looks like this:
    I know this isn't the best example as all that is going on in it is consentrated up in the top-left corner but it is the one used to create the effect you see on the example-image so I thought it would be appropriate.

    How does it work:
    The blendmap is basically, well, a map that determines where the diffrent textures should be shown.
    The diffrent textures are all linked to the RGB values of the blendmap, for example, dirt will only be drawn where the blendmap is colored RED and stone will only be drawn where the blendmap is GREEN and so on.
    You will need to set one of your textures as the base texture, wich will be drawn everywhere the blendmap shows black. It is usually best to set the most common texture as your base, like in this case it is the grass-texture.

    And that is a basic explaination of how it works. Please remember that I have simply converted this shader from one I found on youtube so if my explaining is a bit lacking it is because I did not come up with this whole solution, I just figured it was about time someone shared one that workes for Game Maker.

    How to use/The code:
    First you of course need to pass all your textures into the shader. To do that you need to get the handles of the shader samplers to use and also store your textures in variables. This is all best done in the Create Event of the terrain/world object.
    Here's the code:
    u_baseTex = shader_get_sampler_index( sh_multitex, "baseTex" );
    u_rTex = shader_get_sampler_index( sh_multitex, "rTex" );
    u_gTex = shader_get_sampler_index( sh_multitex, "gTex" );
    u_bTex = shader_get_sampler_index( sh_multitex, "bTex" );
    u_blendMap = shader_get_sampler_index( sh_multitex, "blendMap" );
    texBase = background_get_texture( tex_grass );
    texR = background_get_texture( tex_dirt );
    texG = background_get_texture( tex_stone );
    texB = background_get_texture( tex_road );
    texBM = background_get_texture( tex_terrain_map );
    Then in the Draw Event of the same object you set the shader and pass in the textures using the handles you got and the variables holding your textures.
    Here's the code:
    shader_set( sh_multitex );
    texture_set_stage( u_baseTex, texBase );
    texture_set_stage( u_rTex, texR );
    texture_set_stage( u_gTex, texG );
    texture_set_stage( u_bTex, texB );
    texture_set_stage( u_blendMap, texBM );
    d3d_set_culling( true );
    terrain_draw( tex_grass );
    d3d_set_culling( true );
    I'm actually not quite sure if you need to set a texture for your terrain or flat plane or whatever you want your textures to be drawn on like I've done here, terrain_draw( tex_grass );
    But oh well, it works, so I wont question it.

    The next step will of course be to give you the actual shadercode.
    It's worth mentioning that you don't have to do anything in the Vertex Shader for this to work as all the calculations take place in the Fragment Shader.
    Here it is:
    // Simple passthrough fragment shader
    varying vec2 v_vTexcoord;
    varying vec4 v_vColour;
    uniform sampler2D baseTex;
    uniform sampler2D rTex;
    uniform sampler2D gTex;
    uniform sampler2D bTex;
    uniform sampler2D blendMap;
    void main()
        // Get the colour of the blendMap
        vec4 blendMapCol = texture2D( blendMap, v_vTexcoord );
        // Find out how much the base texture shows through the rest (base texture is usually something like grass)
        float baseTexAmount = 1.0 - ( blendMapCol.r + blendMapCol.g + blendMapCol.b );
        // How many times the texture is repeated (Can of course be passed in as a uniform)
        vec2 tiledCoords = v_vTexcoord * 60.0;
        // Calculate how much is shown of each texture based on the blendmap
        vec4 baseTexCol = texture2D( baseTex, tiledCoords ) * baseTexAmount;
        vec4 rTexCol = texture2D( rTex, tiledCoords ) * blendMapCol.r;
        vec4 gTexCol = texture2D( gTex, tiledCoords ) * blendMapCol.g;
        vec4 bTexCol = texture2D( bTex, tiledCoords ) * blendMapCol.b;
        // Add all the textures together
        vec4 totalCol = baseTexCol + rTexCol + gTexCol + bTexCol;
        gl_FragColor = v_vColour * totalCol;
    Hopefully the comments in the code and the explaining I did earier will help you understand what is going on here :)

    And also I hope someone will find this usefull ^^
    Bart, Joe Ellis, TheWaffle and 3 others like this.

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice