Gunkable props blend the underlying normal map where possible

This commit is contained in:
Rob Kelly 2025-09-08 16:28:31 -06:00
parent f3f8f874f0
commit c38502d351
11 changed files with 310 additions and 29 deletions

View File

@ -3,25 +3,27 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://b0vorb12h2idg"
path="res://.godot/imported/overhead_light_burnout_E.png-ce71c7290fb299e0f7b60d0a9c7d4505.ctex"
path.s3tc="res://.godot/imported/overhead_light_burnout_E.png-ce71c7290fb299e0f7b60d0a9c7d4505.s3tc.ctex"
path.etc2="res://.godot/imported/overhead_light_burnout_E.png-ce71c7290fb299e0f7b60d0a9c7d4505.etc2.ctex"
metadata={
"vram_texture": false
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/props/overhead_light/overhead_light_burnout_E.png"
dest_files=["res://.godot/imported/overhead_light_burnout_E.png-ce71c7290fb299e0f7b60d0a9c7d4505.ctex"]
dest_files=["res://.godot/imported/overhead_light_burnout_E.png-ce71c7290fb299e0f7b60d0a9c7d4505.s3tc.ctex", "res://.godot/imported/overhead_light_burnout_E.png-ce71c7290fb299e0f7b60d0a9c7d4505.etc2.ctex"]
[params]
compress/mode=0
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
@ -31,4 +33,4 @@ process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
detect_3d/compress_to=0

View File

@ -91,6 +91,8 @@ shader_parameter/iridescence_intensity = 0.1
shader_parameter/overlay_emission_scale = 1.0
shader_parameter/edge_bleed = 0.25
shader_parameter/gunk_mask = ExtResource("3_3t4ks")
shader_parameter/base_uv_scale = Vector3(1, 1, 1)
shader_parameter/normal_blend = 1.0
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_gpcv6"]
data = PackedVector3Array(4.5, 0, 4.5, -4.5, 0, 4.5, 4.5, 0, -4.5, 4.5, 0, -4.5, -4.5, 0, 4.5, -4.5, 0, -4.5)
@ -243,6 +245,8 @@ shader_parameter/iridescence_intensity = 0.0
shader_parameter/overlay_emission_scale = 1.0
shader_parameter/edge_bleed = 0.25
shader_parameter/gunk_mask = ExtResource("31_753oq")
shader_parameter/base_uv_scale = Vector3(1, 1, 1)
shader_parameter/normal_blend = 1.0
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_k52xx"]
resource_local_to_scene = true

File diff suppressed because one or more lines are too long

View File

@ -72,6 +72,26 @@ float hardstep(float value) {
return 0.5 * tanh( (20.0 * x - 10.0) * inversesqrt(x - x * x) ) + 0.5;
}
vec3 slerp(vec3 a, vec3 b, float t) {
vec3 v0 = normalize(a);
vec3 v1 = normalize(b);
float cos_theta = clamp(dot(v0, v1), -1.0, 1.0);
// use lerp for small angles to avoid division by small sine
const float epsilon = 1e-6;
if (1.0 - abs(cos_theta) < epsilon) {
return normalize(mix(v0, v1, t));
}
float theta = acos(cos_theta);
float sin_theta = sin(theta);
float w0 = sin((1.0 - t) * theta) / sin_theta;
float w1 = sin(t * theta) / sin_theta;
return w0 * v0 + w1 * v1;
}
vec3 swirl_uvt(vec3 uvt) {
uvt.x += sin(uvt.y * 1.54 * PI + uvt.z) * cos(uvt.y * 1.31 * PI + uvt.z) * 0.2;
uvt.y += cos(uvt.x * 1.74 * PI + uvt.z) * -sin(uvt.y * 1.64 * PI + uvt.z) * 0.2;

View File

@ -5,6 +5,11 @@ render_mode depth_prepass_alpha;
#define USE_MASK
#include "common.gdshaderinc"
group_uniforms base_material;
uniform vec3 base_uv_scale = vec3(1.0);
uniform sampler2D base_normal_map: filter_linear;
uniform float normal_blend = 1.0;
void fragment() {
vec3 uvt = scale_uvt(UV, TIME);
float value = sample_noise(uvt);
@ -13,16 +18,27 @@ void fragment() {
EMISSION = base_emission(UV, value);
SPECULAR = base_specular();
// vec3 nmap = minimal_convolution(UV, uvt);
// vec3 nmap = cross_convolution(UV, uvt);
vec3 nmap = sobel_convolution(UV, uvt);
// vec3 nmap = sobel_5x5_convolution(UV, uvt);
// vec3 nmap = scharr_convolution(UV, uvt);
// vec3 nmap = godot_convolution(UV, uvt);
NORMAL_MAP = nmap / 2.0 + 0.5;
mat3 TBN = mat3(TANGENT, BINORMAL, NORMAL);
mat3 inv_TBN = transpose(TBN);
vec3 base_nmap = texture(base_normal_map, UV * base_uv_scale.xy).rgb * 2.0 - 1.0;
vec3 base_world_normal = TBN * base_nmap;
vec3 gunk_nmap = sobel_convolution(UV, uvt);
vec3 gunk_world_normal = TBN * gunk_nmap;
// Unity blending
// see https://blog.selfshadow.com/publications/blending-in-detail/
vec3 n = base_nmap;
mat3 basis = mat3(
vec3(n.z, n.y, -n.x),
vec3(n.x, n.z, -n.y),
vec3(n.x, n.y, n.z)
);
vec3 nmap = normalize(gunk_nmap.x * basis[0] + gunk_nmap.y * basis[1] + gunk_nmap.z * basis[2]);
vec3 world_normal = TBN * nmap;
NORMAL_MAP = nmap / 2.0 + 0.5;
// add fresnel
vec3 world_normal = mat3(TANGENT, BINORMAL, NORMAL) * nmap;
EMISSION += rim_glow(
world_normal,
VIEW,

View File

@ -22,6 +22,12 @@ const MASK_THRESHOLD := 0.5
@export var source_gunk_material: ShaderMaterial
@export_group("Base Materials")
@export var base_material_index := 0
@export var base_uv_scale := Vector3.ONE
@export var base_normal_map: Texture2D
@export var base_normal_blend := 0.6
var meshtool := MeshDataTool.new()
var _polyline_buffer: Array[Vector2] = []
@ -68,6 +74,22 @@ func _ready() -> void:
mat_instance.next_pass = mesh_instance.material_overlay
mesh_instance.material_overlay = mat_instance
# Extract what we can from a base material, if we can find one.
var base_material: Material = mesh_instance.get_surface_override_material(base_material_index)
if not base_material:
base_material = mesh_instance.mesh.surface_get_material(base_material_index)
var standard_base_mat: StandardMaterial3D = base_material as StandardMaterial3D
if not base_normal_map and standard_base_mat:
base_normal_map = standard_base_mat.normal_texture
base_uv_scale = standard_base_mat.uv1_scale
if base_normal_map:
mat_instance.set_shader_parameter("base_normal_map", base_normal_map)
mat_instance.set_shader_parameter("normal_blend", base_normal_blend)
mat_instance.set_shader_parameter("base_uv_scale", base_uv_scale)
_deferred_init.call_deferred()
# Initialize meshtool