Skip to content

Commit

Permalink
add decal inserts modify editor inserts
Browse files Browse the repository at this point in the history
  • Loading branch information
Xtarsia committed Sep 26, 2024
1 parent ce7ef67 commit 15b2ed5
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 46 deletions.
1 change: 1 addition & 0 deletions Terrain3D.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@
<None Include="README.md" />
<None Include="SConstruct" />
<None Include="src\shaders\debug_views.glsl" />
<None Include="src\shaders\compatibility.glsl" />
<None Include="src\shaders\main.glsl" />
<None Include="src\shaders\uniforms.glsl" />
<None Include="src\shaders\world_noise.glsl" />
Expand Down
18 changes: 18 additions & 0 deletions project/addons/terrain_3d/editor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ func _edit(p_object: Object) -> void:
terrain.set_editor(editor)
ui.set_visible(true)
terrain.set_meta("_edit_lock_", true)

if terrain.is_compatibility_mode():
ui.decal_timer.timeout.connect(func():
var mat_rid: RID = terrain.material.get_material_rid()
RenderingServer.material_set_param(mat_rid, "_editor_decal_visible", false))

if terrain.storage:
ui.terrain_menu.directory_setup.directory_setup_popup()
Expand Down Expand Up @@ -179,6 +184,19 @@ func _forward_3d_gui_input(p_viewport_camera: Camera3D, p_event: InputEvent) ->
## Update decal
ui.decal.global_position = mouse_global_position
ui.update_decal()

## Compatibility "Decal"
if terrain.is_compatibility_mode():
var mat_rid: RID = terrain.material.get_material_rid()
if ui.decal.visible:
RenderingServer.material_set_param(mat_rid, "_editor_decal_position", Vector2(mouse_global_position.x,mouse_global_position.z))
RenderingServer.material_set_param(mat_rid, "_editor_decal_rotation", ui.decal.rotation.y)
RenderingServer.material_set_param(mat_rid, "_editor_decal_size", ui.brush_data.get("size"))
RenderingServer.material_set_param(mat_rid, "_editor_decal_color", ui.decal.modulate)
RenderingServer.material_set_param(mat_rid, "_editor_decal", ui.decal.texture_albedo.get_rid())
RenderingServer.material_set_param(mat_rid, "_editor_decal_visible", true)
else:
RenderingServer.material_set_param(mat_rid, "_editor_decal_visible", true)

## Update region highlight
var region_position: Vector2 = ( Vector2(mouse_global_position.x, mouse_global_position.z) \
Expand Down
19 changes: 19 additions & 0 deletions src/shaders/compatibility.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright © 2024 Cory Petkovsek, Roope Palmroos, and Contributors.

R"(

//INSERT: COMPATIBILITY_DEFINES
// Compatibility overrides
#define fma(a, b, c) (a) * (b) + (c)
#define dFdxCoarse(a) dFdx(a)
#define dFdyCoarse(a) dFdy(a)
#define textureQueryLod(a, b) vec4(0.0)
#define texelOffset(b, c) ivec3(ivec2(b.xy * _region_size + c -0.4979), int(b.z))
#define textureGather(a, b) vec4( \
texelFetch(a, texelOffset(b, vec2(0,1)), 0).r, \
texelFetch(a, texelOffset(b, vec2(1,1)), 0).r, \
texelFetch(a, texelOffset(b, vec2(1,0)), 0).r, \
texelFetch(a, texelOffset(b, vec2(0,0)), 0).r \
)

)"
29 changes: 29 additions & 0 deletions src/shaders/editor_functions.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,33 @@ R"(
ALBEDO *= vec3(.5, .0, .85);
}

//INSERT: EDITOR_SETUP_DECAL
uniform sampler2D _editor_decal : source_color, filter_linear, repeat_disable;
uniform vec2 _editor_decal_position;
uniform float _editor_decal_size;
uniform float _editor_decal_rotation;
uniform vec3 _editor_decal_color : source_color;
uniform bool _editor_decal_visible = false;

