🎉 initial commit

This commit is contained in:
anyreso 2024-04-07 14:25:59 -04:00
commit d02447c7e6
185 changed files with 8442 additions and 0 deletions

View file

@ -0,0 +1,109 @@
// This shader is the minimum needed to allow the terrain to function.
shader_type spatial;
render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx;
// Private uniforms
uniform float _region_size = 1024.0;
uniform float _region_texel_size = 0.0009765625; // = 1/1024
uniform float _mesh_vertex_spacing = 1.0;
uniform float _mesh_vertex_density = 1.0; // = 1/_mesh_vertex_spacing
uniform int _region_map_size = 16;
uniform int _region_map[256];
uniform vec2 _region_offsets[256];
uniform sampler2DArray _height_maps : repeat_disable;
varying vec3 v_vertex; // World coordinate vertex location
////////////////////////
// Vertex
////////////////////////
// Takes in UV world space coordinates, returns ivec3 with:
// XY: (0 to _region_size) coordinates within a region
// Z: layer index used for texturearrays, -1 if not in a region
ivec3 get_region_uv(vec2 uv) {
uv *= _region_texel_size;
ivec2 pos = ivec2(floor(uv)) + (_region_map_size / 2);
int bounds = int(pos.x>=0 && pos.x<_region_map_size && pos.y>=0 && pos.y<_region_map_size);
int layer_index = _region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1;
return ivec3(ivec2((uv - _region_offsets[layer_index]) * _region_size), layer_index);
}
// Takes in UV2 region space coordinates, returns vec3 with:
// XY: (0 to 1) coordinates within a region
// Z: layer index used for texturearrays, -1 if not in a region
vec3 get_region_uv2(vec2 uv) {
ivec2 pos = ivec2(floor(uv)) + (_region_map_size / 2);
int bounds = int(pos.x>=0 && pos.x<_region_map_size && pos.y>=0 && pos.y<_region_map_size);
int layer_index = _region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1;
return vec3(uv - _region_offsets[layer_index], float(layer_index));
}
float get_height(vec2 uv) {
highp float height = 0.0;
vec3 region = get_region_uv2(uv);
if (region.z >= 0.) {
height = texture(_height_maps, region).r;
}
return height;
}
void vertex() {
// Get vertex of flat plane in world coordinates and set world UV
v_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
// UV coordinates in world space. Values are 0 to _region_size within regions
UV = round(v_vertex.xz * _mesh_vertex_density);
// UV coordinates in region space + texel offset. Values are 0 to 1 within regions
UV2 = (UV + vec2(0.5)) * _region_texel_size;
// Get final vertex location and save it
VERTEX.y = get_height(UV2);
v_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}
////////////////////////
// Fragment
////////////////////////
vec3 get_normal(vec2 uv, out vec3 tangent, out vec3 binormal) {
// Get the height of the current vertex
float height = get_height(uv);
// Get the heights to the right and in front, but because of hardware
// interpolation on the edges of the heightmaps, the values are off
// causing the normal map to look weird. So, near the edges of the map
// get the heights to the left or behind instead. Hacky solution that
// reduces the artifact, but doesn't fix it entirely. See #185.
float u, v;
if(mod(uv.y*_region_size, _region_size) > _region_size-2.) {
v = get_height(uv + vec2(0, -_region_texel_size)) - height;
} else {
v = height - get_height(uv + vec2(0, _region_texel_size));
}
if(mod(uv.x*_region_size, _region_size) > _region_size-2.) {
u = get_height(uv + vec2(-_region_texel_size, 0)) - height;
} else {
u = height - get_height(uv + vec2(_region_texel_size, 0));
}
vec3 normal = vec3(u, _mesh_vertex_spacing, v);
normal = normalize(normal);
tangent = cross(normal, vec3(0, 0, 1));
binormal = cross(normal, tangent);
return normal;
}
void fragment() {
// Calculate Terrain Normals
vec3 w_tangent, w_binormal;
vec3 w_normal = get_normal(UV2, w_tangent, w_binormal);
NORMAL = mat3(VIEW_MATRIX) * w_normal;
TANGENT = mat3(VIEW_MATRIX) * w_tangent;
BINORMAL = mat3(VIEW_MATRIX) * w_binormal;
// Apply PBR
ALBEDO=vec3(.2);
}

View file

@ -0,0 +1,83 @@
# This script is an addon for HungryProton's Scatter https://github.com/HungryProton/scatter
# It allows Scatter to detect the terrain height from Terrain3D
# Copy this file into /addons/proton_scatter/src/modifiers
# Then uncomment everything below
# In the editor, add this modifier, then set your Terrain3D node
#@tool
#extends "base_modifier.gd"
#
#
#signal projection_completed
#
#
#@export var terrain_node : NodePath
#@export var align_with_collision_normal := false
#
#var _terrain: Terrain3D
#
#
#func _init() -> void:
# display_name = "Project On Terrain3D"
# category = "Edit"
# can_restrict_height = false
# global_reference_frame_available = true
# local_reference_frame_available = true
# individual_instances_reference_frame_available = true
# use_global_space_by_default()
#
# documentation.add_paragraph(
# "This is a duplicate of `Project on Colliders` that queries the terrain system
# for height and sets the transform height appropriately.
#
# This modifier must have terrain_node set to a Terrain3D node.")
#
# var p := documentation.add_parameter("Terrain Node")
# p.set_type("NodePath")
# p.set_description("Set your Terrain3D node.")
#
# p = documentation.add_parameter("Align with collision normal")
# p.set_type("bool")
# p.set_description(
# "Rotate the transform to align it with the collision normal in case
# the ray cast hit a collider.")
#
#
#func _process_transforms(transforms, domain, _seed) -> void:
# if transforms.is_empty():
# return
#
# if terrain_node:
# _terrain = domain.get_root().get_node_or_null(terrain_node)
#
# if not _terrain:
# warning += """No Terrain3D node found"""
# return
#
# if not _terrain.storage:
# warning += """Terrain3D storage is not initialized"""
# return
#
# # Get global transform
# var gt: Transform3D = domain.get_global_transform()
# var gt_inverse: Transform3D = gt.affine_inverse()
# for i in transforms.list.size():
# var location: Vector3 = (gt * transforms.list[i]).origin
# var height: float = _terrain.storage.get_height(location)
# var normal: Vector3 = _terrain.storage.get_normal(location)
#
# if align_with_collision_normal:
# transforms.list[i].basis.y = normal
# transforms.list[i].basis.x = -transforms.list[i].basis.z.cross(normal)
# transforms.list[i].basis = transforms.list[i].basis.orthonormalized()
#
# transforms.list[i].origin.y = height - gt.origin.y
#
# if transforms.is_empty():
# warning += """Every point has been removed. Possible reasons include: \n
# + No collider is close enough to the shapes.
# + Ray length is too short.
# + Ray direction is incorrect.
# + Collision mask is not set properly.
# + Max slope is too low.
# """