Skip to content

Commit

Permalink
Change region map size to 32x32; update minimum shader to latest
Browse files Browse the repository at this point in the history
  • Loading branch information
TokisanGames committed Sep 24, 2024
1 parent f83779d commit ba50db6
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 65 deletions.
117 changes: 64 additions & 53 deletions project/addons/terrain_3d/extras/minimum.gdshader
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,34 @@ uniform float _region_size = 1024.0;
uniform float _region_texel_size = 0.0009765625; // = 1/1024
uniform float _vertex_spacing = 1.0;
uniform float _vertex_density = 1.0; // = 1/_vertex_spacing
uniform int _region_map_size = 16;
uniform int _region_map[256];
uniform vec2 _region_locations[256];
uniform int _region_map_size = 32;
uniform int _region_map[1024];
uniform vec2 _region_locations[1024];
uniform sampler2DArray _height_maps : repeat_disable;
uniform usampler2DArray _control_maps : repeat_disable;
uniform sampler2DArray _color_maps : source_color, filter_linear_mipmap_anisotropic, repeat_disable;
uniform sampler2DArray _texture_array_albedo : source_color, filter_linear_mipmap_anisotropic, repeat_enable;
uniform sampler2DArray _texture_array_normal : hint_normal, filter_linear_mipmap_anisotropic, repeat_enable;
uniform sampler2D noise_texture : source_color, filter_linear_mipmap_anisotropic, repeat_enable;

uniform float _texture_uv_scale_array[32];
uniform float _texture_uv_rotation_array[32];
uniform float _texture_detile_array[32];
uniform vec4 _texture_color_array[32];
uniform uint _background_mode = 1u; // NONE = 0, FLAT = 1, NOISE = 2
uniform uint _mouse_layer = 0x80000000u; // Layer 32

// Public uniforms
uniform float vertex_normals_distance : hint_range(0, 1024) = 128.0;

// Varyings & Types
varying flat vec3 v_vertex; // World coordinate vertex location
varying flat vec3 v_camera_pos;
varying float v_vertex_xz_dist;
varying flat ivec3 v_region;
varying flat vec2 v_uv_offset;
varying flat vec2 v_uv2_offset;
varying vec3 v_normal;
varying float v_region_border_mask;