// expects uv (Texture/world space 0 to +/- inf 1m units).
vec3 get_decal(vec3 albedo, vec2 uv) {
if (!_editor_decal_visible) {
return albedo;
}
float size = 1. / _editor_decal_size;
float cosa = cos(_editor_decal_rotation);
float sina = sin(_editor_decal_rotation);
vec2 decal_uv = (vec2(cosa * uv.x - sina * uv.y, sina * uv.x + cosa * uv.y) -
vec2(cosa * _editor_decal_position.x - sina * _editor_decal_position.y,
sina * _editor_decal_position.x + cosa * _editor_decal_position.y) * _vertex_density) * size * _vertex_spacing;
if (abs(decal_uv.x) > 0.499 || abs(decal_uv.y) > 0.499) {
return albedo;
}
float decal = smoothstep(0.1,1.0,texture(_editor_decal,decal_uv + 0.5).r);
return mix(albedo, _editor_decal_color, clamp(decal * 0.15, 0.0, 0.25));
}

//INSERT: EDITOR_RENDER_DECAL
ALBEDO = get_decal(ALBEDO, uv);

)"
29 changes: 17 additions & 12 deletions src/shaders/gpu_depth.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,30 @@ render_mode unshaded;
uniform sampler2D depth_texture : source_color, hint_depth_texture, filter_nearest, repeat_disable;

uniform float camera_far = 100000.0;

// Mobile renderer HDR mode has limit of 1 or 2. Pack full range depth to RG
// https://gamedev.stackexchange.com/questions/201151/24bit-float-to-rgb
vec3 encode_rg(float value) {
vec2 kEncodeMul = vec2(1.0, 255.0);
float kEncodeBit = 1.0 / 255.0;
vec2 color = kEncodeMul * value / camera_far;
color = fract(color);
color.x -= color.y * kEncodeBit;
return vec3(color, 0.);
}
uniform bool compatibility = false;

void fragment() {
float depth = textureLod(depth_texture, SCREEN_UV, 0.).x;
if (compatibility) {
depth = depth * 2.0 - 1.0;
}
vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth);
vec4 view = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
view.xyz /= view.w;
float depth_linear = -view.z;
ALBEDO = encode_rg(depth_linear); // Encoded value for Mobile

// Normalize depth to the range 0 - 1
highp float scaledDepth = clamp(depth_linear / 100000.0, 0.0, 1.0);

// Encode using 127 steps, which map to the 128 - 255 range.
// Avoids precision loss for compatability and mobile renderer
// 21bit depth value
highp float r = (floor(scaledDepth * 127.0) + 128.0) / 255.0;
highp float g = (floor(fract(scaledDepth * 127.0) * 127.0) + 128.0) / 255.0;
highp float b = (floor(fract(scaledDepth * 127.0 * 127.0) * 127.0) + 128.0) / 255.0;

ALBEDO = vec3(r, g, b); // Return encoded value, required for Mobile & Compatibility renderers

}

)"
14 changes: 0 additions & 14 deletions src/shaders/uniforms.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,6 @@

R"(

//INSERT: COMPATIBILITY_DEFINES
// Compatibility overrides
#define fma(a, b, c) (a) * (b) + (c)
#define dFdxCoarse(a) dFdx(a)
#define dFdyCoarse(a) dFdy(a)
#define textureQueryLod(a, b) vec4(0.0)
#define texelOffset(b, c) ivec3(ivec2(b.xy * _region_size + c -0.4979), int(b.z))
#define textureGather(a, b) vec4( \
texelFetch(a, texelOffset(b, vec2(0,1)), 0).r, \
texelFetch(a, texelOffset(b, vec2(1,1)), 0).r, \
texelFetch(a, texelOffset(b, vec2(1,0)), 0).r, \
texelFetch(a, texelOffset(b, vec2(0,0)), 0).r \
)

