• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Shaders [SOLVED] Normal Map Shader Coordinate System Problem

A

Austin Scola

Guest
Hey I am trying to use a shader to add simple normal map lighting to my game. I am about 90% there, but there seems to be a discrepancy between the game coordinate system and my shader's coordinate system, and I can't seem to wrap my head around how to get them to line up. I know that it probably has something to do with which gm_matrix I need to multiply by, and I have tried to figure it out in the docs with no success. If anybody could help me out or point me in the right direction (no pun intended) I would greatly appreciate it!

This is the sort of result I am getting:

The location of the light is on the border of the light/dark region (NOT in the middle of the bright region) and it seems to be pointing in the wrong direction?

Here is my vertex code:
Code:
attribute vec3 in_Position;                  // (x,y,z)
//attribute vec3 in_Normal;                  // (x,y,z)     unused in this shader.
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)

varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vPosition;

void main()
{
    vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
   
    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
    v_vPosition = (gm_Matrices[MATRIX_WORLD] * object_space_pos).xyz;
}
Here is my fragment code:
Code:
/// Normal Map Lighting Shader
// slighly modified from https://github.com/mattdesl/lwjgl-basics/wiki/ShaderLesson6#GeneratingNormals

// attributes from vertex shader
varying vec4 v_vColour;
varying vec2 v_vTexcoord;
varying vec3 v_vPosition;

// our texture samplers
// gm_BaseTexture is the diffuse map
uniform sampler2D normal_texture;   //normal map

// values used for shading algorithm...
uniform vec2 Resolution;      //resolution of screen
uniform vec3 LightPos;        // light position in pixels
uniform vec4 LightColor;      //light RGBA -- alpha is intensity
uniform vec4 AmbientColor;    //ambient RGBA -- alpha is intensity
uniform vec3 Falloff;         //attenuation coefficients

void main()
{
    // RGBA of our diffuse color
    vec4 DiffuseColor = texture2D(gm_BaseTexture, v_vTexcoord);

    // RGB of our normal map
    vec3 NormalMap = texture2D(normal_texture, v_vTexcoord).rgb;
    
    // the delta position of the light   
    vec3 LightDir = LightPos - v_vPosition;
    
    // Determine distance (used for attenuation) BEFORE we normalize our LightDir
    float D = length(LightDir);
    
    // normalize our vectors
    vec3 N = normalize(NormalMap * 2.0 - 1.0); // convert to range -1.0 to 1.0, then normalize
    vec3 L = normalize(LightDir);

    // Pre-multiply light color with intensity
    // Then perform "N dot L" to determine our diffuse term
    vec3 Diffuse = (LightColor.rgb * LightColor.a) * clamp(dot(N, L), 0.0, 1.0);

    // pre-multiply ambient color with intensity
    vec3 Ambient = AmbientColor.rgb * AmbientColor.a;

    // calculate attenuation
    float Attenuation = 1.0 / ( Falloff.x + (Falloff.y*D) + (Falloff.z*D*D) );

    // the calculation which brings it all together
    vec3 Intensity = Ambient + Diffuse * Attenuation;
    vec3 FinalColor = DiffuseColor.rgb * Intensity;
    gl_FragColor = v_vColour * vec4(FinalColor, DiffuseColor.a);
}

Here is the code that calls the shader from the object:
Code:
/// @description Call the normal map shader
shader_set(shd_normal_map);

// get uniform handles
resolution = shader_get_uniform(shd_normal_map, "Resolution")
light_pos = shader_get_uniform(shd_normal_map, "LightPos")
light_color = shader_get_uniform(shd_normal_map, "LightColor")
ambient_color = shader_get_uniform(shd_normal_map, "AmbientColor")
falloff = shader_get_uniform(shd_normal_map, "Falloff")

//provide the normal map to the shader
t_normal_map = shader_get_sampler_index(shd_normal_map, "normal_texture");
spr = sprite_get_texture(spr_wall_normal, 0); //second number is the subimage!
texture_set_stage(t_normal_map, spr);

// set the uniforms
shader_set_uniform_f(resolution, 1024.0,768.0)
shader_set_uniform_f(light_pos, mouse_x, mouse_y, -10.0)
shader_set_uniform_f(light_color, 1.0, 0.8, 0.6, 1000.0)
shader_set_uniform_f(ambient_color, 0.6, 0.6, 1.0, 0.2)
shader_set_uniform_f(falloff, 4.0, 3.0, 1.0)

draw_self();
shader_reset();
 

kraifpatrik

(edited)
GameMaker Dev.
So I've tried it out in GMS2 and this is what I got:

result.png

The code is working, all I did is tick "Separate Texture Page" for the textures and change the light z position from -10 to 10.
 
A

Austin Scola

Guest
So I've tried it out in GMS2 and this is what I got:

View attachment 10802

The code is working, all I did is tick "Separate Texture Page" for the textures and change the light z position from -10 to 10.
Wow, can't believe I overlooked th z value. Will have to look up separate texture page in the manual tho. Thank you!
 
B

bilouw

Guest
Hey,

i want to make a normal map shader too! I find this one which is the same that you followed but for pixel art : https://github.com/mattdesl/kami-demos/blob/master/src/normals-pixel
The problem is that code is Javascript, and i don't know exactly how integrate this in GM. For the shader is prettry simple, just copy paste the vertex and fragment part, but then i don't understand how to properly call the shader. When i try with your code above, the result is just a black screen, i can't see the wall. If a desactivate the shader i see the wall, so it seems to miss me something ... can you help me :)?

Thanks.

EDIT : Ok so with your code, i get to the same result that you! So it seems to be the shader i choose who doesn't work?
 
D

Dronife

Guest
Hello everyone, sorry for bothering you all, but is there a chance to add multiple light sources? Sincerely Dronife
 
J

Janey_Springs

Guest
So I've tried it out in GMS2 and this is what I got:

View attachment 10802

The code is working, all I did is tick "Separate Texture Page" for the textures and change the light z position from -10 to 10.
You can upload this demo GMS 2 project on Github. I can't understand how it works. It will be useful to study. Thanks!
 
Top