Selaa lähdekoodia

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.
Hugo Locurcio 3 vuotta sitten
vanhempi
commit
e85459dcd1

+ 4 - 3
doc/classes/FogVolume.xml

@@ -11,14 +11,15 @@
 	</tutorials>
 	<members>
 		<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] 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 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].
 		</member>
-		<member name="shape" type="int" setter="set_shape" getter="get_shape" enum="RenderingServer.FogVolumeShape" default="1">
-			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].
+		<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_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD].
 		</member>
 	</members>
 </class>

+ 13 - 5
doc/classes/RenderingServer.xml

@@ -1186,7 +1186,7 @@
 			<argument index="0" name="fog_volume" type="RID" />
 			<argument index="1" name="extents" type="Vector3" />
 			<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>
 		</method>
 		<method name="fog_volume_set_material">
@@ -1202,7 +1202,7 @@
 			<argument index="0" name="fog_volume" type="RID" />
 			<argument index="1" name="shape" type="int" enum="RenderingServer.FogVolumeShape" />
 			<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>
 		</method>
 		<method name="force_draw">
@@ -3931,14 +3931,22 @@
 		<constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX" value="6" enum="ParticlesCollisionHeightfieldResolution">
 		</constant>
 		<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 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.
 		</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.
 		</constant>
+		<constant name="FOG_VOLUME_SHAPE_MAX" value="5" enum="FogVolumeShape">
+		</constant>
 		<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.
 		</constant>

+ 1 - 1
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");
 }
 

+ 2 - 1
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);

+ 2 - 0
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;

+ 21 - 2
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

+ 3 - 0
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 */
 

+ 3 - 0
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;