Fix terrain surface texture projection
This commit is contained in:
parent
69b7969e25
commit
78a5f0effd
6 changed files with 128 additions and 10 deletions
60
tests/terrain_projection_validation.gd
Normal file
60
tests/terrain_projection_validation.gd
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
const REGION := preload("res://world/regions/starter_island_region.tscn")
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize() -> void:
|
||||||
|
call_deferred("_run")
|
||||||
|
|
||||||
|
|
||||||
|
func _run() -> void:
|
||||||
|
var region := REGION.instantiate()
|
||||||
|
root.add_child(region)
|
||||||
|
await process_frame
|
||||||
|
var terrain := region.get_node(
|
||||||
|
"Terrain/Visual/starter_island"
|
||||||
|
) as MeshInstance3D
|
||||||
|
assert(terrain != null)
|
||||||
|
assert(terrain.mesh.get_surface_count() == 5)
|
||||||
|
assert(terrain.mesh.surface_get_name(0) == "grass_lite")
|
||||||
|
assert(terrain.mesh.surface_get_name(1) == "dirt")
|
||||||
|
assert(terrain.mesh.surface_get_name(2) == "sand")
|
||||||
|
assert(terrain.mesh.surface_get_name(3) == "cliff_wall")
|
||||||
|
assert(terrain.mesh.surface_get_name(4) == "dirt_wall")
|
||||||
|
|
||||||
|
_validate_projected_material(terrain.get_surface_override_material(0))
|
||||||
|
_validate_projected_material(terrain.get_surface_override_material(2))
|
||||||
|
for surface: int in [1, 3, 4]:
|
||||||
|
assert(terrain.get_surface_override_material(surface) == null)
|
||||||
|
assert(terrain.mesh.surface_get_material(surface) is StandardMaterial3D)
|
||||||
|
|
||||||
|
print("Terrain projection validation: PASS")
|
||||||
|
region.free()
|
||||||
|
quit()
|
||||||
|
|
||||||
|
|
||||||
|
func _validate_projected_material(material: Material) -> void:
|
||||||
|
assert(material is ShaderMaterial)
|
||||||
|
var shader_material := material as ShaderMaterial
|
||||||
|
assert(
|
||||||
|
shader_material.shader.resource_path
|
||||||
|
== "res://world/materials/terrain_surface_projection.gdshader"
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
is_equal_approx(
|
||||||
|
float(shader_material.get_shader_parameter("tile_world_size")),
|
||||||
|
2.5
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
is_equal_approx(
|
||||||
|
float(shader_material.get_shader_parameter("blend_sharpness")),
|
||||||
|
6.0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
is_equal_approx(
|
||||||
|
float(shader_material.get_shader_parameter("top_projection_bias")),
|
||||||
|
2.0
|
||||||
|
)
|
||||||
|
)
|
||||||
1
tests/terrain_projection_validation.gd.uid
Normal file
1
tests/terrain_projection_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cto4rc6bn0n4o
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
[gd_resource type="StandardMaterial3D" load_steps=2 format=3]
|
[gd_resource type="ShaderMaterial" load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Texture2D" path="res://art/exported/environment/textures/grass_lite.png" id="1_texture"]
|
[ext_resource type="Texture2D" path="res://art/exported/environment/textures/grass_lite.png" id="1_texture"]
|
||||||
|
[ext_resource type="Shader" path="res://world/materials/terrain_surface_projection.gdshader" id="2_shader"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
resource_name = "Starter Island Grass"
|
resource_name = "Starter Island Grass"
|
||||||
texture_filter = 4
|
shader = ExtResource("2_shader")
|
||||||
albedo_texture = ExtResource("1_texture")
|
shader_parameter/albedo_texture = ExtResource("1_texture")
|
||||||
roughness = 1.0
|
shader_parameter/albedo_tint = Color(1, 1, 1, 1)
|
||||||
uv1_scale = Vector3(21.406, 21.406, 21.406)
|
shader_parameter/tile_world_size = 2.5
|
||||||
|
shader_parameter/blend_sharpness = 6.0
|
||||||
|
shader_parameter/top_projection_bias = 2.0
|
||||||
|
shader_parameter/roughness = 1.0
|
||||||
|
shader_parameter/specular = 0.5
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
[gd_resource type="StandardMaterial3D" load_steps=2 format=3]
|
[gd_resource type="ShaderMaterial" load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Texture2D" path="res://art/exported/environment/textures/sand.png" id="1_texture"]
|
[ext_resource type="Texture2D" path="res://art/exported/environment/textures/sand.png" id="1_texture"]
|
||||||
|
[ext_resource type="Shader" path="res://world/materials/terrain_surface_projection.gdshader" id="2_shader"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
resource_name = "Starter Island Sand"
|
resource_name = "Starter Island Sand"
|
||||||
texture_filter = 4
|
shader = ExtResource("2_shader")
|
||||||
albedo_texture = ExtResource("1_texture")
|
shader_parameter/albedo_texture = ExtResource("1_texture")
|
||||||
roughness = 1.0
|
shader_parameter/albedo_tint = Color(1, 1, 1, 1)
|
||||||
uv1_scale = Vector3(21.406, 21.406, 21.406)
|
shader_parameter/tile_world_size = 2.5
|
||||||
|
shader_parameter/blend_sharpness = 6.0
|
||||||
|
shader_parameter/top_projection_bias = 2.0
|
||||||
|
shader_parameter/roughness = 1.0
|
||||||
|
shader_parameter/specular = 0.5
|
||||||
|
|
|
||||||
46
world/materials/terrain_surface_projection.gdshader
Normal file
46
world/materials/terrain_surface_projection.gdshader
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
shader_type spatial;
|
||||||
|
render_mode cull_back;
|
||||||
|
|
||||||
|
uniform sampler2D albedo_texture : source_color, repeat_enable, filter_nearest_mipmap_anisotropic;
|
||||||
|
uniform vec4 albedo_tint : source_color = vec4(1.0);
|
||||||
|
uniform float tile_world_size : hint_range(0.1, 20.0, 0.05) = 2.5;
|
||||||
|
uniform float blend_sharpness : hint_range(1.0, 16.0, 0.25) = 6.0;
|
||||||
|
uniform float top_projection_bias : hint_range(1.0, 8.0, 0.05) = 2.0;
|
||||||
|
uniform float roughness : hint_range(0.0, 1.0, 0.01) = 1.0;
|
||||||
|
uniform float specular : hint_range(0.0, 1.0, 0.01) = 0.5;
|
||||||
|
|
||||||
|
varying vec3 world_position;
|
||||||
|
varying vec3 world_normal;
|
||||||
|
|
||||||
|
|
||||||
|
void vertex() {
|
||||||
|
world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||||
|
world_normal = normalize(MODEL_NORMAL_MATRIX * NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
vec3 normal = normalize(world_normal);
|
||||||
|
vec3 weights = pow(abs(normal), vec3(max(blend_sharpness, 1.0)));
|
||||||
|
float upward_amount = smoothstep(0.0, 0.8, normal.y);
|
||||||
|
weights.y *= mix(1.0, max(top_projection_bias, 1.0), upward_amount);
|
||||||
|
weights /= max(weights.x + weights.y + weights.z, 0.00001);
|
||||||
|
|
||||||
|
float world_scale = 1.0 / max(tile_world_size, 0.001);
|
||||||
|
vec2 x_uv = world_position.zy * vec2(sign(normal.x), 1.0) * world_scale;
|
||||||
|
vec2 y_uv = world_position.xz * vec2(sign(normal.y), 1.0) * world_scale;
|
||||||
|
vec2 z_uv = world_position.xy * vec2(-sign(normal.z), 1.0) * world_scale;
|
||||||
|
vec4 x_sample = texture(albedo_texture, x_uv);
|
||||||
|
vec4 y_sample = texture(albedo_texture, y_uv);
|
||||||
|
vec4 z_sample = texture(albedo_texture, z_uv);
|
||||||
|
vec4 projected = (
|
||||||
|
x_sample * weights.x
|
||||||
|
+ y_sample * weights.y
|
||||||
|
+ z_sample * weights.z
|
||||||
|
);
|
||||||
|
|
||||||
|
ALBEDO = projected.rgb * albedo_tint.rgb;
|
||||||
|
ROUGHNESS = roughness;
|
||||||
|
SPECULAR = specular;
|
||||||
|
METALLIC = 0.0;
|
||||||
|
}
|
||||||
1
world/materials/terrain_surface_projection.gdshader.uid
Normal file
1
world/materials/terrain_surface_projection.gdshader.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://d2ju2vpykktuo
|
||||||
Loading…
Add table
Add a link
Reference in a new issue