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.
This commit is contained in:
Hugo Locurcio 2022-05-21 12:17:49 +02:00
parent 1c99b7415f
commit e85459dcd1
No known key found for this signature in database
GPG Key ID: 39E8F8BE30B0A49C
8 changed files with 49 additions and 12 deletions

View File

@ -11,14 +11,15 @@
</tutorials> </tutorials>
<members> <members>
<member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)"> <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)">
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] 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.
</member> </member>
<member name="material" type="Material" setter="set_material" getter="get_material"> <member name="material" type="Material" setter="set_material" getter="get_material">
Sets the [Material] to be used by the [FogVolume]. Can be either a [FogMaterial] or a custom [ShaderMaterial]. Sets the [Material] to be used by the [FogVolume]. Can be either a [FogMaterial] or a custom [ShaderMaterial].
</member> </member>
<member name="shape" type="int" setter="set_shape" getter="get_shape" enum="RenderingServer.FogVolumeShape" default="1"> <member name="shape" type="int" setter="set_shape" getter="get_shape" enum="RenderingServer.FogVolumeShape" default="3">
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].
</member> </member>
</members> </members>
</class> </class>

View File

@ -1186,7 +1186,7 @@
<argument index="0" name="fog_volume" type="RID" /> <argument index="0" name="fog_volume" type="RID" />
<argument index="1" name="extents" type="Vector3" /> <argument index="1" name="extents" type="Vector3" />
<description> <description>
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].
</description> </description>
</method> </method>
<method name="fog_volume_set_material"> <method name="fog_volume_set_material">
@ -1202,7 +1202,7 @@
<argument index="0" name="fog_volume" type="RID" /> <argument index="0" name="fog_volume" type="RID" />
<argument index="1" name="shape" type="int" enum="RenderingServer.FogVolumeShape" /> <argument index="1" name="shape" type="int" enum="RenderingServer.FogVolumeShape" />
<description> <description>
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].
</description> </description>
</method> </method>
<method name="force_draw"> <method name="force_draw">
@ -3931,14 +3931,22 @@
<constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX" value="6" enum="ParticlesCollisionHeightfieldResolution"> <constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX" value="6" enum="ParticlesCollisionHeightfieldResolution">
</constant> </constant>
<constant name="FOG_VOLUME_SHAPE_ELLIPSOID" value="0" enum="FogVolumeShape"> <constant name="FOG_VOLUME_SHAPE_ELLIPSOID" value="0" enum="FogVolumeShape">
[FogVolume] will be shaped like an ellipsoid. [FogVolume] will be shaped like an ellipsoid (stretched sphere).
</constant> </constant>
<constant name="FOG_VOLUME_SHAPE_BOX" value="1" enum="FogVolumeShape"> <constant name="FOG_VOLUME_SHAPE_CONE" value="1" enum="FogVolumeShape">
[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).
</constant>
<constant name="FOG_VOLUME_SHAPE_CYLINDER" value="2" enum="FogVolumeShape">
[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).
</constant>
<constant name="FOG_VOLUME_SHAPE_BOX" value="3" enum="FogVolumeShape">
[FogVolume] will be shaped like a box. [FogVolume] will be shaped like a box.
</constant> </constant>
<constant name="FOG_VOLUME_SHAPE_WORLD" value="2" enum="FogVolumeShape"> <constant name="FOG_VOLUME_SHAPE_WORLD" value="4" enum="FogVolumeShape">
[FogVolume] will have no shape, will cover the whole world and will not be culled. [FogVolume] will have no shape, will cover the whole world and will not be culled.
</constant> </constant>
<constant name="FOG_VOLUME_SHAPE_MAX" value="5" enum="FogVolumeShape">
</constant>
<constant name="VIEWPORT_SCALING_3D_MODE_BILINEAR" value="0" enum="ViewportScaling3DMode"> <constant name="VIEWPORT_SCALING_3D_MODE_BILINEAR" value="0" enum="ViewportScaling3DMode">
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. 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.
</constant> </constant>

View File

@ -41,7 +41,7 @@ void FogVolume::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_material"), &FogVolume::get_material); 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::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"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "FogMaterial,ShaderMaterial"), "set_material", "get_material");
} }

View File

@ -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); RS::FogVolumeShape volume_type = storage->fog_volume_get_shape(fog_volume);
Vector3 extents = storage->fog_volume_get_extents(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]; 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[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); 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);

View File

@ -97,6 +97,8 @@ AABB RendererStorageRD::fog_volume_get_aabb(RID p_fog_volume) const {
switch (fog_volume->shape) { switch (fog_volume->shape) {
case RS::FOG_VOLUME_SHAPE_ELLIPSOID: case RS::FOG_VOLUME_SHAPE_ELLIPSOID:
case RS::FOG_VOLUME_SHAPE_CONE:
case RS::FOG_VOLUME_SHAPE_CYLINDER:
case RS::FOG_VOLUME_SHAPE_BOX: { case RS::FOG_VOLUME_SHAPE_BOX: {
AABB aabb; AABB aabb;
aabb.position = -fog_volume->extents; aabb.position = -fog_volume->extents;

View File

@ -192,6 +192,25 @@ void main() {
float k1 = length(local_pos.xyz / (params.extents * params.extents)); float k1 = length(local_pos.xyz / (params.extents * params.extents));
sdf = k0 * (k0 - 1.0) / k1; sdf = k0 * (k0 - 1.0) / k1;
} else if (params.shape == 1) { } 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 // Box
// https://iquilezles.org/www/articles/distfunctions/distfunctions.htm // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
vec3 q = abs(local_pos.xyz) - params.extents; 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 float cull_mask = 1.0; //used to cull cells that do not contribute
if (params.shape <= 1) { if (params.shape <= 3) {
#ifndef SDF_USED #ifndef SDF_USED
cull_mask = 1.0 - smoothstep(-0.1, 0.0, sdf); cull_mask = 1.0 - smoothstep(-0.1, 0.0, sdf);
#endif #endif

View File

@ -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); 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_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_BOX);
BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_WORLD); BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_WORLD);
BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_MAX);
/* VISIBILITY NOTIFIER */ /* VISIBILITY NOTIFIER */

View File

@ -724,8 +724,11 @@ public:
enum FogVolumeShape { enum FogVolumeShape {
FOG_VOLUME_SHAPE_ELLIPSOID, FOG_VOLUME_SHAPE_ELLIPSOID,
FOG_VOLUME_SHAPE_CONE,
FOG_VOLUME_SHAPE_CYLINDER,
FOG_VOLUME_SHAPE_BOX, FOG_VOLUME_SHAPE_BOX,
FOG_VOLUME_SHAPE_WORLD, FOG_VOLUME_SHAPE_WORLD,
FOG_VOLUME_SHAPE_MAX,
}; };
virtual void fog_volume_set_shape(RID p_fog_volume, FogVolumeShape p_shape) = 0; virtual void fog_volume_set_shape(RID p_fog_volume, FogVolumeShape p_shape) = 0;