//INSERT: TEXTURE_SAMPLERS_LINEAR
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;
Expand Down
34 changes: 22 additions & 12 deletions src/terrain_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void Terrain3D::_initialize() {
// Initialize the system
if (!_initialized && _is_inside_world && is_inside_tree()) {
_data->initialize(this);
_material->initialize(this, _compatibility);
_material->initialize(this);
_assets->initialize(this);
_instancer->initialize(this);
_build_meshes(_mesh_lods, _mesh_size);
Expand Down Expand Up @@ -617,6 +617,7 @@ void Terrain3D::_setup_mouse_picking() {
Ref<ShaderMaterial> shader_material;
shader_material.instantiate();
shader_material->set_shader(shader);
shader_material->set_shader_parameter("compatibility", _compatibility);
_mouse_quad->set_surface_override_material(0, shader_material);
_mouse_quad->set_position(Vector3(0.f, 0.f, -0.5f));

Expand Down Expand Up @@ -1206,22 +1207,30 @@ Vector3 Terrain3D::get_intersection(const Vector3 &p_src_pos, const Vector3 &p_d
// Read the depth pixel from the camera viewport
Color screen_depth = vp_img->get_pixel(0, 0);

// Get position from depth packed in RG - unpack back to float.
// Needed for Mobile renderer
// https://gamedev.stackexchange.com/questions/201151/24bit-float-to-rgb
Vector2 screen_rg = Vector2(screen_depth.r, screen_depth.g);
real_t normalized_distance = screen_rg.dot(Vector2(1.f, 1.f / 255.f));
if (normalized_distance < 0.00001f) {
// Get position from depth packed in RGB - unpack back to float.
// Forward+ is 16bit, mobile is 10bit and compatibility is 8bit.
// Compatibility also has precision loss for values below 0.5, so
// we use only the top half of the range, for 21bit depth encoded.
real_t r = floor((screen_depth.r * 256.0) - 128.0);
real_t g = floor((screen_depth.g * 256.0) - 128.0);
real_t b = floor((screen_depth.b * 256.0) - 128.0);

// Decode the full depth value
real_t decoded_depth = (r + g / 127.0 + b / (127.0 * 127.0)) / 127.0;

if (decoded_depth < 0.00001f) {
return V3_MAX;
}
// Necessary for a correct value depth = 1
if (normalized_distance > 0.9999f) {
normalized_distance = 1.0f;
if (decoded_depth > 0.99999f) {
decoded_depth = 1.0f;
}

// Denormalize distance to get real depth and terrain position
real_t depth = normalized_distance * _mouse_cam->get_far();
point = _mouse_cam->get_global_position() + direction * depth;
// Denormalize distance to get real depth and terrain position.
decoded_depth *= _mouse_cam->get_far();

// Project the camera position by the depth value to get the intersection point.
point = _mouse_cam->get_global_position() + direction * decoded_depth;
}

return point;
Expand Down Expand Up @@ -1511,6 +1520,7 @@ void Terrain3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_gi_mode"), &Terrain3D::get_gi_mode);
ClassDB::bind_method(D_METHOD("set_cull_margin", "margin"), &Terrain3D::set_cull_margin);
ClassDB::bind_method(D_METHOD("get_cull_margin"), &Terrain3D::get_cull_margin);
ClassDB::bind_method(D_METHOD("is_compatibility_mode"), &Terrain3D::is_compatibility_mode);

// Utility
ClassDB::bind_method(D_METHOD("get_intersection", "src_pos", "direction"), &Terrain3D::get_intersection);
Expand Down
3 changes: 2 additions & 1 deletion src/terrain_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ class Terrain3D : public Node3D {
String _data_directory;
bool _is_inside_world = false;
bool _initialized = false;
bool _compatibility = false;

// Object references
Terrain3DData *_data = nullptr;
Expand Down Expand Up @@ -97,6 +96,7 @@ class Terrain3D : public Node3D {
RenderingServer::ShadowCastingSetting _cast_shadows = RenderingServer::SHADOW_CASTING_SETTING_ON;
GeometryInstance3D::GIMode _gi_mode = GeometryInstance3D::GI_MODE_STATIC;
real_t _cull_margin = 0.0f;
bool _compatibility = false;

// Mouse cursor
SubViewport *_mouse_vp = nullptr;
Expand Down Expand Up @@ -209,6 +209,7 @@ class Terrain3D : public Node3D {
GeometryInstance3D::GIMode get_gi_mode() const { return _gi_mode; }
void set_cull_margin(const real_t p_margin);
real_t get_cull_margin() const { return _cull_margin; };
bool is_compatibility_mode() const { return _compatibility; };

// Processing
void snap(const Vector3 &p_cam_pos);
Expand Down
30 changes: 25 additions & 5 deletions src/terrain_3d_material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

void Terrain3DMaterial::_preload_shaders() {
// Preprocessor loading of external shader inserts

_parse_shader(
#include "shaders/compatibility.glsl"
, "uniforms");
_parse_shader(
#include "shaders/uniforms.glsl"
, "uniforms");
Expand Down Expand Up @@ -152,11 +154,26 @@ String Terrain3DMaterial::_generate_shader_code() const {

String Terrain3DMaterial::_inject_editor_code(const String &p_shader) const {
String shader = p_shader;
int idx = p_shader.rfind("}");
Array insert_names;
// Insert before vertex()
int idx = shader.find("void vertex() {") - 1;
if (idx < 0) {
return shader;
}
Array insert_names;
if (_compatibility) {
insert_names.push_back("EDITOR_SETUP_DECAL");
}
for (int i = 0; i < insert_names.size(); i++) {
String insert = _shader_code[insert_names[i]];
shader = shader.insert(idx - 1, "\n" + insert);
idx += insert.length();
}
// Inserted at the end of the shader
idx = shader.rfind("}");
if (idx < 0) {
return shader;
}
insert_names.clear();
if (_debug_view_checkered) {
insert_names.push_back("DEBUG_CHECKERED");
}
Expand Down Expand Up @@ -205,6 +222,9 @@ String Terrain3DMaterial::_inject_editor_code(const String &p_shader) const {
if (_show_navigation || (IS_EDITOR && _terrain && _terrain->get_editor() && _terrain->get_editor()->get_tool() == Terrain3DEditor::NAVIGATION)) {
insert_names.push_back("EDITOR_NAVIGATION");
}
if (_compatibility) {
insert_names.push_back("EDITOR_RENDER_DECAL");
}
for (int i = 0; i < insert_names.size(); i++) {
String insert = _shader_code[insert_names[i]];
shader = shader.insert(idx - 1, "\n" + insert);
Expand Down Expand Up @@ -384,15 +404,15 @@ void Terrain3DMaterial::_set_shader_parameters(const Dictionary &p_dict) {
// This function serves as the constructor which is initialized by the class Terrain3D.
// Godot likes to create resource objects at startup, so this prevents it from creating
// uninitialized materials.
void Terrain3DMaterial::initialize(Terrain3D *p_terrain, const bool p_compatibility) {
void Terrain3DMaterial::initialize(Terrain3D *p_terrain) {
if (p_terrain != nullptr) {
_terrain = p_terrain;
} else {
LOG(ERROR, "Initialization failed, p_terrain is null");
return;
}
LOG(INFO, "Initializing material");
_compatibility = p_compatibility;
_compatibility = _terrain->is_compatibility_mode();
_preload_shaders();
_material = RS->material_create();
_shader.instantiate();
Expand Down
4 changes: 2 additions & 2 deletions src/terrain_3d_material.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Terrain3DMaterial : public Resource {
Ref<Shader> _shader_override; // User's shader we copy code from
mutable TypedArray<StringName> _active_params; // All shader params in the current shader
mutable Dictionary _shader_params; // Public shader params saved to disk
bool _compatibility = false; // If true, some shader functions will be overriden useing #defines.
bool _compatibility = false; // If true, some shader functions will be overriden using #defines.

// Material Features
WorldBackground _world_background = FLAT;
Expand Down Expand Up @@ -81,7 +81,7 @@ class Terrain3DMaterial : public Resource {

public:
Terrain3DMaterial() {}
void initialize(Terrain3D *p_terrain, const bool p_compatibility = false);
void initialize(Terrain3D *p_terrain);
~Terrain3DMaterial();

void update();
Expand Down

0 comments on commit 15b2ed5

Please sign in to comment.