////////////////////////
// Vertex
Expand All @@ -33,26 +44,22 @@ varying flat vec2 v_uv2_offset;
// 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);
ivec3 get_region_uv(const vec2 uv) {
ivec2 pos = ivec2(floor(uv * _region_texel_size)) + (_region_map_size / 2);
int bounds = int(uint(pos.x | pos.y) < uint(_region_map_size));
int layer_index = _region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1;
return ivec3(ivec2((uv - _region_locations[layer_index]) * _region_size), layer_index);
return ivec3(ivec2(mod(uv,_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) {
// Vertex function added half a texel to UV2, to center the UV's. vertex(), fragment() and get_height()
// call this with reclaimed versions of UV2, so to keep the last row/column within the correct
// window, take back the half pixel before the floor().
ivec2 pos = ivec2(floor(uv - vec2(_region_texel_size * 0.5))) + (_region_map_size / 2);
int bounds = int(pos.x>=0 && pos.x<_region_map_size && pos.y>=0 && pos.y<_region_map_size);
vec3 get_region_uv2(const vec2 uv2) {
// Remove Texel Offset to ensure correct region index.
ivec2 pos = ivec2(floor(uv2 - vec2(_region_texel_size * 0.5))) + (_region_map_size / 2);
int bounds = int(uint(pos.x | pos.y) < uint(_region_map_size));
int layer_index = _region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1;
// The return value is still texel-centered.
return vec3(uv - _region_locations[layer_index], float(layer_index));
return vec3(uv2 - _region_locations[layer_index], float(layer_index));
}

// 1 lookup
Expand All @@ -66,70 +73,75 @@ float get_height(vec2 uv) {
}

void vertex() {
// Get camera pos in world vertex coords
v_camera_pos = INV_VIEW_MATRIX[3].xyz;

// Get vertex of flat plane in world coordinates and set world UV
vec3 vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;

v_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;

// Camera distance to vertex on flat plane
v_vertex_xz_dist = length(v_vertex.xz - v_camera_pos.xz);

// UV coordinates in world space. Values are 0 to _region_size within regions
UV = round(vertex.xz * _vertex_density);
UV = round(v_vertex.xz * _vertex_density);

// UV coordinates in region space + texel offset. Values are 0 to 1 within regions
UV2 = fma(UV, vec2(_region_texel_size), vec2(0.5 * _region_texel_size));

// Discard vertices for Holes. 1 lookup
ivec3 region = get_region_uv(UV);
uint control = texelFetch(_control_maps, region, 0).r;
v_region = get_region_uv(UV);
uint control = texelFetch(_control_maps, v_region, 0).r;
bool hole = bool(control >>2u & 0x1u);

// Show holes to all cameras except mouse camera (on exactly 1 layer)
if ( !(CAMERA_VISIBLE_LAYERS == _mouse_layer) &&
(hole || (_background_mode == 0u && region.z < 0)) ) {
VERTEX.x = 0./0.;
} else {
// 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
(hole || (_background_mode == 0u && (get_region_uv(UV - _region_texel_size) & v_region).z < 0))) {
VERTEX.x = 0. / 0.;
} else {
// Set final vertex height & calculate vertex normals. 3 lookups.
VERTEX.y = get_height(UV2);
v_vertex.y = VERTEX.y;
v_normal = vec3(
v_vertex.y - get_height(UV2 + vec2(_region_texel_size, 0)),
_vertex_spacing,
v_vertex.y - get_height(UV2 + vec2(0, _region_texel_size))
);
// Due to a bug caused by the GPUs linear interpolation across edges of region maps,
// mask region edges and use vertex normals only across region boundaries.
v_region_border_mask = mod(UV.x + 2.5, _region_size) - fract(UV.x) < 5.0 || mod(UV.y + 2.5, _region_size) - fract(UV.y) < 5.0 ? 1. : 0.;
}

// Transform UVs to local to avoid poor precision during varying interpolation.
v_uv_offset = MODEL_MATRIX[3].xz * _vertex_density;
UV -= v_uv_offset;
v_uv2_offset = v_uv_offset * _region_texel_size;
UV2 -= v_uv2_offset;

// Convert model space to view space w/ skip_vertex_transform render mode
VERTEX = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
VERTEX = (VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
NORMAL = normalize((MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);
BINORMAL = normalize((MODELVIEW_MATRIX * vec4(BINORMAL, 0.0)).xyz);
TANGENT = normalize((MODELVIEW_MATRIX * vec4(TANGENT, 0.0)).xyz);
TANGENT = normalize((MODELVIEW_MATRIX * vec4(TANGENT, 0.0)).xyz);
}

////////////////////////
// Fragment
////////////////////////

// 3 lookups
// 0 - 3 lookups
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;
float u, v, height;
vec3 normal;
// Use vertex normals within radius of vertex_normals_distance, and along region borders.
if (v_region_border_mask > 0.5 || v_vertex_xz_dist < vertex_normals_distance) {
normal = normalize(v_normal);
} else {
height = get_height(uv);
u = height - get_height(uv + vec2(_region_texel_size, 0));
v = height - get_height(uv + vec2(0, _region_texel_size));
normal = normalize(vec3(u, _vertex_spacing, v));
}

vec3 normal = vec3(u, _vertex_spacing, v);
normal = normalize(normal);
tangent = cross(normal, vec3(0, 0, 1));
binormal = cross(normal, tangent);
return normal;
Expand All @@ -150,4 +162,3 @@ void fragment() {
// Apply PBR
ALBEDO=vec3(.2);
}

4 changes: 2 additions & 2 deletions project/addons/terrain_3d/src/region_gizmo.gd
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func _redraw() -> void:

if show_rect:
var modulate: Color = main_color if !use_secondary_color else secondary_color
if abs(region_position.x) > 8 or abs(region_position.y) > 8:
if abs(region_position.x) > Terrain3DData.REGION_MAP_SIZE*.5 or abs(region_position.y) > Terrain3DData.REGION_MAP_SIZE*.5:
modulate = Color.GRAY
draw_rect(Vector2(region_size,region_size)*.5 + rect_position, region_size, selection_material, modulate)

Expand All @@ -44,7 +44,7 @@ func _redraw() -> void:

draw_rect(Vector2(region_size,region_size)*.5 + grid_tile_position, region_size, material, grid_color)

draw_rect(Vector2.ZERO, region_size * 16.0, material, border_color)
draw_rect(Vector2.ZERO, region_size * Terrain3DData.REGION_MAP_SIZE, material, border_color)


func draw_rect(p_pos: Vector2, p_size: float, p_material: StandardMaterial3D, p_modulate: Color) -> void:
Expand Down
6 changes: 3 additions & 3 deletions src/shaders/main.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ uniform float _region_size = 1024.0;
uniform float _region_texel_size = 0.0009765625; // = 1/1024
uniform float _vertex_spacing = 1.0;
uniform float _vertex_density = 1.0; // = 1/_vertex_spacing
uniform int _region_map_size = 16;
uniform int _region_map[256];
uniform vec2 _region_locations[256];
uniform int _region_map_size = 32;
uniform int _region_map[1024];
uniform vec2 _region_locations[1024];
uniform sampler2DArray _height_maps : repeat_disable;
uniform usampler2DArray _control_maps : repeat_disable;
//INSERT: TEXTURE_SAMPLERS_NEAREST
Expand Down
12 changes: 6 additions & 6 deletions src/terrain_3d_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Terrain3DData : public Object {

public: // Constants
static inline const real_t CURRENT_VERSION = 0.93f;
static inline const int REGION_MAP_SIZE = 16;
static inline const int REGION_MAP_SIZE = 32;
static inline const Vector2i REGION_MAP_VSIZE = Vector2i(REGION_MAP_SIZE, REGION_MAP_SIZE);

enum HeightFilter {
Expand Down Expand Up @@ -66,7 +66,7 @@ class Terrain3DData : public Object {
// Editing occurs on the Image arrays above, which are converted to Texture arrays
// below for the shader.

// 16x16 grid with region_id:int at its location, no region = 0, region_ids >= 1
// 32x32 grid with region_id:int at its location, no region = 0, region_ids >= 1
PackedInt32Array _region_map;
bool _region_map_dirty = true;

Expand Down Expand Up @@ -180,13 +180,13 @@ VARIANT_ENUM_CAST(Terrain3DData::HeightFilter);

// Verifies the location is within the bounds of the _region_map array and
// the world, returning the _region_map index, which contains the region_id.
// Valid region locations are -8, -8 to 7, 7, or when offset: 0, 0 to 15, 15
// If any bits other than 0xF are set, it's out of bounds and returns -1
// Valid region locations are -16, -16 to 15, 15, or when offset: 0, 0 to 31, 31
// If any bits other than 0x1F are set, it's out of bounds and returns -1
inline int Terrain3DData::get_region_map_index(const Vector2i &p_region_loc) {
// Offset world to positive values only
Vector2i loc = p_region_loc + (REGION_MAP_VSIZE / 2);
// Catch values > 15
if ((uint32_t(loc.x | loc.y) & uint32_t(~0xF)) > 0) {
// Catch values > 31
if ((uint32_t(loc.x | loc.y) & uint32_t(~0x1F)) > 0) {
return -1;
}
return loc.y * REGION_MAP_SIZE + loc.x;
Expand Down
2 changes: 1 addition & 1 deletion src/terrain_3d_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Terrain3DStorage : public Resource {

public: // Constants
static inline const real_t CURRENT_VERSION = 0.92f;
static inline const int REGION_MAP_SIZE = 16;
static inline const int REGION_MAP_SIZE = 32;
static inline const Vector2i REGION_MAP_VSIZE = Vector2i(REGION_MAP_SIZE, REGION_MAP_SIZE);

enum MapType {
Expand Down

0 comments on commit ba50db6

Please sign in to comment.