Fake Interior Shader

Updated 2022-06-08: Now supports texture for emission map!

Use a NoiseTexture to get random rooms lit up, like the old version! Some nice settings for the OpenSimplexNoise resource are 3 octaves, 2 period, 1 persistence, and 2 lacunarity.

 

Fake Interior Mapping shader for the Godot Game Engine 3.x that works with GLES3. This shader is an optimization measure used in game development to increase performance while keeping a good visual quality, This is the technique used in the Sims, Forza Horizon, Spiderman and other open-world games.

 

Learn how to use it with the creator’s guide:

https://youtu.be/thnWb5waSVc

 

For one that supports GLES2, check out OBKF’s original version on GitHub: OBKF/Fake-Interior-Shader-for-GodotEngine

Shader code
shader_type spatial;
//render_mode unshaded;

uniform vec2 rooms = vec2(1, 1);
uniform float room_seed :hint_range(0.0, 999.0, 1.0) = 0.0;
uniform vec2 atlas_rooms = vec2(1, 1);
uniform float depth :hint_range(0.0, 1.0)= 0.5;
uniform float emission_cutoff :hint_range(0.0, 1.0) = 0.5;
uniform float emission_strength :hint_range(0.0, 10.0) = 1.0;
uniform sampler2D room_texture :hint_white;
uniform sampler2D room_emit_texture :hint_black;
uniform sampler2D emission_texture :hint_black;

varying vec3 tangent_view_dir;

// psuedo random with float input
vec2 f_random(float co){
	return fract(sin((co + room_seed) * vec2(12.9898,78.233)) * 43758.5453);
}

void vertex(){
	// scale the UVs by the amount of rooms
	UV = UV*rooms;
	
	// Get camera position in World space coordinates
	vec3 cam_pos = (inverse(MODELVIEW_MATRIX) * vec4(0, 0, 0, 1)).xyz; //object space
	vec3 view_dir = VERTEX - cam_pos;
	vec3 bitangent = normalize(cross(TANGENT, NORMAL));

	// get tangent space camera vector
	tangent_view_dir = vec3(
		dot(view_dir, TANGENT),
		dot(view_dir, bitangent),
		dot(view_dir, NORMAL)
	);
}

void fragment () {
	// room uvs
	vec2 room_uv = fract(UV);
	vec2 room_index_uv = floor(UV);

	// randomize the rooms
	vec2 n = floor(f_random(room_index_uv.x + room_index_uv.y * (room_index_uv.x + 1.0)) * atlas_rooms);
	room_index_uv += n;

	// get room depth from room atlas alpha else use the Depth paramater
	float far_frac = textureLod(room_texture, (room_index_uv+0.5)/atlas_rooms, 0.0).a;
	if (far_frac == 1.0) far_frac = depth;

	float depth_scale = 1.0 / (1.0 - far_frac) - 1.0;

	// raytrace box from view dir
	vec3 pos = vec3(room_uv * 2.0 - 1.0, -1.0);
	vec3 _tangent_view_dir = tangent_view_dir;
	_tangent_view_dir.z *= -depth_scale;
	vec3 id = 1.0 / _tangent_view_dir;
	vec3 k = abs(id) - pos * id;
	float k_min = min(min(k.x, k.y), k.z);
	pos += k_min * _tangent_view_dir;

	// 0.0 - 1.0 room depth
	float interp = pos.z * 0.5 + 0.5;

	// account for perspective in "room" textures
	// assumes camera with an fov of 53.13 degrees (atan(0.5))
	float real_z = clamp(interp, 0.0, 1.0) / depth_scale + 1.0;
	interp = 1.0 - (1.0 / real_z);
	interp *= depth_scale + 1.0;

	// iterpolate from wall back to near wall
	vec2 interior_uv = pos.xy * mix(1.0, far_frac, interp);
	interior_uv = interior_uv * 0.5 + 0.5;

	// sample room atlas texture
	vec2 uv = (room_index_uv + interior_uv) / atlas_rooms;
	vec3 room = textureLod(room_texture, uv, 0.0).rgb;
	vec3 emit = textureLod(room_emit_texture, uv, 0.0).rgb;

	// use emission map based on cutoff parameter
	ivec2 emission_texture_size = textureSize(emission_texture, 0);
	int x = int(float(UV.x * float(emission_texture_size.x))) % int(rooms.x);
	int y = int(float(UV.y * float(emission_texture_size.y))) % int(rooms.y);
	// Scale UV across whole surface, offset by a half room
	vec2 stretched_uv = (UV / rooms) - (0.5 / rooms);
	// Force UV to be "pixelated" by rounding each room
	vec2 pixelated_uv = round(stretched_uv * rooms) / rooms;
	float is_emit = dot(textureLod(emission_texture, pixelated_uv, 0.0).rgb, vec3(0.299, 0.587, 0.114));
	is_emit = is_emit >= emission_cutoff ? 1.0 : 0.0;

	// final result
	ALBEDO = room * (1.0 - is_emit);
	EMISSION = emit * is_emit * emission_strength;
}
Tags
interior parallax mapping building window room rooms
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 GammaGames

2D Shine Highlight

Related shaders

Interior mapping shader

Cheap terrain with fake normal map or POM

View-Matcap Based Fake Vertex Lighting

Subscribe
Notify of
guest

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
baiyan
baiyan
1 year ago

that is really coooool!

Instructions
1 month ago

Very good shader, thanks for sharing!