diff --git a/Terrain3D.vcxproj b/Terrain3D.vcxproj index a58901ee2..c89d24a7c 100644 --- a/Terrain3D.vcxproj +++ b/Terrain3D.vcxproj @@ -152,6 +152,7 @@ + @@ -204,6 +205,7 @@ + diff --git a/doc/docs/shader_design.md b/doc/docs/shader_design.md index 5be22b8fd..11dbe5024 100644 --- a/doc/docs/shader_design.md +++ b/doc/docs/shader_design.md @@ -38,7 +38,7 @@ Finally `vertex()` sets the UV and UV2 coordinates, and the height of the mesh v The first step is calculating the terrain normals. This shared between the `vertex()` and `fragment()` functions. Clipmap terrain vertices spread out at lower LODs causing certain things like normals look strange when you look in the distance as the vertices used for calculation suddenly separate at further LODs. So we switch from normals calculated per vertex to per pixel when the pixel is farther than `vertex_normal_distance`. -The exact distance that the transition from per vertex to per pixel normal calculations occurs can be adjusted from the default of 192m via the `vertex_normals_distance` uniform. +The exact distance that the transition from per vertex to per pixel normal calculations occurs can be adjusted from the default of 192m via the `_normals_distance` uniform. Generating normals in the shader works fine and modern GPUs can handle the load of 2 - 3 additional height lookups and the on-the-fly calculations. Doing this saves 3-4MB VRAM per region. diff --git a/project/addons/terrain_3d/shader/core/t3d_managed_uniforms.gdshaderinc b/project/addons/terrain_3d/shader/core/t3d_managed_uniforms.gdshaderinc index a4334a62a..0c76ad807 100644 --- a/project/addons/terrain_3d/shader/core/t3d_managed_uniforms.gdshaderinc +++ b/project/addons/terrain_3d/shader/core/t3d_managed_uniforms.gdshaderinc @@ -51,6 +51,10 @@ uniform uint _mouse_layer = 0x80000000u; // Layer 32 // The height-based or default blend sharpness value uniform float _blending_sharpness = 0.87; +// The distance beyond which normals will be calculated per-pixel, if +// NORMALS_BY_DISTANCE is defined. +uniform float _normals_distance; + // ***************************************************************************** // END: CORE INTERNALS // ----------------------------------------------------------------------------- @@ -99,13 +103,4 @@ uniform float _blending_sharpness = 0.87; // ***************************************************************************** // END: MOD UNIFORMS // ----------------------------------------------------------------------------- -// BEGIN: UNSORTED STAGING AREA -// ***************************************************************************** - -// Public uniforms -uniform float vertex_normals_distance : hint_range(0, 1024) = 128.0; - -// ***************************************************************************** -// END: UNSORTED STAGING AREA -// ----------------------------------------------------------------------------- #endif diff --git a/project/addons/terrain_3d/shader/vertex/t3d_bg_world_noise_type1_funcs.gdshaderinc b/project/addons/terrain_3d/shader/vertex/t3d_bg_world_noise_type1_funcs.gdshaderinc new file mode 100644 index 000000000..556e3df67 --- /dev/null +++ b/project/addons/terrain_3d/shader/vertex/t3d_bg_world_noise_type1_funcs.gdshaderinc @@ -0,0 +1,81 @@ +// WORLD_NOISE1 + +//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)))); } + +// Explicitly Optimized - changes made should have (mostly) already been inlined by the compiler but why take chances. +float ihashv2(ivec2 iv) { + vec2 v = sin( vec2( iv * ivec2(17, 13) ) + vec2( float(iv.y) * 0.1, float(iv.x) ) ); + v.y = ( abs(v.y) + 0.1 ); + return fract( 1e4 * v.x * v.y ); } + +// alternate optimization, unclear which performs better between this and above. +//float hashv2(ivec2 iv) { +// vec2 v = vec2(iv); +// v = sin( vec2( +// fma( 17., v.x, v.y * 0.1 ), +// fma( 13., v.y, v.x ) ) ); +// return fract( 1e4 * v.x * ( 0.1 + abs(v.y) ) ); } + +/* vec3 orig_noise2D(vec2 x) { + vec2 f = fract(x); + // Quintic Hermine Curve. Similar to SmoothStep() + vec2 u = f*f*f*(f*(f*6.0-15.0)+10.0); + vec2 du = 30.0*f*f*((f*f)-(f*2.0)+1.0); + // vec2 du = 30.0*f*f*(f*(f-2.0)+1.0); // Original + + vec2 p = floor(x); + + // Four corners in 2D of a tile + float a = hashv2( p+vec2(0,0) ); + float b = hashv2( p+vec2(1,0) ); + float c = hashv2( p+vec2(0,1) ); + float d = hashv2( p+vec2(1,1) ); + + // Mix 4 corner percentages + float k0 = a; + float k1 = b - a; + float k2 = c - a; + float k3 = a - b - c + d; + return vec3( k0 + k1 * u.x + k2 * u.y + k3 * u.x * u.y, + du * ( vec2(k1, k2) + k3 * u.yx) ); } */ + +// https://iquilezles.org/articles/morenoise/ +// Explicitly Optimized - changes made should already be in effect from compiler optimization but that's not always the case. +vec3 noise2D(vec2 x) { + const ivec2 i01 = ivec2(0,1); + + vec2 f = fract(x); + // Quintic Hermine Curve. Similar to SmoothStep() + vec2 f2 = f*f; + vec4 udu = f2.xyxy * vec4( + f * (fma(f, (fma(f, vec2(6.0), -vec2(15.0))), vec2(10.0))), + 30.0 * (fma (f, (f - 2.0), vec2(1.0)))); + ivec2 p = ivec2(floor(x)); + + // Four corners in 2D of a tile + vec4 abcd = vec4( ihashv2(p), ihashv2(p + i01.yx), ihashv2(p + i01.xy), ihashv2(p + 1) ); + + // Mix 4 corner percentages + vec3 k123 = abcd.yzx - abcd.xxy; + k123.z = k123.z - abcd.z + abcd.w; + udu.zw *= fma(udu.yx, k123.zz, k123.xy); + k123 *= udu.xyx; + return vec3( fma(k123.z, udu.y, abcd.x + k123.x + k123.y), udu.zw ); } + +float bg_world(vec2 p) { + float a = 0.0; + float b = 1.0; + vec2 d = vec2(0.0); + int octaves = int( clamp( + float(_bg_world_max_octaves) - floor(v_vertex_xz_dist/(_bg_world_lod_distance)), + float(_bg_world_min_octaves), float(_bg_world_max_octaves)) ); + for( int i=0; i < octaves; i++ ) { + vec3 n = noise2D(p); + d += n.yz; + a += b * n.x / (1.0 + dot(d,d)); + b *= 0.5; + p = mat2( vec2(0.8, -0.6), vec2(0.6, 0.8) ) * p * 2.0; } + return a; } + +// World Noise end \ No newline at end of file diff --git a/src/propsets/ALL_SETS.h b/src/propsets/ALL_SETS.h index f26d1e0a3..6dff6f878 100644 --- a/src/propsets/ALL_SETS.h +++ b/src/propsets/ALL_SETS.h @@ -15,6 +15,7 @@ #include "propsets/_TINTING.h" #include "propsets/_AUTO_TEXTURING.h" #include "propsets/_UV_DISTORTION.h" +#include "propsets/_NORMALS.h" #include "propsets/_DEBUG_VIEWS.h" // ################################################################################ @@ -70,10 +71,11 @@ within the generated shader, so if ever this happens it's not a big deal. // section. It defines the functions that will provide the values to the placeholder // in-line "help" textareas. #define __MAKE_MANAGED_HELP()\ - HELP_BLEND()\ - HELP_MULTI()\ HELP_BG_WORLD()\ + HELP_BLEND()\ + HELP_NORMS()\ HELP_TINTING()\ + HELP_MULTI()\ HELP_AUTO_TEXTURING()\ HELP_UVDIST()\ HELP_DEBUG()\ @@ -81,20 +83,22 @@ within the generated shader, so if ever this happens it's not a big deal. // This generates all of the actual functions within the class .cpp file. #define MAKE_MANAGED_FUNCTIONS()\ - MAKE_BLENDING_FUNCTIONS()\ - MAKE_MULTI_SCALING_FUNCTIONS()\ MAKE_BG_WORLD_FUNCTIONS()\ + MAKE_BLENDING_FUNCTIONS()\ + MAKE_NORMALS_FUNCTIONS()\ MAKE_TINTING_FUNCTIONS()\ + MAKE_MULTI_SCALING_FUNCTIONS()\ MAKE_AUTO_TEXTURING_FUNCTIONS()\ MAKE_UV_DISTORTION_FUNCTIONS()\ MAKE_DEBUG_VIEW_FUNCTIONS() // This binds the necessary get/set functions for each managed property group. #define BIND_MANAGED_VARS()\ - BIND_BLENDING_VARS()\ - BIND_MULTI_SCALING_VARS()\ BIND_BG_WORLD_VARS()\ + BIND_BLENDING_VARS()\ + BIND_NORMALS_VARS()\ BIND_TINTING_VARS()\ + BIND_MULTI_SCALING_VARS()\ BIND_AUTO_TEXTURING_VARS()\ BIND_UV_DISTORTION_VARS()\ BIND_DEBUG_VIEW_VARS() @@ -103,38 +107,42 @@ within the generated shader, so if ever this happens it's not a big deal. // it's probably best to call this after BIND_MANAGED_VARS, but I'm not sure // it really matters. #define ADD_MANAGED_PROPS()\ - PROPS_BLENDING()\ - PROPS_MULTI_SCALING()\ PROPS_BG_WORLD()\ + PROPS_BLENDING()\ + PROPS_NORMALS()\ PROPS_TINTING()\ + PROPS_MULTI_SCALING()\ PROPS_AUTO_TEXTURING()\ PROPS_UV_DISTORTION()\ PROPS_DEBUG_VIEW() #define PRIVATE_MANAGED_VARS()\ - PRIV_BLENDING_VARS()\ - PRIV_MULTI_SCALING_VARS()\ PRIV_BG_WORLD_VARS()\ + PRIV_BLENDING_VARS()\ + PRIV_NORMALS_VARS()\ PRIV_TINTING_VARS()\ + PRIV_MULTI_SCALING_VARS()\ PRIV_AUTO_TEXTURING_VARS()\ PRIV_UV_DISTORTION_VARS()\ PRIV_DEBUG_VIEW_VARS() #define PUBLIC_MANAGED_FUNCS()\ __MAKE_MANAGED_HELP()\ - PUBLIC_BLENDING_FUNCS()\ - PUBLIC_MULTI_SCALING_FUNCS()\ PUBLIC_BG_WORLD_FUNCS()\ + PUBLIC_BLENDING_FUNCS()\ + PUBLIC_NORMALS_FUNCS()\ PUBLIC_TINTING_FUNCS()\ + PUBLIC_MULTI_SCALING_FUNCS()\ PUBLIC_AUTO_TEXTURING_FUNCS()\ PUBLIC_UV_DISTORTION_FUNCS()\ PUBLIC_DEBUG_VIEW_FUNCS() #define UPDATE_MANAGED_VARS()\ - UPDATE_BLENDING()\ - UPDATE_MULTI_SCALING()\ UPDATE_BG_WORLD()\ + UPDATE_BLENDING()\ + UPDATE_NORMALS()\ UPDATE_TINTING()\ + UPDATE_MULTI_SCALING()\ UPDATE_AUTO_TEXTURING()\ UPDATE_UV_DISTORTION() diff --git a/src/propsets/_NORMALS.h b/src/propsets/_NORMALS.h new file mode 100644 index 000000000..25c0f5703 --- /dev/null +++ b/src/propsets/_NORMALS.h @@ -0,0 +1,73 @@ +#pragma once + +#ifndef TERRAIN3D_NORMALS_H +#define TERRAIN3D_NORMALS_H + +//Code Templates for Terrain3D Managed GLSL/Godot NORMALS Properties + +// ################################################################################ +#pragma region _NORMALS_ + +// ******************* +// ** NORMALS ** +// ******************* + +#pragma region _HELP_ +#define HELP_NORMS()\ + ADD_HELP_TOPIC_DECL(normals, R"( +A mesh normal is the outward facing direction of a surface at any point. +3D graphics smoothly shifts that normal over the entire surface. How +that normal is calculated impacts quality and speed inversely, with +per-pixel providing the highest quality, but per-vertex having the fastest +speed. A third option is available, where beyond a certain distance +it uses per-pixel, because the mesh density is much lower there and it +looks better per-pixel. But up-close where the mesh density is very high, +per-pixel is less necessary. It still looks better but it's harder to tell +and in many situations it might be good enough, and offer faster speeds. + +The Distance setting lets you adjust the vertex/pixel range if the By_Distance +option is selected. +)") +#pragma endregion _HELP_ + +#pragma region _normals_helper_macros_ +#define GETR_NORMS(m_bind_id, m_type) GSTR( normals_##m_bind_id, m_type ) +#define VAR_NORMS(m_bind_id, m_type, m_value) VARR( normals_##m_bind_id, m_type##, m_value ) +#define PROP_NORMS(m_member_id, m_var_type, ...) __PROP_GENGRP( normals, m_member_id, m_var_type, __VA_ARGS__ ) +#define BIND_NORMS(m_bind_id, m_param_label) ADD_BIND( normals_##m_bind_id, m_param_label ) +#define SETUPD_NORMS(m_bind_id, m_type, s_log_desc) SETUPD__GRP( normals, normals_##m_bind_id, m_type, s_log_desc ) +#define _SETPR_NORMS(m_bind_id, m_type, s_log_desc) __SETPR_GRP( normals, normals_##m_bind_id, m_type, s_log_desc ) +#define _UPDSH_NORMS(m_member_id) UPDATE_SHADER( normals_##m_member_id ) +#pragma endregion _normals_helper_macros_ + +#define UPDATE_NORMALS() UPDATE_GROUP(normals) + +#define PRIV_NORMALS_VARS()\ + GROUP_VARS(normals)\ + VAR_NORMS(quality, NormalCalculation, BY_DISTANCE)\ + VAR_NORMS(distance, float, 128.0f) + +#define PUBLIC_NORMALS_FUNCS()\ + GETR_NORMS(quality, NormalCalculation)\ + GETR_NORMS(distance, float) + +#define BIND_NORMALS_VARS() \ + BIND_NORMS(quality, strategy)\ + BIND_NORMS(distance, range) + +#define PROPS_NORMALS()\ + ADD_GROUP("Mesh Normals", "normals_");\ + PROP_NORMS(quality, INT, ENUM, "Pixel,Vertex,By_Distance")\ + PROP_NORMS(distance, FLOAT, RANGE, "0.0,1024.0,1., or_greater")\ + ADD_INLINE_HELP(normals, Mesh Normals, About Mesh Normals) + +#define MAKE_NORMALS_FUNCTIONS() \ + UPDATE_GRP_START_CON(normals, true)\ + _UPDSH_NORMS(distance)\ + UPDATE_GRP_END()\ + SETUPD_NORMS(quality, NormalCalculation, "Quality: ")\ + _SETPR_NORMS(distance, float, "Distance: ") + +#pragma endregion _NORMALS_ +// ################################################################################ +#endif \ No newline at end of file diff --git a/src/shaders/main.glsl b/src/shaders/main.glsl index 136d64ea8..3e3c026e9 100644 --- a/src/shaders/main.glsl +++ b/src/shaders/main.glsl @@ -19,55 +19,10 @@ R"( * */ -#if defined(BG_WORLD_ENABLED) // WORLD_NOISE1 - -uniform sampler2D _region_blend_map : hint_default_black, filter_linear, repeat_disable; - -float hashf(float f) { - return fract(sin(f) * 1e4); } - -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)))); } - -// https://iquilezles.org/articles/morenoise/ -vec3 noise2D(vec2 x) { - vec2 f = fract(x); - // Quintic Hermine Curve. Similar to SmoothStep() - vec2 u = f*f*f*(f*(f*6.0-15.0)+10.0); - vec2 du = 30.0*f*f*(f*(f-2.0)+1.0); - - vec2 p = floor(x); - - // Four corners in 2D of a tile - float a = hashv2( p+vec2(0,0) ); - float b = hashv2( p+vec2(1,0) ); - float c = hashv2( p+vec2(0,1) ); - float d = hashv2( p+vec2(1,1) ); - - // Mix 4 corner percentages - float k0 = a; - float k1 = b - a; - float k2 = c - a; - float k3 = a - b - c + d; - return vec3( k0 + k1 * u.x + k2 * u.y + k3 * u.x * u.y, - du * ( vec2(k1, k2) + k3 * u.yx) ); } - -float bg_world(vec2 p) { - float a = 0.0; - float b = 1.0; - vec2 d = vec2(0.0); - int octaves = int( clamp( - float(_bg_world_max_octaves) - floor(v_vertex_xz_dist/(_bg_world_lod_distance)), - float(_bg_world_min_octaves), float(_bg_world_max_octaves)) ); - for( int i=0; i < octaves; i++ ) { - vec3 n = noise2D(p); - d += n.yz; - a += b * n.x / (1.0 + dot(d,d)); - b *= 0.5; - p = mat2( vec2(0.8, -0.6), vec2(0.6, 0.8) ) * p * 2.0; } - return a; } - -// World Noise end +#if defined(BG_WORLD_ENABLED) + // WORLD_NOISE_TYPE1_FUNCS + uniform sampler2D _region_blend_map : hint_default_black, filter_linear, repeat_disable; + #include "res://addons/terrain_3d/shader/vertex/t3d_bg_world_noise_type1_funcs.gdshaderinc" #endif // 1 lookup @@ -98,8 +53,12 @@ float get_height(vec2 uv) { vec3 get_normal(vec2 uv, out vec3 tangent, out vec3 binormal) { 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) { + // Use vertex normals within radius of _normals_distance, and along region borders. + if (v_region_border_mask > 0.5 + #if defined(NORMALS_BY_DISTANCE) + || v_vertex_xz_dist < _normals_distance + #endif + ) { normal = normalize(v_normal); } else { height = get_height(uv); @@ -278,11 +237,17 @@ void fragment() { vec2 uv2 = UV2 + v_uv2_offset; // Calculate Terrain Normals. 4 lookups - 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; + #if defined(NORMALS_PER_VERTEX) + vec3 w_normal = normalize(v_normal); + vec3 w_tangent = cross(w_normal, vec3(0, 0, 1)); + vec3 w_binormal = cross(w_normal, w_tangent); + #else + vec3 w_tangent, w_binormal; + vec3 w_normal = get_normal(uv2, w_tangent, w_binormal); + #endif + NORMAL = mat3(VIEW_MATRIX) * w_normal; + TANGENT = mat3(VIEW_MATRIX) * w_tangent; + BINORMAL = mat3(VIEW_MATRIX) * w_binormal; // Idenfity 4 vertices surrounding this pixel vec2 texel_pos = uv; diff --git a/src/terrain_3d_material.cpp b/src/terrain_3d_material.cpp index d23e438e0..d264bfb86 100644 --- a/src/terrain_3d_material.cpp +++ b/src/terrain_3d_material.cpp @@ -166,14 +166,19 @@ String Terrain3DMaterial::_get_current_defines() { Array _defs; _add_if_true(_defs, _blending_texture_filtering == LINEAR, "TEXTURE_SAMPLERS_LINEAR", "TEXTURE_SAMPLERS_NEAREST"); _add_if_true(_defs, _blending_by_height, "HEIGHT_BLENDING_ENABLED"); - _add_if_true(_defs, _tinting_enabled, "NOISE_TINT_ENABLED"); + _add_if_true(_defs, _tinting_enabled, "NOISE_TINT_ENABLED"); _add_if_true(_defs, _auto_texturing_enabled, "AUTO_TEXTURING_ENABLED"); + _add_if_true(_defs, _multi_scaling_enabled, "MULTI_SCALING_ENABLED"); + _add_if_true(_defs, _uv_distortion_enabled, "UV_DISTORTION_ENABLED"); + _add_if_true(_defs, _bg_world_fill >= NOISE, "BG_WORLD_ENABLED"); _add_if_true(_defs, _bg_world_fill == FLAT, "BG_FLAT_ENABLED"); _add_if_true(_defs, _bg_world_fill == NONE, "BG_NONE"); - _add_if_true(_defs, _multi_scaling_enabled, "MULTI_SCALING_ENABLED"); - _add_if_true(_defs, _uv_distortion_enabled, "UV_DISTORTION_ENABLED"); - + + _add_if_true(_defs, _normals_quality == PIXEL, "NORMALS_PER_PIXEL"); + _add_if_true(_defs, _normals_quality == VERTEX, "NORMALS_PER_VERTEX"); + _add_if_true(_defs, _normals_quality == BY_DISTANCE, "NORMALS_BY_DISTANCE"); + _add_if_true(_defs, _debug_view_checkered, "DEBUG_CHECKERED"); _add_if_true(_defs, _debug_view_grey, "DEBUG_GREY"); _add_if_true(_defs, _debug_view_heightmap, "DEBUG_HEIGHTMAP"); @@ -685,6 +690,67 @@ bool Terrain3DMaterial::_get(const StringName &p_name, Variant &r_property) cons return true; } +// Original unoptimized version retained for reference (more readable) +//float Terrain3DMaterial::hashv2(Vector2 v) { +// return Math::fract(10000.0f * sin(17.0f * v.x + v.y * 0.1f) * (0.1f + abs(sin(v.y * 13.0f + v.x)))); } + +float Terrain3DMaterial::ihashv2(Vector2i iv) { + Vector2 v = Vector2( iv * Vector2i(17, 13) ) + Vector2( float(iv.y) * 0.1, float(iv.x) ); + v.x = sin(v.x); + v.y = ( abs(sin(v.y)) + 0.1 ); + return Math::fract( 1e4 * v.x * v.y ); } + +// https://iquilezles.org/articles/morenoise/ +Vector3 Terrain3DMaterial::noise2D(Vector2 x) { + Vector2 f = Vector2(Math::fract(x.x),Math::fract(x.y)); + // Quintic Hermine Curve. Similar to SmoothStep() + Vector2 f2 = f*f; + Vector2 u = f2*f*(f*(f*6.0f-Vector2(15.0f, 15.0f))+Vector2(10.0f, 10.0f)); + Vector2 du = 30.0f*f2*(f*(f-Vector2(2.0f, 2.0f))+Vector2(1.0f, 1.0f)); + + Vector2i p = Vector2i(Math::floor(x.x), Math::floor(x.y)); + + // Four corners in 2D of a tile + float a = ihashv2( p ); + float b = ihashv2( p+Vector2i(1,0) ); + float c = ihashv2( p+Vector2i(0,1) ); + float d = ihashv2( p+Vector2i(1,1) ); + + // Mix 4 corner percentages + float k0 = a; + float k1 = b - a; + float k2 = c - a; + float k3 = a - b - c + d; + Vector2 _direvs = du * ( Vector2(k1, k2) + k3 * Vector2(u.y,u.x) ); + return Vector3( k0 + k1 * u.x + k2 * u.y + k3 * u.x * u.y, _direvs.x, _direvs.y ); } + +int Terrain3DMaterial::get_octaves_by_distance(float d) { + return int( Math::clamp( + float(_bg_world_max_octaves) - Math::floor(d /(_bg_world_lod_distance)), + float(_bg_world_min_octaves), float(_bg_world_max_octaves)) ); } + +float Terrain3DMaterial::noise_type1(Vector2 p, int octaves) { + float a = 0.0f; + float b = 1.0f; + Vector2 d = Vector2(0.0f, 0.0f); + for( int i=0; i < octaves; i++ ) { + Vector3 n = noise2D(p); + d += Vector2(n.y, n.z); + a += b * n.x / (1.0f + d.dot(d)); + b *= 0.5f; + p = Vector2(0.8f * p.x + 0.6f * p.y, -0.6f * p.x + 0.8f * p.y) *2.0f; } + return a; } + +float Terrain3DMaterial::get_unweighted_generated_height(Vector3 worldPos, int octaves) { + worldPos += _bg_world_offset; + float dx, dy; + const float _offs = 16.0f * 1024.0f; + // Should the half pixel be added before, after, or not at all? Not at all for now. + dx = ((worldPos.x+_offs)/1024.0f)-16.f; + dy = ((worldPos.z+_offs)/1024.0f)-16.f; + Vector2 uv = Vector2(dx, dy); + return noise_type1( uv * _bg_world_scale * .1 , octaves) * (_bg_world_height*10.0f) + (_bg_world_offset.y * 100.f); } + String Terrain3DMaterial::_format_string_for_inline_help (String _source) { return _source.replace("\n\n", "[__TEMP_CRLF__]").replace("\n", "").replace("[__TEMP_CRLF__]", "\n\n"); } @@ -692,9 +758,6 @@ void Terrain3DMaterial::_safe_material_set_param(StringName _param, Variant _val if (_initialized && _material.is_valid()) { RS->material_set_param(_material, _param, _value); } } - - - MAKE_MANAGED_FUNCTIONS() void Terrain3DMaterial::_bind_methods() { @@ -704,6 +767,9 @@ void Terrain3DMaterial::_bind_methods() { BIND_ENUM_CONSTANT(NOISE); BIND_ENUM_CONSTANT(LINEAR); BIND_ENUM_CONSTANT(NEAREST); + BIND_ENUM_CONSTANT(PIXEL); + BIND_ENUM_CONSTANT(VERTEX); + BIND_ENUM_CONSTANT(BY_DISTANCE); // Private ClassDB::bind_method(D_METHOD("_set_shader_parameters", "dict"), &Terrain3DMaterial::_set_shader_parameters); @@ -721,6 +787,9 @@ void Terrain3DMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shader_param", "name", "value"), &Terrain3DMaterial::set_shader_param); ClassDB::bind_method(D_METHOD("get_shader_param", "name"), &Terrain3DMaterial::get_shader_param); ClassDB::bind_method(D_METHOD("save"), &Terrain3DMaterial::save); + ClassDB::bind_method(D_METHOD("get_unweighted_generated_height"), &Terrain3DMaterial::get_unweighted_generated_height); + ClassDB::bind_method(D_METHOD("get_octaves_by_distance"), &Terrain3DMaterial::get_octaves_by_distance); + ClassDB::bind_method(D_METHOD("noise_type1"), &Terrain3DMaterial::noise_type1); ADD_MANAGED_PROPS() diff --git a/src/terrain_3d_material.h b/src/terrain_3d_material.h index 4dd2f164f..fc7fe1352 100644 --- a/src/terrain_3d_material.h +++ b/src/terrain_3d_material.h @@ -32,6 +32,12 @@ class Terrain3DMaterial : public Resource { NEAREST, }; + enum NormalCalculation { + PIXEL, + VERTEX, + BY_DISTANCE + }; + private: PRIVATE_MANAGED_VARS() @@ -70,6 +76,13 @@ class Terrain3DMaterial : public Resource { void _set_shader_parameters(const Dictionary &p_dict); Dictionary _get_shader_parameters() const { return _shader_params; } + int get_octaves_by_distance(float d); + float get_unweighted_generated_height(Vector3 worldPos, int octaves); + float noise_type1(Vector2 p, int octaves); + Vector3 noise2D(Vector2 x); + float ihashv2(Vector2i iv); + + public: Terrain3DMaterial(){}; void initialize(int p_region_size); @@ -111,5 +124,6 @@ class Terrain3DMaterial : public Resource { VARIANT_ENUM_CAST(Terrain3DMaterial::WorldBackground); VARIANT_ENUM_CAST(Terrain3DMaterial::TextureFiltering); +VARIANT_ENUM_CAST(Terrain3DMaterial::NormalCalculation); #endif // TERRAIN3D_MATERIAL_CLASS_H \ No newline at end of file