First Person View Model Shader

Shader for rendering first person view models.

Similar to the method used by:

– Valve (TF2)

– Halo (Reach)

 

Shader code
// Riordan's (Kastor) FPS view shader (MIT)
shader_type spatial;
render_mode depth_draw_opaque,cull_back;

uniform float fov : hint_range(20, 120) = 40;
const float M_PI = 3.14159265359;

void vertex() {
    // recreate the camera projection matrix with our custom fov value 
    float scale = 1.0 / tan(fov * 0.5 * M_PI / 180.0); 
    PROJECTION_MATRIX[0][0] = scale / (VIEWPORT_SIZE.x / VIEWPORT_SIZE.y);
    PROJECTION_MATRIX[1][1] = scale;
}

void fragment() {
	// Scale the depth value 70%, this prevents most clipping.
	DEPTH = FRAGCOORD.z;
	DEPTH = FRAGCOORD.z * 0.7;
}
Tags
FPS
The shader code and all code snippets in this post are under MIT license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

PS1/PSX Model

FPS view shader with color/texture and metallic

Spatial View-Depending Directional Billboard

Subscribe
Notify of
guest

5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Glitshy
1 year ago

Thanks! Btw there is the function ‘radians()’ to convert from degrees to radians 😉

tower
tower
9 months ago

Just a heads up, this shader as is results in inverted rendering in Godot 4.x, due to the screen-space y coordinate being flipped in Godot 4. Here’s some amended code for it to work in Godot 4.x

void vertex() {
    // recreate the camera projection matrix with our custom fov value 
    float scale = 1.0 / tan(fov * 0.5 * M_PI / 180.0); 
    PROJECTION_MATRIX[0][0] = -scale / (VIEWPORT_SIZE.x / -VIEWPORT_SIZE.y);
    PROJECTION_MATRIX[1][1] = -scale;
}
Belzecue
Belzecue
9 months ago
shader_type spatial;

uniform float fov : hint_range(20, 120) = 40;
const float M_PI = 3.14159265359;


void vertex() {
	// recreate the camera projection matrix with our custom fov value 
	float scale = 1.0 / tan(fov * 0.5 * M_PI / 180.0); 
	PROJECTION_MATRIX[0][0] = scale / (VIEWPORT_SIZE.x / VIEWPORT_SIZE.y);
	PROJECTION_MATRIX[1][1] = scale;
	POSITION = PROJECTION_MATRIX * MODELVIEW_MATRIX * vec4(VERTEX, 1.0);
	POSITION.z = 0.1;
}

This avoids setting DEPTH in frag func, which is a performance killer (see https://twitter.com/reduzio/status/1748831423690133831)

driftware
driftware
8 months ago

this makes my model appear without textures for some reason.

Anaxim
Anaxim
7 months ago
Reply to  driftware

And appears double right? For me the original model appears too + a second model with the shader FOV and no textures. (I cant find nowhere a proper FOV shader for Godot 4.2)