View-Matcap Based Fake Vertex Lighting

Based off of Firerabbit’s View-Matcap shader.

Temporary, very hacky solution for Godot 4’s lack of vertex lighting in Vulkan renderer. Useful for Mario 64-style lighting based on camera angle. Not super versatile or accurate, but can produce interesting effects with various matcap textures. Also supports alpha-scissor transparency and billboarding, as well as a global “color_lighting” shader variable for sky color emulation.

I recommend creating a GradientTexture2D going from white to a dark grey, setting the fill mode to Radial, and playing around with it until you find a result you’re happy with.

Shader code
shader_type spatial;
render_mode cull_disabled, unshaded;
global uniform vec4 color_lighting;
uniform sampler2D base_texture: source_color, hint_default_black, filter_linear_mipmap;
uniform sampler2D matcap : source_color, hint_default_black, filter_linear_mipmap, repeat_disable; // Sampler 2d of the matcap
uniform bool use_global_lighting = false;
uniform float alpha_scissor_threshold = 0.0;
uniform bool is_billboard = false;

void vertex() {
	vec3 tempNormal = normalize((MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);//Normalize vectors relative to view
	vec2 matcap_uv = clamp(tempNormal.xy * vec2(0.5, -0.5) + vec2(0.5, 0.5), vec2(0.0), vec2(1.0));//Generate Matcap UV
	vec4 _matcap = texture(matcap, matcap_uv).rgba; //Matcap Texture
	COLOR = _matcap.rgba; //Set vertex color to Matcap Color
	//Billboarding
	if (is_billboard){
	    mat4 modified_model_view = VIEW_MATRIX * mat4(
	        INV_VIEW_MATRIX[0],
	        INV_VIEW_MATRIX[1],
	        INV_VIEW_MATRIX[2],
	        MODEL_MATRIX[3]
	    );
	    MODELVIEW_MATRIX = modified_model_view;
		MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(
			vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0),
			vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0),
			vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0),
			vec4(0.0, 0.0, 0.0, 1.0));
		MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);
	}
}

void fragment() {
	vec4 _tex = texture(base_texture, UV);
	ALBEDO = (_tex * COLOR).rgb;
	//Global lighting
	if (use_global_lighting){
		ALBEDO = ALBEDO * color_lighting.rgb;
	}
	if (_tex.a < alpha_scissor_threshold){
		discard;
	}
}

//void light() {
	// Called for every pixel for every light affecting the material.
	// Uncomment to replace the default light processing function with this one.
//}
Tags
matcap, N64, vertex lighting
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.

More from ANDROGYNESERAPH

Simple Ordered Dithering and Screen Pixelation

Related shaders

Updated: Faux Vertex Lighting

PSX Shader with Vertex Lighting

Fake Interior Shader

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Calinou
1 month ago

Vertex shading has been reimplemented in 4.4.dev3 and later: https://github.com/godotengine/godot/pull/83360