Skip to content

Commit

Permalink
Merge pull request #229 from TokisanGames/custom-uniforms
Browse files Browse the repository at this point in the history
Add custom uniforms for override shaders
  • Loading branch information
TokisanGames authored Oct 16, 2023
2 parents 01bd4dc + d416009 commit 0d7b1b7
Show file tree
Hide file tree
Showing 11 changed files with 381 additions and 174 deletions.
2 changes: 1 addition & 1 deletion src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
#define COLOR_CHECKED Color(1.f, 1.f, 1.0f, -1.0f)
#define COLOR_NORMAL Color(0.5f, 0.5f, 1.0f, 1.0f)

#endif CONSTANTS_CLASS_H
#endif // CONSTANTS_CLASS_H
4 changes: 2 additions & 2 deletions src/shaders/debug_views.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ R"(
float _view_distance = 100.0; // Visible distance of grid
// Draw region grid
_region_line = .1*sqrt(_camera_dist);
if (mod(_pixel_pos.x + _region_line*.5, region_size) <= _region_line ||
mod(_pixel_pos.z + _region_line*.5, region_size) <= _region_line ) {
if (mod(_pixel_pos.x + _region_line*.5, _region_size) <= _region_line ||
mod(_pixel_pos.z + _region_line*.5, _region_size) <= _region_line ) {
ALBEDO = vec3(1.);
}
if ( _camera_dist < _view_distance ) {
Expand Down
96 changes: 47 additions & 49 deletions src/shaders/main.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,20 @@
R"(shader_type spatial;
render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx;

uniform float region_size = 1024.0;
uniform float region_pixel_size = 1.0;
uniform int region_map_size = 16;

uniform int region_map[256];
uniform vec2 region_offsets[256];
uniform sampler2DArray height_maps : filter_linear_mipmap, repeat_disable;
uniform sampler2DArray control_maps : filter_linear_mipmap, repeat_disable;
uniform sampler2DArray color_maps : filter_linear_mipmap, 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 float texture_uv_scale_array[32];
uniform float texture_uv_rotation_array[32];
uniform vec3 texture_3d_projection_array[32];
uniform vec4 texture_color_array[32];
uniform float _region_size = 1024.0;
uniform float _region_pixel_size = 0.0009765625; // 1.0 / 1024.0
uniform int _region_map_size = 16;
uniform int _region_map[256];
uniform vec2 _region_offsets[256];
uniform sampler2DArray _height_maps : filter_linear_mipmap, repeat_disable;
uniform sampler2DArray _control_maps : filter_linear_mipmap, repeat_disable;
uniform sampler2DArray _color_maps : filter_linear_mipmap, 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 float _texture_uv_scale_array[32];
uniform float _texture_uv_rotation_array[32];
uniform vec4 _texture_color_array[32];

//INSERT: WORLD_NOISE1

Expand All @@ -34,26 +32,26 @@ vec4 pack_normal(vec3 n, float a) {
}

// Takes location in world space coordinates, returns ivec3 with:
// XY: (0-region_size) coordinates within the region
// XY: (0-_region_size) coordinates within the region
// Z: region index used for texturearrays, -1 if not in a region
ivec3 get_region(vec2 uv) {
ivec2 pos = ivec2(floor(uv)) + (region_map_size / 2);
int index = region_map[ pos.y*region_map_size + pos.x ] - 1;
return ivec3(ivec2((uv - region_offsets[index]) * region_size), index);
ivec2 pos = ivec2(floor(uv)) + (_region_map_size / 2);
int index = _region_map[ pos.y*_region_map_size + pos.x ] - 1;
return ivec3(ivec2((uv - _region_offsets[index]) * _region_size), index);
}

// vec3 form of get_region. Same return values
vec3 get_regionf(vec2 uv) {
ivec2 pos = ivec2(floor(uv)) + (region_map_size / 2);
int index = region_map[ pos.y*region_map_size + pos.x ] - 1;
return vec3(uv - region_offsets[index], float(index));
ivec2 pos = ivec2(floor(uv)) + (_region_map_size / 2);
int index = _region_map[ pos.y*_region_map_size + pos.x ] - 1;
return vec3(uv - _region_offsets[index], float(index));
}

float get_height(vec2 uv) {
float height = 0.0;
vec3 region = get_regionf(uv);
if (region.z >= 0.) {
height = texture(height_maps, region).r;
height = texture(_height_maps, region).r;
}
//INSERT: WORLD_NOISE2
return height;
Expand Down Expand Up @@ -85,10 +83,10 @@ vec3 get_normal(vec2 uv, out vec3 tangent, out vec3 binormal) {
// Control map is also sampled 4 times, so in theory we could reduce the region samples to 4 from 8,
// but control map sampling is slightly different with the mirroring and doesn't work here.
// The region map is very, very small, so maybe the performance cost isn't too high
float left = get_height(uv + vec2(-region_pixel_size, 0));
float right = get_height(uv + vec2(region_pixel_size, 0));
float back = get_height(uv + vec2(0, -region_pixel_size));
float fore = get_height(uv + vec2(0, region_pixel_size));
float left = get_height(uv + vec2(-_region_pixel_size, 0));
float right = get_height(uv + vec2(_region_pixel_size, 0));
float back = get_height(uv + vec2(0, -_region_pixel_size));
float fore = get_height(uv + vec2(0, _region_pixel_size));
vec3 horizontal = vec3(2.0, right - left, 0.0);
vec3 vertical = vec3(0.0, back - fore, 2.0);
vec3 normal = normalize(cross(vertical, horizontal));
Expand All @@ -101,24 +99,24 @@ vec3 get_normal(vec2 uv, out vec3 tangent, out vec3 binormal) {
vec4 get_material(vec2 uv, vec4 index, vec2 uv_center, float weight, inout float total_weight, inout vec4 out_normal) {
float material = index.r * 255.0;
float r = random(uv_center) * PI;
float rand = r * texture_uv_rotation_array[int(material)];
float rand = r * _texture_uv_rotation_array[int(material)];
vec2 rot = vec2(cos(rand), sin(rand));
vec2 matUV = rotate(uv, rot.x, rot.y) * texture_uv_scale_array[int(material)];
vec2 matUV = rotate(uv, rot.x, rot.y) * _texture_uv_scale_array[int(material)];

vec4 albedo = texture(texture_array_albedo, vec3(matUV, material));
albedo.rgb *= texture_color_array[int(material)].rgb;
vec4 normal = texture(texture_array_normal, vec3(matUV, material));
vec4 albedo = texture(_texture_array_albedo, vec3(matUV, material));
albedo.rgb *= _texture_color_array[int(material)].rgb;
vec4 normal = texture(_texture_array_normal, vec3(matUV, material));
vec3 n = unpack_normal(normal);
normal.xz = rotate(n.xz, rot.x, -rot.y);

if (index.b > 0.0) {
float materialOverlay = index.g * 255.0;
float rand2 = r * texture_uv_rotation_array[int(materialOverlay)];
float rand2 = r * _texture_uv_rotation_array[int(materialOverlay)];
vec2 rot2 = vec2(cos(rand2), sin(rand2));
vec2 matUV2 = rotate(uv, rot2.x, rot2.y) * texture_uv_scale_array[int(materialOverlay)];
vec4 albedo2 = texture(texture_array_albedo, vec3(matUV2, materialOverlay));
albedo2.rgb *= texture_color_array[int(materialOverlay)].rgb;
vec4 normal2 = texture(texture_array_normal, vec3(matUV2, materialOverlay));
vec2 matUV2 = rotate(uv, rot2.x, rot2.y) * _texture_uv_scale_array[int(materialOverlay)];
vec4 albedo2 = texture(_texture_array_albedo, vec3(matUV2, materialOverlay));
albedo2.rgb *= _texture_color_array[int(materialOverlay)].rgb;
vec4 normal2 = texture(_texture_array_normal, vec3(matUV2, materialOverlay));
n = unpack_normal(normal2);
normal2.xz = rotate(n.xz, rot2.x, -rot2.y);

Expand All @@ -136,7 +134,7 @@ vec4 get_material(vec2 uv, vec4 index, vec2 uv_center, float weight, inout float
void vertex() {
vec3 world_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
UV = world_vertex.xz * 0.5; // Without this, individual material UV needs to be very small.
UV2 = ((world_vertex.xz + vec2(0.5)) / vec2(region_size));
UV2 = ((world_vertex.xz + vec2(0.5)) / vec2(_region_size));
VERTEX.y = get_height(UV2);
NORMAL = vec3(0, 1, 0);
}
Expand All @@ -152,20 +150,20 @@ void fragment() {
// Calculated Weighted Material
// source : https://github.com/cdxntchou/IndexMapTerrain
// black magic which I don't understand at all. Seems simple but what and why?
vec2 pos_texel = UV2 * region_size + 0.5;
vec2 pos_texel = UV2 * _region_size + 0.5;
vec2 pos_texel00 = floor(pos_texel);
vec4 mirror = vec4(fract(pos_texel00 * 0.5) * 2.0, 1.0, 1.0);
mirror.zw = vec2(1.0) - mirror.xy;

ivec3 index00UV = get_region((pos_texel00 + mirror.xy) * region_pixel_size);
ivec3 index01UV = get_region((pos_texel00 + mirror.xw) * region_pixel_size);
ivec3 index10UV = get_region((pos_texel00 + mirror.zy) * region_pixel_size);
ivec3 index11UV = get_region((pos_texel00 + mirror.zw) * region_pixel_size);
ivec3 index00UV = get_region((pos_texel00 + mirror.xy) * _region_pixel_size);
ivec3 index01UV = get_region((pos_texel00 + mirror.xw) * _region_pixel_size);
ivec3 index10UV = get_region((pos_texel00 + mirror.zy) * _region_pixel_size);
ivec3 index11UV = get_region((pos_texel00 + mirror.zw) * _region_pixel_size);

vec4 index00 = texelFetch(control_maps, index00UV, 0);
vec4 index01 = texelFetch(control_maps, index01UV, 0);
vec4 index10 = texelFetch(control_maps, index10UV, 0);
vec4 index11 = texelFetch(control_maps, index11UV, 0);
vec4 index00 = texelFetch(_control_maps, index00UV, 0);
vec4 index01 = texelFetch(_control_maps, index01UV, 0);
vec4 index10 = texelFetch(_control_maps, index10UV, 0);
vec4 index11 = texelFetch(_control_maps, index11UV, 0);

vec2 weights1 = clamp(pos_texel - pos_texel00, 0, 1);
weights1 = mix(weights1, vec2(1.0) - weights1, mirror.xy);
Expand All @@ -187,7 +185,7 @@ void fragment() {
vec3 ruv = get_regionf(UV2);
vec4 color_tex = vec4(1., 1., 1., .5);
if (ruv.z >= 0.) {
color_tex = texture(color_maps, ruv);
color_tex = texture(_color_maps, ruv);
}

// Apply PBR
Expand Down
14 changes: 7 additions & 7 deletions src/shaders/world_noise.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ R"(
//INSERT: WORLD_NOISE1
// World Noise

uniform sampler2D region_blend_map : hint_default_black, filter_linear, repeat_disable;
uniform float noise_scale = 2.0;
uniform float noise_height = 300.0;
uniform float noise_blend_near = 0.5;
uniform float noise_blend_far = 1.0;
uniform sampler2D _region_blend_map : hint_default_black, filter_linear, repeat_disable;
uniform float noise_scale : hint_range(0, 20, 0.1) = 2.0;
uniform float noise_height : hint_range(0, 1000, 0.1) = 300.0;
uniform float noise_blend_near : hint_range(0, .95, 0.01) = 0.5;
uniform float noise_blend_far : hint_range(.05, 1, 0.01) = 1.0;

float hashv2(vec2 v) {
return fract(1e4 * sin(17.0 * v.x + v.y * 0.1) * (0.1 + abs(sin(v.y * 13.0 + v.x))));
Expand All @@ -35,8 +35,8 @@ float noise2D(vec2 st) {
// World Noise end
//INSERT: WORLD_NOISE2
// World Noise
float weight = texture(region_blend_map, (uv/float(region_map_size))+0.5).r;
float rmap_half_size = float(region_map_size)*.5;
float weight = texture(_region_blend_map, (uv/float(_region_map_size))+0.5).r;
float rmap_half_size = float(_region_map_size)*.5;
if(abs(uv.x) > rmap_half_size+.5 || abs(uv.y) > rmap_half_size+.5) {
weight = 0.;
} else {
Expand Down
31 changes: 19 additions & 12 deletions src/terrain_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
int Terrain3D::_debug_level{ ERROR };

void Terrain3D::_initialize() {
LOG(INFO, "Checking storage, texture list, signal, and terrain initialization");
LOG(INFO, "Checking material, storage, texture_list, signal, and mesh initialization");

// Make blank objects if needed
if (_material.is_null()) {
Expand All @@ -46,15 +46,15 @@ void Terrain3D::_initialize() {

// Connect signals
if (!_texture_list->is_connected("textures_changed", Callable(_material.ptr(), "_update_texture_arrays"))) {
LOG(DEBUG, "Connecting texture_list.textures_changed to _storage._update_texture_arrays()");
LOG(DEBUG, "Connecting texture_list.textures_changed to _material->_update_texture_arrays()");
_texture_list->connect("textures_changed", Callable(_material.ptr(), "_update_texture_arrays"));
}
if (!_storage->is_connected("region_size_changed", Callable(_material.ptr(), "set_region_size"))) {
LOG(DEBUG, "Connecting region_size_changed signal to set_region_size()");
LOG(DEBUG, "Connecting region_size_changed signal to _material->set_region_size()");
_storage->connect("region_size_changed", Callable(_material.ptr(), "set_region_size"));
}
if (!_storage->is_connected("regions_changed", Callable(_material.ptr(), "_update_regions"))) {
LOG(DEBUG, "Connecting regions_changed signal to _update_regions()");
LOG(DEBUG, "Connecting regions_changed signal to _material->_update_regions()");
_storage->connect("regions_changed", Callable(_material.ptr(), "_update_regions"));
}
if (!_storage->is_connected("height_maps_changed", Callable(this, "update_aabbs"))) {
Expand All @@ -64,7 +64,7 @@ void Terrain3D::_initialize() {

// Initialize the system
if (!_initialized && _is_inside_world && is_inside_tree()) {
_material->set_region_size(_storage->get_region_size());
_material->initialize(_storage->get_region_size());
_storage->_update_regions(true); // generate map arrays
_texture_list->_update_list(); // generate texture arrays
_build(_clipmap_levels, _clipmap_size);
Expand Down Expand Up @@ -668,8 +668,10 @@ void Terrain3D::snap(Vector3 p_cam_pos) {
}

void Terrain3D::update_aabbs() {
ERR_FAIL_COND_MSG(_meshes.is_empty(), "Terrain meshes have not been built yet");
ERR_FAIL_COND_MSG(!_storage.is_valid(), "Terrain3DStorage is not valid");
if (_meshes.is_empty() || _storage.is_null()) {
LOG(DEBUG, "Update AABB called before terrain meshes built. Returning.");
return;
}

Vector2 height_range = _storage->get_height_range();
LOG(DEBUG_CONT, "Updating AABBs. Total height range: ", height_range, ", extra cull margin: ", _cull_margin);
Expand Down Expand Up @@ -814,16 +816,21 @@ void Terrain3D::_notification(int p_what) {

case NOTIFICATION_EDITOR_PRE_SAVE: {
LOG(INFO, "NOTIFICATION_EDITOR_PRE_SAVE");
if (!_texture_list.is_valid()) {
LOG(DEBUG, "Save requested, but no valid texture list. Skipping");
} else {
_texture_list->save();
}
if (!_storage.is_valid()) {
LOG(DEBUG, "Save requested, but no valid storage. Skipping");
} else {
_storage->save();
}
if (!_material.is_valid()) {
LOG(DEBUG, "Save requested, but no valid material. Skipping");
} else {
_material->save();
}
if (!_texture_list.is_valid()) {
LOG(DEBUG, "Save requested, but no valid texture list. Skipping");
} else {
_texture_list->save();
}
break;
}

Expand Down
Loading

0 comments on commit 0d7b1b7

Please sign in to comment.