Shaders Effect only works at position 0,0,0 [SOLVED]

Kentae

Member
Hi guys, I need some fresh eyes on this... Preferably someone who understands shaders better than me.

So I'm trying to add a fresnel effect to a spaceship model and it works as it should for as long as the ship is at position x = 0, y = 0, z = 0.

But whenever I move the ship the effect kind of stays behind, if that makes any sense.

Anyway, here's the code:
Draw
Code:
// Render Player.
with ( obj_player )
    {
    shader_set( test );
    shadeTest = shader_get_uniform( test, "cameraPos" );
    shader_set_uniform_f( shadeTest, kt_camera_get_x_from(), kt_camera_get_y_from(), kt_camera_get_z_from() );
   
    d3d_transform_set_identity();
    d3d_transform_add_quat( quat_w, quat_x, quat_y, quat_z );
    d3d_transform_add_translation( x, y, z );
   
    vertex_submit( global.test_model, pr_trianglelist, background_get_texture( tex_test ) );
   
    d3d_transform_set_identity();
   
    shader_reset();
    }
I draw the player (or ship) from a master render object here.

Shader Vertex
Code:
//
// Simple passthrough vertex shader
//
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 vec3 v_vPosition;
varying vec3 v_vNormal;
varying vec4 v_vColour;
varying vec2 v_vTexcoord;
varying vec2 v_vTexcoord2;

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_vPosition = in_Position;
    v_vNormal = ( gm_Matrices[MATRIX_WORLD] * vec4( in_Normal, 0.0 ) ).xyz;
    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
    v_vTexcoord2 = normalize( ( gm_Matrices[MATRIX_WORLD_VIEW] * vec4( in_Normal, 0.0 ) ).xyz ).xy / 2.0 + 0.5;
}
Shader Fragment
Code:
//
// Simple passthrough fragment shader
//
varying vec3 v_vPosition;
varying vec3 v_vNormal;
varying vec4 v_vColour;
varying vec2 v_vTexcoord;
varying vec2 v_vTexcoord2;

uniform vec3 cameraPos;

void main()
{
    // Calculate the to camera vector.
    vec3 toCameraVec = cameraPos - v_vPosition;
   
    vec4 Col = vec4( 1.0, 0.2, 0.2, 1.0 );
    vec4 Tex = texture2D( gm_BaseTexture, v_vTexcoord2 );
   
   
    // Add fresnel effect.
    vec3 viewVector = normalize( toCameraVec );
    float refractiveFactor = dot( vec3( 0.0, 0.0, 1.0 ), viewVector );
    //refractiveFactor = pow( refractiveFactor, 0.5 );
   
   
    Col = mix( Tex, Col, refractiveFactor );
   
    gl_FragColor = Col;
}

I'm using the code from an enviornment mapping shader by TheSnidr to get the, seemingly, reflective surface.
I'm also using a quaternion system by TheSnidr.
The kt_camera_get_x_from (and Y Z) scripts just get the cameras from vector.

I'm using GMS 1.4.

EDIT: Woop, just realised I forgot to undo the testing I did in the Fragment shader before posting the code.
This:
float refractiveFactor = dot( vec3( 0.0, 0.0, 1.0 ), viewVector );
is supposed to be this:
float refractiveFactor = dot( v_vNormal, viewVector );
 
I don't understand what this is supposed to do:

v_vTexcoord2 = normalize( ( gm_Matrices[MATRIX_WORLD_VIEW] * vec4( in_Normal, 0.0 ) ).xyz ).xy / 2.0 + 0.5;

I would compute the texture coordinates based on the reflection angle:

vec3 viewVector = normalize( toCameraVec );
vec3 R = reflect( -viewVector, normalize(v_vNormal));
vec2 uv = 0.5 + vec2(atan(R.x, R.y) / 6.2831853, asin(-R.z) / 3.1415629);
vec4 Tex = texture2D( gm_BaseTexture, uv );
float refractiveFactor = dot(v_vNormal,viewVector);
Col = mix( Tex, Col, refractiveFactor );

or I guess you could compute texture coordinates similarly to what you were doing before but using the reflection vector rather than the normal vector, even though it produces somewhat strange results depending on your texture.

vec2 uv = R.xz * -0.5 + 0.5;

EDIT:

By the way, the reason you were having problems originally is because your vertex position was in model space and your camera position was in world space.

You'll want to do this in your vertex shader:

v_vPosition = (gm_Matrices[MATRIX_WORLD] * vec4(in_Position, 1.0)).xyz;

So typical of me to go off on a tangent first and then forget to address the original problem until making an edit.
 
Last edited:

Kentae

Member
v_vTexcoord2 = normalize( ( gm_Matrices[MATRIX_WORLD_VIEW] * vec4( in_Normal, 0.0 ) ).xyz ).xy / 2.0 + 0.5;
I'm not sure how that one works, it's part of the enviornment mapping. This particular part of the shader works as it should though.

It's this part that doesn't seem to work right:
Code:
// Add fresnel effect.
    vec3 viewVector = normalize( toCameraVec );
    float refractiveFactor = dot( vec3( 0.0, 0.0, 1.0 ), viewVector );
But I'm not sure :S
 
Sorry for all the editing in my previous post, but I believe the cause of your problem was because your vertex position was in model space but your camera position was in world space.

You'll want to do this in your vertex shader:

v_vPosition = (gm_Matrices[MATRIX_WORLD] * vec4(in_Position, 1.0)).xyz;
 
The problem was your camera coordinates were in world space. But your vertex position was in model space. The only time they would correspond with each other would be if the model was not translated, scaled, or rotated.
 
Top