From e85459dcd12b6fd683d94f088d65a22c9c1320a4 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Sat, 21 May 2022 12:17:49 +0200 Subject: [PATCH] Add Cone and Cylinder shapes to FogVolume This complements the existing Ellipsoid and Box local fog shapes. This can be used to represent a light cone coming from a SpotLight. --- doc/classes/FogVolume.xml | 7 +++--- doc/classes/RenderingServer.xml | 18 +++++++++++---- scene/3d/fog_volume.cpp | 2 +- .../renderer_rd/renderer_scene_render_rd.cpp | 3 ++- .../renderer_rd/renderer_storage_rd.cpp | 2 ++ .../renderer_rd/shaders/volumetric_fog.glsl | 23 +++++++++++++++++-- servers/rendering_server.cpp | 3 +++ servers/rendering_server.h | 3 +++ 8 files changed, 49 insertions(+), 12 deletions(-) diff --git a/doc/classes/FogVolume.xml b/doc/classes/FogVolume.xml index d28a6a8783b..3f2ee3035c5 100644 --- a/doc/classes/FogVolume.xml +++ b/doc/classes/FogVolume.xml @@ -11,14 +11,15 @@ - Sets the size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX]. + Sets the size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX]. [b]Note:[/b] Thin fog volumes may appear to flicker when the camera moves or rotates. This can be alleviated by increasing [member ProjectSettings.rendering/environment/volumetric_fog/volume_depth] (at a performance cost) or by decreasing [member Environment.volumetric_fog_length] (at no performance cost, but at the cost of lower fog range). Alternatively, the [FogVolume] can be made thicker and use a lower density in the [member material]. + [b]Note:[/b] If [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_CONE] or [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], the cone/cylinder will be adjusted to fit within the extents. Non-uniform scaling of cone/cylinder shapes via the [member extents] property is not supported, but you can scale the [FogVolume] node instead. Sets the [Material] to be used by the [FogVolume]. Can be either a [FogMaterial] or a custom [ShaderMaterial]. - - Sets the shape of the [FogVolume] to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX], or [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD]. + + Sets the shape of the [FogVolume] to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD]. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index b8f26f75c91..4d039227cef 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -1186,7 +1186,7 @@ - Sets the size of the fog volume when shape is [constant FOG_VOLUME_SHAPE_ELLIPSOID] or [constant FOG_VOLUME_SHAPE_BOX]. + Sets the size of the fog volume when shape is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX]. @@ -1202,7 +1202,7 @@ - Sets the shape of the fog volume to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX], or [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD]. + Sets the shape of the fog volume to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD]. @@ -3931,14 +3931,22 @@ - [FogVolume] will be shaped like an ellipsoid. + [FogVolume] will be shaped like an ellipsoid (stretched sphere). - + + [FogVolume] will be shaped like a cone pointing upwards (in local coordinates). The cone's angle is set automatically to fill the extents. The cone will be adjusted to fit within the extents. Rotate the [FogVolume] node to reorient the cone. Non-uniform scaling via extents is not supported (scale the [FogVolume] node instead). + + + [FogVolume] will be shaped like an upright cylinder (in local coordinates). Rotate the [FogVolume] node to reorient the cylinder. The cylinder will be adjusted to fit within the extents. Non-uniform scaling via extents is not supported (scale the [FogVolume] node instead). + + [FogVolume] will be shaped like a box. - + [FogVolume] will have no shape, will cover the whole world and will not be culled. + + Use bilinear scaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less then [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling. diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp index 8d05254a25c..8fbadb4b7be 100644 --- a/scene/3d/fog_volume.cpp +++ b/scene/3d/fog_volume.cpp @@ -41,7 +41,7 @@ void FogVolume::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material"), &FogVolume::get_material); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Ellipsoid,Box,World"), "set_shape", "get_shape"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Ellipsoid (Local),Cone (Local),Cylinder (Local),Box (Local),World (Global)"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "FogMaterial,ShaderMaterial"), "set_material", "get_material"); } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 9e798e8b6dc..85a132e6dfe 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -4365,7 +4365,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e RS::FogVolumeShape volume_type = storage->fog_volume_get_shape(fog_volume); Vector3 extents = storage->fog_volume_get_extents(fog_volume); - if (volume_type == RS::FOG_VOLUME_SHAPE_BOX || volume_type == RS::FOG_VOLUME_SHAPE_ELLIPSOID) { + if (volume_type != RS::FOG_VOLUME_SHAPE_WORLD) { + // Local fog volume. Vector3i points[8]; points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index cf642c38c9c..1b9e0faa008 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -97,6 +97,8 @@ AABB RendererStorageRD::fog_volume_get_aabb(RID p_fog_volume) const { switch (fog_volume->shape) { case RS::FOG_VOLUME_SHAPE_ELLIPSOID: + case RS::FOG_VOLUME_SHAPE_CONE: + case RS::FOG_VOLUME_SHAPE_CYLINDER: case RS::FOG_VOLUME_SHAPE_BOX: { AABB aabb; aabb.position = -fog_volume->extents; diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl index a2a4c918946..eee609fb485 100644 --- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl @@ -186,12 +186,31 @@ void main() { float sdf = -1.0; if (params.shape == 0) { - //Ellipsoid + // Ellipsoid // https://www.shadertoy.com/view/tdS3DG float k0 = length(local_pos.xyz / params.extents); float k1 = length(local_pos.xyz / (params.extents * params.extents)); sdf = k0 * (k0 - 1.0) / k1; } else if (params.shape == 1) { + // Cone + // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm + + // Compute the cone angle automatically to fit within the volume's extents. + float inv_height = 1.0 / max(0.001, params.extents.y); + float radius = 1.0 / max(0.001, (min(params.extents.x, params.extents.z) * 0.5)); + float hypotenuse = sqrt(radius * radius + inv_height * inv_height); + float rsin = radius / hypotenuse; + float rcos = inv_height / hypotenuse; + vec2 c = vec2(rsin, rcos); + + float q = length(local_pos.xz); + sdf = max(dot(c, vec2(q, local_pos.y - params.extents.y)), -params.extents.y - local_pos.y); + } else if (params.shape == 2) { + // Cylinder + // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm + vec2 d = abs(vec2(length(local_pos.xz), local_pos.y)) - vec2(min(params.extents.x, params.extents.z), params.extents.y); + sdf = min(max(d.x, d.y), 0.0) + length(max(d, 0.0)); + } else if (params.shape == 3) { // Box // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm vec3 q = abs(local_pos.xyz) - params.extents; @@ -199,7 +218,7 @@ void main() { } float cull_mask = 1.0; //used to cull cells that do not contribute - if (params.shape <= 1) { + if (params.shape <= 3) { #ifndef SDF_USED cull_mask = 1.0 - smoothstep(-0.1, 0.0, sdf); #endif diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 766ca88e346..8f285aeaad0 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2140,8 +2140,11 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("fog_volume_set_material", "fog_volume", "material"), &RenderingServer::fog_volume_set_material); BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_ELLIPSOID); + BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_CONE); + BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_CYLINDER); BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_BOX); BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_WORLD); + BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_MAX); /* VISIBILITY NOTIFIER */ diff --git a/servers/rendering_server.h b/servers/rendering_server.h index d622571a478..1ac48053d83 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -724,8 +724,11 @@ public: enum FogVolumeShape { FOG_VOLUME_SHAPE_ELLIPSOID, + FOG_VOLUME_SHAPE_CONE, + FOG_VOLUME_SHAPE_CYLINDER, FOG_VOLUME_SHAPE_BOX, FOG_VOLUME_SHAPE_WORLD, + FOG_VOLUME_SHAPE_MAX, }; virtual void fog_volume_set_shape(RID p_fog_volume, FogVolumeShape p_shape) = 0;