Addition of FogVolumes, FogShaders, FogMaterial, and overhaul of VolumetricFog

Co-authored-by: Brian Semrau <brian.semrau@gmail.com>
This commit is contained in:
clayjohn 2021-10-03 04:28:55 -07:00
parent 9307808987
commit 1b2cd9f251
51 changed files with 2979 additions and 777 deletions

View file

@ -248,23 +248,41 @@
<member name="tonemap_white" type="float" setter="set_tonemap_white" getter="get_tonemap_white" default="1.0">
The white reference value for tonemapping. Only effective if the [member tonemap_mode] isn't set to [constant TONE_MAPPER_LINEAR].
</member>
<member name="volumetric_fog_density" type="float" setter="set_volumetric_fog_density" getter="get_volumetric_fog_density" default="0.01">
<member name="volumetric_fog_albedo" type="Color" setter="set_volumetric_fog_albedo" getter="get_volumetric_fog_albedo" default="Color(1, 1, 1, 1)">
The [Color] of the volumetric fog when interacting with lights. Mist and fog have an albedo close to [code]Color(1, 1, 1, 1)[/code] while smoke has a darker albedo.
</member>
<member name="volumetric_fog_ambient_inject" type="float" setter="set_volumetric_fog_ambient_inject" getter="get_volumetric_fog_ambient_inject" default="0.0">
Scales the strength of ambient light used in the volumetric fog. A value of [code]0[/code] means that ambient light will not impact the volumetric fog.
</member>
<member name="volumetric_fog_anisotropy" type="float" setter="set_volumetric_fog_anisotropy" getter="get_volumetric_fog_anisotropy" default="0.2">
The direction of scattered light as it goes through the volumetric fog. A value close [code]1[/code] means almost all light is scattered forward. A value close to [code]0[/code] means light is scattered equally in all directions. A value close to [code]-1[/code] means light is scattered mostly backward. Fog and mist scatter light slightly forward, while smoke scatters light equally in all directions.
</member>
<member name="volumetric_fog_density" type="float" setter="set_volumetric_fog_density" getter="get_volumetric_fog_density" default="0.05">
The base density of the volumetric fog. Set this to the lowest density you want to have globally.
</member>
<member name="volumetric_fog_detail_spread" type="float" setter="set_volumetric_fog_detail_spread" getter="get_volumetric_fog_detail_spread" default="2.0">
The distribution of size down the length of the froxel buffer. A higher value compresses the froxels closer to the camera and places more detail closer to the camera.
</member>
<member name="volumetric_fog_emission" type="Color" setter="set_volumetric_fog_emission" getter="get_volumetric_fog_emission" default="Color(0, 0, 0, 1)">
The emitted light from the volumetric fog. Even with emission, volumetric fog will not cast light onto other surfaces. Emission is useful to establish an ambient color. As the volumetric fog effect uses single-scattering only, fog tends to need a little bit of emission to soften the harsh shadows.
</member>
<member name="volumetric_fog_emission_energy" type="float" setter="set_volumetric_fog_emission_energy" getter="get_volumetric_fog_emission_energy" default="1.0">
The brightness of the emitted light from the volumetric fog.
</member>
<member name="volumetric_fog_enabled" type="bool" setter="set_volumetric_fog_enabled" getter="is_volumetric_fog_enabled" default="false">
Enables the volumetric fog effect. Volumetric fog uses a screen-aligned froxel buffer to calculate accurate volumetric scattering in the short to medium range. Volumetric fog interacts with [FogVolume]s and lights to calculate localized and global fog. Volumetric fog uses a PBR single-scattering model based on extinction, scattering, and emission which it exposes to users as density, albedo, and emission.
</member>
<member name="volumetric_fog_gi_inject" type="float" setter="set_volumetric_fog_gi_inject" getter="get_volumetric_fog_gi_inject" default="0.0">
Scales the strength of Global Illumination used in the volumetric fog. A value of [code]0[/code] means that Global Illumination will not impact the volumetric fog.
</member>
<member name="volumetric_fog_length" type="float" setter="set_volumetric_fog_length" getter="get_volumetric_fog_length" default="64.0">
</member>
<member name="volumetric_fog_light" type="Color" setter="set_volumetric_fog_light" getter="get_volumetric_fog_light" default="Color(0, 0, 0, 1)">
</member>
<member name="volumetric_fog_light_energy" type="float" setter="set_volumetric_fog_light_energy" getter="get_volumetric_fog_light_energy" default="1.0">
The distance over which the volumetric fog is computed. Increase to compute fog over a greater range, decrease to add more detail when a long range is not needed. For best quality fog, keep this as low as possible.
</member>
<member name="volumetric_fog_temporal_reprojection_amount" type="float" setter="set_volumetric_fog_temporal_reprojection_amount" getter="get_volumetric_fog_temporal_reprojection_amount" default="0.9">
The amount by which to blend the last frame with the current frame. A higher number results in smoother volumetric fog, but makes "ghosting" much worse. A lower value reduces ghosting but can result in the per-frame temporal jitter becoming visible.
</member>
<member name="volumetric_fog_temporal_reprojection_enabled" type="bool" setter="set_volumetric_fog_temporal_reprojection_enabled" getter="is_volumetric_fog_temporal_reprojection_enabled" default="true">
Enables temporal reprojection in the volumetric fog. Temporal reprojection blends the current frame's volumetric fog with the last frame's volumetric fog to smooth out jagged edges. The performance cost is minimal, however it does lead to moving [FogVolume]s and [Light3D]s "ghosting" and leaving a trail behind them. When temporal reprojection is enabled, try to avoid moving [FogVolume]s or [Light3D]s too fast.
</member>
</members>
<constants>
@ -349,13 +367,5 @@
</constant>
<constant name="SDFGI_Y_SCALE_50_PERCENT" value="2" enum="SDFGIYScale">
</constant>
<constant name="VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED" value="0" enum="VolumetricFogShadowFilter">
</constant>
<constant name="VOLUMETRIC_FOG_SHADOW_FILTER_LOW" value="1" enum="VolumetricFogShadowFilter">
</constant>
<constant name="VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM" value="2" enum="VolumetricFogShadowFilter">
</constant>
<constant name="VOLUMETRIC_FOG_SHADOW_FILTER_HIGH" value="3" enum="VolumetricFogShadowFilter">
</constant>
</constants>
</class>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="FogMaterial" inherits="Material" version="4.0">
<brief_description>
[Material] used with a [FogVolume] to draw things with the volumetric fog effect.
</brief_description>
<description>
A [Material] resource that can be used by [FogVolume]s to draw volumetric effects.
</description>
<tutorials>
</tutorials>
<members>
<member name="albedo" type="Color" setter="set_albedo" getter="get_albedo" default="Color(1, 1, 1, 1)">
Sets the single-scattering [Color] of the [FogVolume]. Internally [member albedo] is converted into single-scattering which is additively blended with other [FogVolume]s and the [member Environment.volumetric_fog_albedo].
</member>
<member name="density" type="float" setter="set_density" getter="get_density" default="1.0">
Sets the density of the [FogVolume]. Denser objects are more opaque, but may suffer from under-sampling artifacts that look like stripes.
</member>
<member name="density_texture" type="Texture3D" setter="set_density_texture" getter="get_density_texture">
Sets a 3D texture that is used to scale the [member density] of the [FogVolume].
</member>
<member name="edge_fade" type="float" setter="set_edge_fade" getter="get_edge_fade" default="0.1">
Sets the hardness of the edges of the [FogVolume]. A higher number will result in softer edges while a lower number will result in harder edges.
</member>
<member name="emission" type="Color" setter="set_emission" getter="get_emission" default="Color(0, 0, 0, 1)">
Sets the [Color] of the light emitted by the [FogVolume]. Emitted light will not cast light or shadows on other objects, but can be useful for modulating the [Color] of the [FogVolume] independently from light sources.
</member>
<member name="height_falloff" type="float" setter="set_height_falloff" getter="get_height_falloff" default="0.0">
Sets the rate by which the height-based fog decreases in density as height increases in world space. A high falloff will result in a sharp transition, while a low falloff will result in a smoother transition. A value of [code]0[/code] results in uniform-density fog. The height threshold is determined by the height of the associated [FogVolume].
</member>
</members>
</class>

23
doc/classes/FogVolume.xml Normal file
View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="FogVolume" inherits="VisualInstance3D" version="4.0">
<brief_description>
A node used to add local fog with the volumetric fog effect.
</brief_description>
<description>
[FogVolume]s are used to add localized fog into the global volumetric fog effect.
Performance of [FogVolume]s is directly related to their relative size on the screen and the complexity of their attached [FogMaterial]. It is best to keep [FogVolume]s relatively small and simple where possible.
</description>
<tutorials>
</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].
</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>
</members>
</class>

View file

@ -1577,10 +1577,13 @@
Scales the distance over which samples are taken for subsurface scattering effect. Changing this does not impact performance, but higher values will result in significant artifacts as the samples will become obviously spread out. A lower value results in a smaller spread of scattered light.
</member>
<member name="rendering/environment/volumetric_fog/use_filter" type="int" setter="" getter="" default="1">
Enables filtering of the volumetric fog effect prior to integration. This substantially blurs the fog which reduces fine details but also smooths out harsh edges and aliasing artifacts. Disable when more detail is required.
</member>
<member name="rendering/environment/volumetric_fog/volume_depth" type="int" setter="" getter="" default="128">
<member name="rendering/environment/volumetric_fog/volume_depth" type="int" setter="" getter="" default="64">
Number of slices to use along the depth of the froxel buffer for volumetric fog. A lower number will be more efficient but may result in artifacts appearing during camera movement.
</member>
<member name="rendering/environment/volumetric_fog/volume_size" type="int" setter="" getter="" default="64">
Base size used to determine size of froxel buffer in the camera X-axis and Y-axis. The final size is scaled by the aspect ratio of the screen, so actual values may differ from what is set. Set a larger size for more detailed fog, set a smaller size for better performance.
</member>
<member name="rendering/global_illumination/gi/use_half_resolution" type="bool" setter="" getter="" default="false">
</member>

View file

@ -1120,13 +1120,16 @@
<argument index="0" name="env" type="RID" />
<argument index="1" name="enable" type="bool" />
<argument index="2" name="density" type="float" />
<argument index="3" name="light" type="Color" />
<argument index="4" name="light_energy" type="float" />
<argument index="5" name="length" type="float" />
<argument index="6" name="p_detail_spread" type="float" />
<argument index="7" name="gi_inject" type="float" />
<argument index="8" name="temporal_reprojection" type="bool" />
<argument index="9" name="temporal_reprojection_amount" type="float" />
<argument index="3" name="albedo" type="Color" />
<argument index="4" name="emission" type="Color" />
<argument index="5" name="emission_energy" type="float" />
<argument index="6" name="anisotropy" type="float" />
<argument index="7" name="length" type="float" />
<argument index="8" name="p_detail_spread" type="float" />
<argument index="9" name="gi_inject" type="float" />
<argument index="10" name="temporal_reprojection" type="bool" />
<argument index="11" name="temporal_reprojection_amount" type="float" />
<argument index="12" name="ambient_inject" type="float" />
<description>
</description>
</method>
@ -1134,6 +1137,7 @@
<return type="void" />
<argument index="0" name="active" type="bool" />
<description>
Enables filtering of the volumetric fog scattering buffer. This results in much smoother volumes with very few under-sampling artifacts.
</description>
</method>
<method name="environment_set_volumetric_fog_volume_size">
@ -1141,6 +1145,37 @@
<argument index="0" name="size" type="int" />
<argument index="1" name="depth" type="int" />
<description>
Sets the resolution of the volumetric fog's froxel buffer. [code]size[/code] is modified by the screen's aspect ratio and then used to set the width and height of the buffer. While [code]depth[/code] is directly used to set the depth of the buffer.
</description>
</method>
<method name="fog_volume_create">
<return type="RID" />
<description>
Creates a new fog volume and allocates an RID.
</description>
</method>
<method name="fog_volume_set_extents">
<return type="void" />
<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].
</description>
</method>
<method name="fog_volume_set_material">
<return type="void" />
<argument index="0" name="fog_volume" type="RID" />
<argument index="1" name="material" type="RID" />
<description>
Sets the [Material] of the fog volume. Can be either a [FogMaterial] or a custom [ShaderMaterial].
</description>
</method>
<method name="fog_volume_set_shape">
<return type="void" />
<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].
</description>
</method>
<method name="force_draw">
@ -1430,6 +1465,13 @@
Sets a margin to increase the size of the AABB when culling objects from the view frustum. This allows you to avoid culling objects that fall outside the view frustum. Equivalent to [member GeometryInstance3D.extra_cull_margin].
</description>
</method>
<method name="instance_set_ignore_culling">
<return type="void" />
<argument index="0" name="instance" type="RID" />
<argument index="1" name="enabled" type="bool" />
<description>
</description>
</method>
<method name="instance_set_layer_mask">
<return type="void" />
<argument index="0" name="instance" type="RID" />
@ -3417,7 +3459,10 @@
<constant name="SHADER_SKY" value="3" enum="ShaderMode">
Shader is a sky shader.
</constant>
<constant name="SHADER_MAX" value="4" enum="ShaderMode">
<constant name="SHADER_FOG" value="4" enum="ShaderMode">
Shader is a fog shader.
</constant>
<constant name="SHADER_MAX" value="5" enum="ShaderMode">
Represents the size of the [enum ShaderMode] enum.
</constant>
<constant name="MATERIAL_RENDER_PRIORITY_MIN" value="-128">
@ -3789,6 +3834,15 @@
</constant>
<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.
</constant>
<constant name="FOG_VOLUME_SHAPE_BOX" value="1" enum="FogVolumeShape">
[FogVolume] will be shaped like a box.
</constant>
<constant name="FOG_VOLUME_SHAPE_WORLD" value="2" enum="FogVolumeShape">
[FogVolume] will have no shape, will cover the whole world and will not be culled.
</constant>
<constant name="VIEWPORT_UPDATE_DISABLED" value="0" enum="ViewportUpdateMode">
Do not update the viewport.
</constant>
@ -4155,7 +4209,9 @@
</constant>
<constant name="INSTANCE_VISIBLITY_NOTIFIER" value="11" enum="InstanceType">
</constant>
<constant name="INSTANCE_MAX" value="12" enum="InstanceType">
<constant name="INSTANCE_FOG_VOLUME" value="12" enum="InstanceType">
</constant>
<constant name="INSTANCE_MAX" value="13" enum="InstanceType">
Represents the size of the [enum InstanceType] enum.
</constant>
<constant name="INSTANCE_GEOMETRY_MASK" value="14" enum="InstanceType">

View file

@ -60,5 +60,8 @@
<constant name="MODE_SKY" value="3" enum="Mode">
Mode used for drawing skies. Only works with shaders attached to [Sky] objects.
</constant>
<constant name="MODE_FOG" value="4" enum="Mode">
Mode used for setting the color and density of volumetric fog effect.
</constant>
</constants>
</class>

View file

@ -176,7 +176,10 @@
</constant>
<constant name="TYPE_SKY" value="8" enum="Type">
</constant>
<constant name="TYPE_MAX" value="9" enum="Type">
<constant name="TYPE_FOG" value="9" enum="Type">
A compute shader that runs for each froxel of the volumetric fog map.
</constant>
<constant name="TYPE_MAX" value="10" enum="Type">
Represents the size of the [enum Type] enum.
</constant>
<constant name="NODE_ID_INVALID" value="-1">

View file

@ -8052,9 +8052,9 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
ERR_FAIL_COND_MSG(p_x_groups > limits.maxComputeWorkGroupCount[0],
"Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")");
ERR_FAIL_COND_MSG(p_y_groups > limits.maxComputeWorkGroupCount[1],
"Dispatch amount of Y compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")");
"Dispatch amount of Y compute groups (" + itos(p_y_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[1]) + ")");
ERR_FAIL_COND_MSG(p_z_groups > limits.maxComputeWorkGroupCount[2],
"Dispatch amount of Z compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")");
"Dispatch amount of Z compute groups (" + itos(p_z_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[2]) + ")");
ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified.");
#endif

View file

@ -7035,6 +7035,10 @@ EditorNode::EditorNode() {
physical_sky_mat_convert.instantiate();
resource_conversion_plugins.push_back(physical_sky_mat_convert);
Ref<FogMaterialConversionPlugin> fog_mat_convert;
fog_mat_convert.instantiate();
resource_conversion_plugins.push_back(fog_mat_convert);
Ref<VisualShaderConversionPlugin> vshader_convert;
vshader_convert.instantiate();
resource_conversion_plugins.push_back(vshader_convert);

View file

@ -0,0 +1 @@
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4.5 9.0000002c-.2761429-.0000014-.5000014.2238571-.5.5-.0000014.2761429.2238571.5000008.5.4999998l8-.0000002c.276143.0000012.500001-.2238569.5-.4999998.000001-.2761429-.223857-.5000014-.5-.5z" fill="#45d7ff"/><path d="m3.5 11c-.2761429-.000001-.5000014.223857-.5.5-.0000014.276143.2238571.500001.5.5h5c.2761429.000001.500001-.223857.5-.5.000001-.276143-.2238571-.500001-.5-.5z" fill="#8045ff"/><path d="m5.5 13c-.2761424 0-.5.223858-.5.5s.2238576.5.5.5h5c.276142 0 .5-.223858.5-.5s-.223858-.5-.5-.5z" fill="#ff4596"/><path d="m15 7h-13.936663c.2611574 1 1.436663 1 1.436663 1h11.5s1 0 1-1z" fill="#45ffa2"/><path d="m13.857422 5h-10.857422s-2 0-2 1.5c0 .216176.0100075.3416435.063337.5h13.936663c0-1-1.5-1-1.5-1s.23811-.4733054.357422-1z" fill="#80ff45"/><path d="m11.152344 3h1.847656c-.730134-.4197888-1.344054-.2676656-1.847656 0z" fill="#ff4545"/><path d="m9.7089844 3h-6.2714844c-.4375 1-.4375 2-.4375 2h10.857422c.149158-.6584498.108902-1.4444139-.857422-2h-1.847656c-.696054.3699541-1.152344 1-1.152344 1s-.161454-.5556722-.2910156-1z" fill="#ffe345"/><path d="m6.5 1c-1.75 0-2.625 1-3.0625 2h6.2714844c-.2591912-.8888889-.8754469-2-3.2089844-2z" fill="#ff4545"/><path d="m10.5 11c-.276143-.000001-.500001.223857-.5.5-.000001.276143.223857.500001.5.5h2.5c.276143.000001.500001-.223857.5-.5.000001-.276143-.223857-.500001-.5-.5z" fill="#8045ff"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1 @@
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><g fill-opacity=".996078"><path d="m4.5 9.0000002c-.2761429-.0000014-.5000014.2238571-.5.5-.0000014.2761429.2238571.5000008.5.4999998l8-.0000002c.276143.0000012.500001-.2238569.5-.4999998.000001-.2761429-.223857-.5000014-.5-.5z"/><path d="m3.5 11c-.2761429-.000001-.5000014.223857-.5.5-.0000014.276143.2238571.500001.5.5h5c.2761429.000001.500001-.223857.5-.5.000001-.276143-.2238571-.500001-.5-.5z"/><path d="m5.5 13c-.2761424 0-.5.223858-.5.5s.2238576.5.5.5h5c.276142 0 .5-.223858.5-.5s-.223858-.5-.5-.5z"/></g><path d="m2.5 8s-1.5 0-1.5-1.5 2-1.5 2-1.5 0-4 3.5-4 3.5 3 3.5 3 1.260711-2 3-1 .5 3 .5 3 1.5 0 1.5 1-1 1-1 1z" fill-opacity=".99608"/><path d="m10.5 11c-.276143-.000001-.500001.223857-.5.5-.000001.276143.223857.500001.5.5h2.5c.276143.000001.500001-.223857.5-.5.000001-.276143-.223857-.500001-.5-.5z" fill-opacity=".996078"/></g></svg>

After

Width:  |  Height:  |  Size: 949 B

View file

@ -32,6 +32,7 @@
#include "editor/editor_scale.h"
#include "scene/gui/subviewport_container.h"
#include "scene/resources/fog_material.h"
#include "scene/resources/particles_material.h"
#include "scene/resources/sky_material.h"
@ -477,3 +478,40 @@ Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> &
smat->set_name(mat->get_name());
return smat;
}
String FogMaterialConversionPlugin::converts_to() const {
return "ShaderMaterial";
}
bool FogMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
Ref<FogMaterial> mat = p_resource;
return mat.is_valid();
}
Ref<Resource> FogMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
Ref<FogMaterial> mat = p_resource;
ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
Ref<ShaderMaterial> smat;
smat.instantiate();
Ref<Shader> shader;
shader.instantiate();
String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
shader->set_code(code);
smat->set_shader(shader);
List<PropertyInfo> params;
RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
smat->set_shader_param(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
return smat;
}

View file

@ -152,4 +152,13 @@ public:
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override;
};
class FogMaterialConversionPlugin : public EditorResourceConversionPlugin {
GDCLASS(FogMaterialConversionPlugin, EditorResourceConversionPlugin);
public:
virtual String converts_to() const override;
virtual bool handles(const Ref<Resource> &p_resource) const override;
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override;
};
#endif // MATERIAL_EDITOR_PLUGIN_H

View file

@ -41,6 +41,7 @@
#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/cpu_particles_3d.h"
#include "scene/3d/decal.h"
#include "scene/3d/fog_volume.h"
#include "scene/3d/gpu_particles_3d.h"
#include "scene/3d/gpu_particles_collision_3d.h"
#include "scene/3d/joint_3d.h"
@ -5272,3 +5273,119 @@ void Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo(
#undef ADD_VTX
}
////
FogVolumeGizmoPlugin::FogVolumeGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/fog_volume", Color(0.5, 0.7, 1));
create_material("shape_material", gizmo_color);
gizmo_color.a = 0.15;
create_material("shape_material_internal", gizmo_color);
create_handle_material("handles");
}
bool FogVolumeGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return (Object::cast_to<FogVolume>(p_spatial) != nullptr);
}
String FogVolumeGizmoPlugin::get_gizmo_name() const {
return "FogVolume";
}
int FogVolumeGizmoPlugin::get_priority() const {
return -1;
}
String FogVolumeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
return "Extents";
}
Variant FogVolumeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
return Vector3(p_gizmo->get_spatial_node()->call("get_extents"));
}
void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
Node3D *sn = p_gizmo->get_spatial_node();
Transform3D gt = sn->get_global_transform();
Transform3D gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
Vector3 axis;
axis[p_id] = 1.0;
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = ra[p_id];
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
d = 0.001;
}
Vector3 he = sn->call("get_extents");
he[p_id] = d;
sn->call("set_extents", he);
}
void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
Node3D *sn = p_gizmo->get_spatial_node();
if (p_cancel) {
sn->call("set_extents", p_restore);
return;
}
UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Fog Volume Extents"));
ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
ur->add_undo_method(sn, "set_extents", p_restore);
ur->commit_action();
}
void FogVolumeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Node3D *cs = p_gizmo->get_spatial_node();
p_gizmo->clear();
if (RS::FogVolumeShape(int(p_gizmo->get_spatial_node()->call("get_shape"))) != RS::FOG_VOLUME_SHAPE_WORLD) {
const Ref<Material> material =
get_material("shape_material", p_gizmo);
const Ref<Material> material_internal =
get_material("shape_material_internal", p_gizmo);
Ref<Material> handles_material = get_material("handles");
Vector<Vector3> lines;
AABB aabb;
aabb.position = -cs->call("get_extents").operator Vector3();
aabb.size = aabb.position * -2;
for (int i = 0; i < 12; i++) {
Vector3 a, b;
aabb.get_edge(i, a, b);
lines.push_back(a);
lines.push_back(b);
}
Vector<Vector3> handles;
for (int i = 0; i < 3; i++) {
Vector3 ax;
ax[i] = cs->call("get_extents").operator Vector3()[i];
handles.push_back(ax);
}
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
p_gizmo->add_handles(handles, handles_material);
}
}
/////

View file

@ -669,4 +669,21 @@ public:
Joint3DGizmoPlugin();
};
class FogVolumeGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(FogVolumeGizmoPlugin, EditorNode3DGizmoPlugin);
public:
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
FogVolumeGizmoPlugin();
};
#endif // NODE_3D_EDITOR_GIZMOS_H

View file

@ -7004,6 +7004,7 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<NavigationRegion3DGizmoPlugin>(memnew(NavigationRegion3DGizmoPlugin)));
add_gizmo_plugin(Ref<Joint3DGizmoPlugin>(memnew(Joint3DGizmoPlugin)));
add_gizmo_plugin(Ref<PhysicalBone3DGizmoPlugin>(memnew(PhysicalBone3DGizmoPlugin)));
add_gizmo_plugin(Ref<FogVolumeGizmoPlugin>(memnew(FogVolumeGizmoPlugin)));
}
void Node3DEditor::_bind_methods() {

View file

@ -41,6 +41,7 @@
#include "scene/3d/world_environment.h"
#include "scene/gui/panel_container.h"
#include "scene/resources/environment.h"
#include "scene/resources/fog_material.h"
#include "scene/resources/sky_material.h"
class Node3DEditor;

View file

@ -178,6 +178,10 @@ void ShaderTextEditor::_check_shader_mode() {
mode = Shader::MODE_CANVAS_ITEM;
} else if (type == "particles") {
mode = Shader::MODE_PARTICLES;
} else if (type == "sky") {
mode = Shader::MODE_SKY;
} else if (type == "fog") {
mode = Shader::MODE_FOG;
} else {
mode = Shader::MODE_SPATIAL;
}

View file

@ -168,6 +168,11 @@ void ShaderCreateDialog::_create_new() {
code += "\t// Place sky code here.\n";
code += "}\n";
break;
case Shader::MODE_FOG:
code += "void fog() {\n";
code += "\t// Place fog code here.\n";
code += "}\n";
break;
}
}
text_shader->set_code(code.as_string());

119
scene/3d/fog_volume.cpp Normal file
View file

@ -0,0 +1,119 @@
/*************************************************************************/
/* fog_volume.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "fog_volume.h"
///////////////////////////
void FogVolume::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &FogVolume::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &FogVolume::get_extents);
ClassDB::bind_method(D_METHOD("set_shape", "shape"), &FogVolume::set_shape);
ClassDB::bind_method(D_METHOD("get_shape"), &FogVolume::get_shape);
ClassDB::bind_method(D_METHOD("set_material", "material"), &FogVolume::set_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::INT, "shape", PROPERTY_HINT_ENUM, "Ellipsoid,Box,World"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "FogMaterial,ShaderMaterial"), "set_material", "get_material");
}
void FogVolume::_validate_property(PropertyInfo &property) const {
if (property.name == "extents" && shape == RS::FOG_VOLUME_SHAPE_WORLD) {
property.usage = PROPERTY_USAGE_NONE;
return;
}
}
void FogVolume::set_extents(const Vector3 &p_extents) {
extents = p_extents;
extents.x = MAX(0.0, extents.x);
extents.y = MAX(0.0, extents.y);
extents.z = MAX(0.0, extents.z);
RS::get_singleton()->fog_volume_set_extents(_get_volume(), extents);
update_gizmos();
}
Vector3 FogVolume::get_extents() const {
return extents;
}
void FogVolume::set_shape(RS::FogVolumeShape p_type) {
shape = p_type;
RS::get_singleton()->fog_volume_set_shape(_get_volume(), shape);
RS::get_singleton()->instance_set_ignore_culling(get_instance(), shape == RS::FOG_VOLUME_SHAPE_WORLD);
update_gizmos();
notify_property_list_changed();
}
RS::FogVolumeShape FogVolume::get_shape() const {
return shape;
}
void FogVolume::set_material(const Ref<Material> &p_material) {
material = p_material;
RID material_rid;
if (material.is_valid()) {
material_rid = material->get_rid();
}
RS::get_singleton()->fog_volume_set_material(_get_volume(), material_rid);
update_gizmos();
}
Ref<Material> FogVolume::get_material() const {
return material;
}
AABB FogVolume::get_aabb() const {
if (shape != RS::FOG_VOLUME_SHAPE_WORLD) {
return AABB(-extents, extents * 2);
}
return AABB();
}
TypedArray<String> FogVolume::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!get_viewport()->find_world_3d()->get_environment()->is_volumetric_fog_enabled()) {
warnings.push_back(("Fog Volumes need volumetric fog to be enabled in the scene's Environment in order to be visible."));
}
return warnings;
}
FogVolume::FogVolume() {
volume = RS::get_singleton()->fog_volume_create();
RS::get_singleton()->fog_volume_set_shape(volume, RS::FOG_VOLUME_SHAPE_BOX);
set_base(volume);
}
FogVolume::~FogVolume() {
RS::get_singleton()->free(volume);
}

72
scene/3d/fog_volume.h Normal file
View file

@ -0,0 +1,72 @@
/*************************************************************************/
/* fog_volume.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef FOG_VOLUME_H
#define FOG_VOLUME_H
#include "core/templates/rid.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/main/node.h"
#include "scene/main/viewport.h"
#include "scene/resources/material.h"
class FogVolume : public VisualInstance3D {
GDCLASS(FogVolume, VisualInstance3D);
Vector3 extents = Vector3(1, 1, 1);
Ref<Material> material;
RS::FogVolumeShape shape = RS::FOG_VOLUME_SHAPE_BOX;
RID volume;
protected:
_FORCE_INLINE_ RID _get_volume() { return volume; }
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const override;
public:
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
void set_shape(RS::FogVolumeShape p_type);
RS::FogVolumeShape get_shape() const;
void set_material(const Ref<Material> &p_material);
Ref<Material> get_material() const;
virtual AABB get_aabb() const override;
virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); }
TypedArray<String> get_configuration_warnings() const override;
FogVolume();
~FogVolume();
};
#endif // FOG_VOLUME_H

View file

@ -213,6 +213,7 @@
#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/cpu_particles_3d.h"
#include "scene/3d/decal.h"
#include "scene/3d/fog_volume.h"
#include "scene/3d/gpu_particles_3d.h"
#include "scene/3d/gpu_particles_collision_3d.h"
#include "scene/3d/importer_mesh_instance_3d.h"
@ -245,6 +246,7 @@
#include "scene/3d/world_environment.h"
#include "scene/3d/xr_nodes.h"
#include "scene/resources/environment.h"
#include "scene/resources/fog_material.h"
#include "scene/resources/importer_mesh.h"
#include "scene/resources/mesh_library.h"
#endif
@ -520,6 +522,8 @@ void register_scene_types() {
GDREGISTER_CLASS(VisibleOnScreenNotifier3D);
GDREGISTER_CLASS(VisibleOnScreenEnabler3D);
GDREGISTER_CLASS(WorldEnvironment);
GDREGISTER_CLASS(FogVolume);
GDREGISTER_CLASS(FogMaterial);
GDREGISTER_CLASS(RemoteTransform3D);
GDREGISTER_VIRTUAL_CLASS(Joint3D);

View file

@ -782,7 +782,7 @@ void Environment::_update_fog() {
// Volumetric Fog
void Environment::_update_volumetric_fog() {
RS::get_singleton()->environment_set_volumetric_fog(environment, volumetric_fog_enabled, volumetric_fog_density, volumetric_fog_light, volumetric_fog_light_energy, volumetric_fog_length, volumetric_fog_detail_spread, volumetric_fog_gi_inject, volumetric_fog_temporal_reproject, volumetric_fog_temporal_reproject_amount);
RS::get_singleton()->environment_set_volumetric_fog(environment, volumetric_fog_enabled, volumetric_fog_density, volumetric_fog_albedo, volumetric_fog_emission, volumetric_fog_emission_energy, volumetric_fog_anisotropy, volumetric_fog_length, volumetric_fog_detail_spread, volumetric_fog_gi_inject, volumetric_fog_temporal_reproject, volumetric_fog_temporal_reproject_amount, volumetric_fog_ambient_inject);
}
void Environment::set_volumetric_fog_enabled(bool p_enable) {
@ -795,26 +795,39 @@ bool Environment::is_volumetric_fog_enabled() const {
return volumetric_fog_enabled;
}
void Environment::set_volumetric_fog_density(float p_density) {
p_density = CLAMP(p_density, 0.0000001, 1.0);
volumetric_fog_density = p_density;
_update_volumetric_fog();
}
float Environment::get_volumetric_fog_density() const {
return volumetric_fog_density;
}
void Environment::set_volumetric_fog_light(Color p_color) {
volumetric_fog_light = p_color;
void Environment::set_volumetric_fog_albedo(Color p_color) {
volumetric_fog_albedo = p_color;
_update_volumetric_fog();
}
Color Environment::get_volumetric_fog_light() const {
return volumetric_fog_light;
Color Environment::get_volumetric_fog_albedo() const {
return volumetric_fog_albedo;
}
void Environment::set_volumetric_fog_light_energy(float p_begin) {
volumetric_fog_light_energy = p_begin;
void Environment::set_volumetric_fog_emission(Color p_color) {
volumetric_fog_emission = p_color;
_update_volumetric_fog();
}
float Environment::get_volumetric_fog_light_energy() const {
return volumetric_fog_light_energy;
Color Environment::get_volumetric_fog_emission() const {
return volumetric_fog_emission;
}
void Environment::set_volumetric_fog_emission_energy(float p_begin) {
volumetric_fog_emission_energy = p_begin;
_update_volumetric_fog();
}
float Environment::get_volumetric_fog_emission_energy() const {
return volumetric_fog_emission_energy;
}
void Environment::set_volumetric_fog_anisotropy(float p_anisotropy) {
volumetric_fog_anisotropy = p_anisotropy;
_update_volumetric_fog();
}
float Environment::get_volumetric_fog_anisotropy() const {
return volumetric_fog_anisotropy;
}
void Environment::set_volumetric_fog_length(float p_length) {
volumetric_fog_length = p_length;
@ -824,6 +837,7 @@ float Environment::get_volumetric_fog_length() const {
return volumetric_fog_length;
}
void Environment::set_volumetric_fog_detail_spread(float p_detail_spread) {
p_detail_spread = CLAMP(p_detail_spread, 0.5, 6.0);
volumetric_fog_detail_spread = p_detail_spread;
_update_volumetric_fog();
}
@ -838,6 +852,13 @@ void Environment::set_volumetric_fog_gi_inject(float p_gi_inject) {
float Environment::get_volumetric_fog_gi_inject() const {
return volumetric_fog_gi_inject;
}
void Environment::set_volumetric_fog_ambient_inject(float p_ambient_inject) {
volumetric_fog_ambient_inject = p_ambient_inject;
_update_volumetric_fog();
}
float Environment::get_volumetric_fog_ambient_inject() const {
return volumetric_fog_ambient_inject;
}
void Environment::set_volumetric_fog_temporal_reprojection_enabled(bool p_enable) {
volumetric_fog_temporal_reproject = p_enable;
@ -1295,18 +1316,24 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled);
ClassDB::bind_method(D_METHOD("is_volumetric_fog_enabled"), &Environment::is_volumetric_fog_enabled);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_light", "color"), &Environment::set_volumetric_fog_light);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_light"), &Environment::get_volumetric_fog_light);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_emission", "color"), &Environment::set_volumetric_fog_emission);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_emission"), &Environment::get_volumetric_fog_emission);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_albedo", "color"), &Environment::set_volumetric_fog_albedo);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_albedo"), &Environment::get_volumetric_fog_albedo);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_density", "density"), &Environment::set_volumetric_fog_density);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_density"), &Environment::get_volumetric_fog_density);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_light_energy", "begin"), &Environment::set_volumetric_fog_light_energy);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_light_energy"), &Environment::get_volumetric_fog_light_energy);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_emission_energy", "begin"), &Environment::set_volumetric_fog_emission_energy);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_emission_energy"), &Environment::get_volumetric_fog_emission_energy);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_anisotropy", "anisotropy"), &Environment::set_volumetric_fog_anisotropy);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_anisotropy"), &Environment::get_volumetric_fog_anisotropy);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_length", "length"), &Environment::set_volumetric_fog_length);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_length"), &Environment::get_volumetric_fog_length);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_detail_spread", "detail_spread"), &Environment::set_volumetric_fog_detail_spread);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_detail_spread"), &Environment::get_volumetric_fog_detail_spread);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_gi_inject", "gi_inject"), &Environment::set_volumetric_fog_gi_inject);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_gi_inject"), &Environment::get_volumetric_fog_gi_inject);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_ambient_inject", "enabled"), &Environment::set_volumetric_fog_ambient_inject);
ClassDB::bind_method(D_METHOD("get_volumetric_fog_ambient_inject"), &Environment::get_volumetric_fog_ambient_inject);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_enabled", "enabled"), &Environment::set_volumetric_fog_temporal_reprojection_enabled);
ClassDB::bind_method(D_METHOD("is_volumetric_fog_temporal_reprojection_enabled"), &Environment::is_volumetric_fog_temporal_reprojection_enabled);
ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_amount", "temporal_reprojection_amount"), &Environment::set_volumetric_fog_temporal_reprojection_amount);
@ -1315,11 +1342,14 @@ void Environment::_bind_methods() {
ADD_GROUP("Volumetric Fog", "volumetric_fog_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_enabled"), "set_volumetric_fog_enabled", "is_volumetric_fog_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_volumetric_fog_density", "get_volumetric_fog_density");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "volumetric_fog_light", PROPERTY_HINT_COLOR_NO_ALPHA), "set_volumetric_fog_light", "get_volumetric_fog_light");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_light_energy", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_light_energy", "get_volumetric_fog_light_energy");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_RANGE, "0.00,16,0.01,exp"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "volumetric_fog_albedo", PROPERTY_HINT_COLOR_NO_ALPHA), "set_volumetric_fog_albedo", "get_volumetric_fog_albedo");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "volumetric_fog_emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_volumetric_fog_emission", "get_volumetric_fog_emission");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_emission_energy", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_emission_energy", "get_volumetric_fog_emission_energy");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_anisotropy", PROPERTY_HINT_RANGE, "-0.9,0.9,0.01"), "set_volumetric_fog_anisotropy", "get_volumetric_fog_anisotropy");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_length", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_length", "get_volumetric_fog_length");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING, "0.01,16,0.01"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_ambient_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_ambient_inject", "get_volumetric_fog_ambient_inject");
ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_temporal_reprojection_enabled"), "set_volumetric_fog_temporal_reprojection_enabled", "is_volumetric_fog_temporal_reprojection_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.0,0.999,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount");
@ -1381,11 +1411,6 @@ void Environment::_bind_methods() {
BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_DISABLED);
BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_75_PERCENT);
BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_50_PERCENT);
BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED);
BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_LOW);
BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM);
BIND_ENUM_CONSTANT(VOLUMETRIC_FOG_SHADOW_FILTER_HIGH);
}
Environment::Environment() {

View file

@ -90,13 +90,6 @@ public:
GLOW_BLEND_MODE_MIX,
};
enum VolumetricFogShadowFilter {
VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED,
VOLUMETRIC_FOG_SHADOW_FILTER_LOW,
VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM,
VOLUMETRIC_FOG_SHADOW_FILTER_HIGH,
};
private:
RID environment;
@ -190,12 +183,15 @@ private:
// Volumetric Fog
bool volumetric_fog_enabled = false;
float volumetric_fog_density = 0.01;
Color volumetric_fog_light = Color(0.0, 0.0, 0.0);
float volumetric_fog_light_energy = 1.0;
float volumetric_fog_density = 0.05;
Color volumetric_fog_albedo = Color(1.0, 1.0, 1.0);
Color volumetric_fog_emission = Color(0.0, 0.0, 0.0);
float volumetric_fog_emission_energy = 1.0;
float volumetric_fog_anisotropy = 0.2;
float volumetric_fog_length = 64.0;
float volumetric_fog_detail_spread = 2.0;
float volumetric_fog_gi_inject = 0.0;
float volumetric_fog_ambient_inject = false;
bool volumetric_fog_temporal_reproject = true;
float volumetric_fog_temporal_reproject_amount = 0.9;
void _update_volumetric_fog();
@ -375,16 +371,22 @@ public:
bool is_volumetric_fog_enabled() const;
void set_volumetric_fog_density(float p_density);
float get_volumetric_fog_density() const;
void set_volumetric_fog_light(Color p_color);
Color get_volumetric_fog_light() const;
void set_volumetric_fog_light_energy(float p_begin);
float get_volumetric_fog_light_energy() const;
void set_volumetric_fog_albedo(Color p_color);
Color get_volumetric_fog_albedo() const;
void set_volumetric_fog_emission(Color p_color);
Color get_volumetric_fog_emission() const;
void set_volumetric_fog_emission_energy(float p_begin);
float get_volumetric_fog_emission_energy() const;
void set_volumetric_fog_anisotropy(float p_anisotropy);
float get_volumetric_fog_anisotropy() const;
void set_volumetric_fog_length(float p_length);
float get_volumetric_fog_length() const;
void set_volumetric_fog_detail_spread(float p_detail_spread);
float get_volumetric_fog_detail_spread() const;
void set_volumetric_fog_gi_inject(float p_gi_inject);
float get_volumetric_fog_gi_inject() const;
void set_volumetric_fog_ambient_inject(float p_ambient_inject);
float get_volumetric_fog_ambient_inject() const;
void set_volumetric_fog_temporal_reprojection_enabled(bool p_enable);
bool is_volumetric_fog_temporal_reprojection_enabled() const;
void set_volumetric_fog_temporal_reprojection_amount(float p_amount);
@ -413,6 +415,5 @@ VARIANT_ENUM_CAST(Environment::ToneMapper)
VARIANT_ENUM_CAST(Environment::SDFGICascades)
VARIANT_ENUM_CAST(Environment::SDFGIYScale)
VARIANT_ENUM_CAST(Environment::GlowBlendMode)
VARIANT_ENUM_CAST(Environment::VolumetricFogShadowFilter)
#endif // ENVIRONMENT_H

View file

@ -0,0 +1,181 @@
/*************************************************************************/
/* fog_material.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "fog_material.h"
#include "core/version.h"
Mutex FogMaterial::shader_mutex;
RID FogMaterial::shader;
void FogMaterial::set_density(float p_density) {
density = p_density;
RS::get_singleton()->material_set_param(_get_material(), "density", density);
}
float FogMaterial::get_density() const {
return density;
}
void FogMaterial::set_albedo(Color p_albedo) {
albedo = p_albedo;
RS::get_singleton()->material_set_param(_get_material(), "albedo", albedo);
}
Color FogMaterial::get_albedo() const {
return albedo;
}
void FogMaterial::set_emission(Color p_emission) {
emission = p_emission;
RS::get_singleton()->material_set_param(_get_material(), "emission", emission);
}
Color FogMaterial::get_emission() const {
return emission;
}
void FogMaterial::set_height_falloff(float p_falloff) {
height_falloff = MAX(p_falloff, 0.0f);
RS::get_singleton()->material_set_param(_get_material(), "height_falloff", height_falloff);
}
float FogMaterial::get_height_falloff() const {
return height_falloff;
}
void FogMaterial::set_edge_fade(float p_edge_fade) {
edge_fade = MAX(p_edge_fade, 0.0f);
RS::get_singleton()->material_set_param(_get_material(), "edge_fade", edge_fade);
}
float FogMaterial::get_edge_fade() const {
return edge_fade;
}
void FogMaterial::set_density_texture(const Ref<Texture3D> &p_texture) {
density_texture = p_texture;
RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RS::get_singleton()->material_set_param(_get_material(), "density_texture", tex_rid);
}
Ref<Texture3D> FogMaterial::get_density_texture() const {
return density_texture;
}
Shader::Mode FogMaterial::get_shader_mode() const {
return Shader::MODE_FOG;
}
RID FogMaterial::get_shader_rid() const {
_update_shader();
return shader;
}
RID FogMaterial::get_rid() const {
_update_shader();
if (!shader_set) {
RS::get_singleton()->material_set_shader(_get_material(), shader);
shader_set = true;
}
return _get_material();
}
void FogMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_density", "density"), &FogMaterial::set_density);
ClassDB::bind_method(D_METHOD("get_density"), &FogMaterial::get_density);
ClassDB::bind_method(D_METHOD("set_albedo", "albedo"), &FogMaterial::set_albedo);
ClassDB::bind_method(D_METHOD("get_albedo"), &FogMaterial::get_albedo);
ClassDB::bind_method(D_METHOD("set_emission", "emission"), &FogMaterial::set_emission);
ClassDB::bind_method(D_METHOD("get_emission"), &FogMaterial::get_emission);
ClassDB::bind_method(D_METHOD("set_height_falloff", "height_falloff"), &FogMaterial::set_height_falloff);
ClassDB::bind_method(D_METHOD("get_height_falloff"), &FogMaterial::get_height_falloff);
ClassDB::bind_method(D_METHOD("set_edge_fade", "edge_fade"), &FogMaterial::set_edge_fade);
ClassDB::bind_method(D_METHOD("get_edge_fade"), &FogMaterial::get_edge_fade);
ClassDB::bind_method(D_METHOD("set_density_texture", "density_texture"), &FogMaterial::set_density_texture);
ClassDB::bind_method(D_METHOD("get_density_texture"), &FogMaterial::get_density_texture);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, "0.0,16.0,0.0001,or_greater,or_lesser"), "set_density", "get_density");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "albedo", PROPERTY_HINT_COLOR_NO_ALPHA), "set_albedo", "get_albedo");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height_falloff", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_height_falloff", "get_height_falloff");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_fade", PROPERTY_HINT_EXP_EASING), "set_edge_fade", "get_edge_fade");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "density_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_density_texture", "get_density_texture");
}
void FogMaterial::cleanup_shader() {
if (shader.is_valid()) {
RS::get_singleton()->free(shader);
}
}
void FogMaterial::_update_shader() {
shader_mutex.lock();
if (shader.is_null()) {
shader = RS::get_singleton()->shader_create();
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
RS::get_singleton()->shader_set_code(shader, R"(
// NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s FogMaterial.
shader_type fog;
uniform float density : hint_range(0, 1, 0.0001) = 1.0;
uniform vec4 albedo : hint_color = vec4(1.0);
uniform vec4 emission : hint_color = vec4(0, 0, 0, 1);
uniform float height_falloff = 0.0;
uniform float edge_fade = 0.1;
uniform sampler3D density_texture: hint_white;
void fog() {
DENSITY = density * clamp(exp2(-height_falloff * (WORLD_POSITION.y - OBJECT_POSITION.y)), 0.0, 1.0);
DENSITY *= texture(density_texture, UVW).r;
DENSITY *= pow(clamp(-SDF / min(min(EXTENTS.x, EXTENTS.y), EXTENTS.z), 0.0, 1.0), edge_fade);
ALBEDO = albedo.rgb;
EMISSION = emission.rgb;
}
)");
}
shader_mutex.unlock();
}
FogMaterial::FogMaterial() {
set_density(1.0);
set_albedo(Color(1, 1, 1, 1));
set_emission(Color(0, 0, 0, 1));
set_height_falloff(0.0);
set_edge_fade(0.1);
}
FogMaterial::~FogMaterial() {
RS::get_singleton()->material_set_shader(_get_material(), RID());
}

View file

@ -0,0 +1,87 @@
/*************************************************************************/
/* fog_material.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef FOG_MATERIAL_H
#define FOG_MATERIAL_H
#include "scene/resources/material.h"
class FogMaterial : public Material {
GDCLASS(FogMaterial, Material);
private:
float density = 1.0;
Color albedo = Color(1, 1, 1, 1);
Color emission = Color(0, 0, 0, 0);
float height_falloff = 0.0;
float edge_fade = 0.1;
Ref<Texture3D> density_texture;
static Mutex shader_mutex;
static RID shader;
static void _update_shader();
mutable bool shader_set = false;
protected:
static void _bind_methods();
public:
void set_density(float p_density);
float get_density() const;
void set_albedo(Color p_color);
Color get_albedo() const;
void set_emission(Color p_color);
Color get_emission() const;
void set_height_falloff(float p_falloff);
float get_height_falloff() const;
void set_edge_fade(float p_edge_fade);
float get_edge_fade() const;
void set_density_texture(const Ref<Texture3D> &p_texture);
Ref<Texture3D> get_density_texture() const;
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_shader_rid() const override;
virtual RID get_rid() const override;
static void cleanup_shader();
FogMaterial();
virtual ~FogMaterial();
};
#endif // FOG_MATERIAL_H

View file

@ -49,6 +49,8 @@ void Shader::set_code(const String &p_code) {
mode = MODE_PARTICLES;
} else if (type == "sky") {
mode = MODE_SKY;
} else if (type == "fog") {
mode = MODE_FOG;
} else {
mode = MODE_SPATIAL;
}
@ -149,6 +151,7 @@ void Shader::_bind_methods() {
BIND_ENUM_CONSTANT(MODE_CANVAS_ITEM);
BIND_ENUM_CONSTANT(MODE_PARTICLES);
BIND_ENUM_CONSTANT(MODE_SKY);
BIND_ENUM_CONSTANT(MODE_FOG);
}
Shader::Shader() {

View file

@ -46,6 +46,7 @@ public:
MODE_CANVAS_ITEM,
MODE_PARTICLES,
MODE_SKY,
MODE_FOG,
MODE_MAX
};

View file

@ -1096,6 +1096,7 @@ static const char *type_string[VisualShader::TYPE_MAX] = {
"start_custom",
"process_custom",
"sky",
"fog",
};
bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
@ -1245,7 +1246,7 @@ void VisualShader::reset_state() {
}
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
//mode
p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky"));
p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky,Fog"));
//render modes
Map<String, String> blend_mode_enums;
@ -1636,7 +1637,7 @@ void VisualShader::_update_shader() const {
Vector<VisualShader::DefaultTextureParam> default_tex_params;
Set<StringName> classes;
Map<int, int> insertion_pos;
static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles", "sky" };
static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles", "sky", "fog" };
global_code += String() + "shader_type " + shader_mode_str[shader_mode] + ";\n";
@ -1684,7 +1685,7 @@ void VisualShader::_update_shader() const {
global_code += "render_mode " + render_mode + ";\n\n";
}
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky" };
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" };
String global_expressions;
Set<String> used_uniform_names;
@ -1755,7 +1756,7 @@ void VisualShader::_update_shader() const {
StringBuilder func_code;
bool is_empty_func = false;
if (shader_mode != Shader::MODE_PARTICLES && shader_mode != Shader::MODE_SKY) {
if (shader_mode != Shader::MODE_PARTICLES && shader_mode != Shader::MODE_SKY && shader_mode != Shader::MODE_FOG) {
is_empty_func = true;
}
@ -2030,6 +2031,7 @@ void VisualShader::_bind_methods() {
BIND_ENUM_CONSTANT(TYPE_START_CUSTOM);
BIND_ENUM_CONSTANT(TYPE_PROCESS_CUSTOM);
BIND_ENUM_CONSTANT(TYPE_SKY);
BIND_ENUM_CONSTANT(TYPE_FOG);
BIND_ENUM_CONSTANT(TYPE_MAX);
BIND_CONSTANT(NODE_ID_INVALID);
@ -2307,6 +2309,16 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "sky_coords", "vec3(SKY_COORDS, 0.0)" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
// Fog, Fog
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "world_position", "WORLD_POSITION" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "object_position", "OBJECT_POSITION" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "uvw", "UVW" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "extents", "EXTENTS" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "sdf", "SDF" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
@ -2932,6 +2944,13 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "fog", "FOG.rgb" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "fog_alpha", "FOG.a" },
////////////////////////////////////////////////////////////////////////
// Fog, Fog.
////////////////////////////////////////////////////////////////////////
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "density", "DENSITY" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "emission", "EMISSION" },
////////////////////////////////////////////////////////////////////////
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};

View file

@ -57,6 +57,7 @@ public:
TYPE_START_CUSTOM,
TYPE_PROCESS_CUSTOM,
TYPE_SKY,
TYPE_FOG,
TYPE_MAX
};

View file

@ -128,7 +128,7 @@ public:
void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) override {}
void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) override {}
void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) override {}
void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) override {}
void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override {}
void environment_set_volumetric_fog_filter_active(bool p_enable) override {}
@ -155,6 +155,12 @@ public:
void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {}
void light_instance_mark_visible(RID p_light_instance) override {}
RID fog_volume_instance_create(RID p_fog_volume) override { return RID(); }
void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override {}
void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override {}
RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override { return RID(); }
Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override { return Vector3(); }
RID reflection_atlas_create() override { return RID(); }
int reflection_atlas_get_size(RID p_ref_atlas) const override { return 0; }
void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {}
@ -180,7 +186,7 @@ public:
void voxel_gi_set_quality(RS::VoxelGIQuality) override {}
void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override {}
void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override {}
void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {}
void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {}
@ -610,6 +616,17 @@ public:
void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override {}
void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override {}
/* FOG VOLUMES */
RID fog_volume_allocate() override { return RID(); }
void fog_volume_initialize(RID p_rid) override {}
void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override {}
void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override {}
void fog_volume_set_material(RID p_fog_volume, RID p_material) override {}
AABB fog_volume_get_aabb(RID p_fog_volume) const override { return AABB(); }
RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const override { return RS::FOG_VOLUME_SHAPE_BOX; }
/* VISIBILITY NOTIFIER */
virtual RID visibility_notifier_allocate() override { return RID(); }
virtual void visibility_notifier_initialize(RID p_notifier) override {}

View file

@ -92,16 +92,19 @@ void RendererSceneEnvironmentRD::set_fog(bool p_enable, const Color &p_light_col
fog_aerial_perspective = p_fog_aerial_perspective;
}
void RendererSceneEnvironmentRD::set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) {
void RendererSceneEnvironmentRD::set_volumetric_fog(bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) {
volumetric_fog_enabled = p_enable;
volumetric_fog_density = p_density;
volumetric_fog_light = p_light;
volumetric_fog_light_energy = p_light_energy;
volumetric_fog_scattering = p_albedo;
volumetric_fog_emission = p_emission;
volumetric_fog_emission_energy = p_emission_energy;
volumetric_fog_anisotropy = p_anisotropy,
volumetric_fog_length = p_length;
volumetric_fog_detail_spread = p_detail_spread;
volumetric_fog_gi_inject = p_gi_inject;
volumetric_fog_temporal_reprojection = p_temporal_reprojection;
volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount;
volumetric_fog_ambient_inject = p_ambient_inject;
}
void RendererSceneEnvironmentRD::set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) {

View file

@ -79,13 +79,16 @@ public:
///
bool volumetric_fog_enabled = false;
float volumetric_fog_density = 0.01;
Color volumetric_fog_light = Color(0, 0, 0);
float volumetric_fog_light_energy = 0.0;
Color volumetric_fog_scattering = Color(1, 1, 1);
Color volumetric_fog_emission = Color(0, 0, 0);
float volumetric_fog_emission_energy = 0.0;
float volumetric_fog_anisotropy = 0.2;
float volumetric_fog_length = 64.0;
float volumetric_fog_detail_spread = 2.0;
float volumetric_fog_gi_inject = 0.0;
bool volumetric_fog_temporal_reprojection = true;
float volumetric_fog_temporal_reprojection_amount = 0.9;
float volumetric_fog_ambient_inject = 0.0;
/// Glow
@ -146,7 +149,7 @@ public:
void set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap);
void set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias);
void set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective);
void set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount);
void set_volumetric_fog(bool p_enable, float p_density, const Color &p_scatterin, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject);
void set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance);
void set_ssao(bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect);
};

View file

@ -3098,12 +3098,14 @@ void RendererSceneGIRD::setup_voxel_gi_instances(RID p_render_buffers, const Tra
}
rb->gi.uniform_set = RID();
if (rb->volumetric_fog) {
if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) {
RD::get_singleton()->free(rb->volumetric_fog->fog_uniform_set);
RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set);
RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set2);
}
rb->volumetric_fog->uniform_set = RID();
rb->volumetric_fog->uniform_set2 = RID();
rb->volumetric_fog->fog_uniform_set = RID();
rb->volumetric_fog->process_uniform_set = RID();
rb->volumetric_fog->process_uniform_set2 = RID();
}
}

View file

@ -365,7 +365,7 @@ float RendererSceneRenderRD::environment_get_fog_aerial_perspective(RID p_env) c
return env->fog_aerial_perspective;
}
void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) {
void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) {
RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env);
ERR_FAIL_COND(!env);
@ -373,7 +373,7 @@ void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_ena
return;
}
env->set_volumetric_fog(p_enable, p_density, p_light, p_light_energy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount);
env->set_volumetric_fog(p_enable, p_density, p_albedo, p_emission, p_emission_energy, p_anisotropy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount, p_ambient_inject);
}
void RendererSceneRenderRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) {
@ -499,6 +499,37 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba
////////////////////////////////////////////////////////////
RID RendererSceneRenderRD::fog_volume_instance_create(RID p_fog_volume) {
FogVolumeInstance fvi;
fvi.volume = p_fog_volume;
return fog_volume_instance_owner.make_rid(fvi);
}
void RendererSceneRenderRD::fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) {
FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
ERR_FAIL_COND(!fvi);
fvi->transform = p_transform;
}
void RendererSceneRenderRD::fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) {
FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
ERR_FAIL_COND(!fvi);
fvi->active = p_active;
}
RID RendererSceneRenderRD::fog_volume_instance_get_volume(RID p_fog_volume_instance) const {
FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
ERR_FAIL_COND_V(!fvi, RID());
return fvi->volume;
}
Vector3 RendererSceneRenderRD::fog_volume_instance_get_position(RID p_fog_volume_instance) const {
FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
ERR_FAIL_COND_V(!fvi, Vector3());
return fvi->transform.get_origin();
}
////////////////////////////////////////////////////////////
RID RendererSceneRenderRD::reflection_atlas_create() {
ReflectionAtlas ra;
ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count");
@ -3472,6 +3503,180 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
}
}
////////////////////////////////////////////////////////////////////////////////
// FOG SHADER
void RendererSceneRenderRD::FogShaderData::set_code(const String &p_code) {
//compile
code = p_code;
valid = false;
ubo_size = 0;
uniforms.clear();
if (code == String()) {
return; //just invalid, but no error
}
ShaderCompilerRD::GeneratedCode gen_code;
ShaderCompilerRD::IdentifierActions actions;
actions.entry_point_stages["fog"] = ShaderCompilerRD::STAGE_COMPUTE;
uses_time = false;
actions.usage_flag_pointers["TIME"] = &uses_time;
actions.uniforms = &uniforms;
RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
Error err = scene_singleton->volumetric_fog.compiler.compile(RS::SHADER_FOG, code, &actions, path, gen_code);
ERR_FAIL_COND_MSG(err != OK, "Fog shader compilation failed.");
if (version.is_null()) {
version = scene_singleton->volumetric_fog.shader.version_create();
}
scene_singleton->volumetric_fog.shader.version_set_compute_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_COMPUTE], gen_code.defines);
ERR_FAIL_COND(!scene_singleton->volumetric_fog.shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
pipeline = RD::get_singleton()->compute_pipeline_create(scene_singleton->volumetric_fog.shader.version_get_shader(version, 0));
valid = true;
}
void RendererSceneRenderRD::FogShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
if (!p_texture.is_valid()) {
default_texture_params.erase(p_name);
} else {
default_texture_params[p_name] = p_texture;
}
}
void RendererSceneRenderRD::FogShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
Map<int, StringName> order;
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
if (E->get().texture_order >= 0) {
order[E->get().texture_order + 100000] = E->key();
} else {
order[E->get().order] = E->key();
}
}
for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
pi.name = E->get();
p_param_list->push_back(pi);
}
}
void RendererSceneRenderRD::FogShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
continue;
}
RendererStorage::InstanceShaderParam p;
p.info = ShaderLanguage::uniform_to_property_info(E->get());
p.info.name = E->key(); //supply name
p.index = E->get().instance_index;
p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
p_param_list->push_back(p);
}
}
bool RendererSceneRenderRD::FogShaderData::is_param_texture(const StringName &p_param) const {
if (!uniforms.has(p_param)) {
return false;
}
return uniforms[p_param].texture_order >= 0;
}
bool RendererSceneRenderRD::FogShaderData::is_animated() const {
return false;
}
bool RendererSceneRenderRD::FogShaderData::casts_shadows() const {
return false;
}
Variant RendererSceneRenderRD::FogShaderData::get_default_parameter(const StringName &p_parameter) const {
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
}
return Variant();
}
RS::ShaderNativeSourceCode RendererSceneRenderRD::FogShaderData::get_native_source_code() const {
RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
return scene_singleton->volumetric_fog.shader.version_get_native_source_code(version);
}
RendererSceneRenderRD::FogShaderData::FogShaderData() {
valid = false;
}
RendererSceneRenderRD::FogShaderData::~FogShaderData() {
RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
ERR_FAIL_COND(!scene_singleton);
//pipeline variants will clear themselves if shader is gone
if (version.is_valid()) {
scene_singleton->volumetric_fog.shader.version_free(version);
}
}
////////////////////////////////////////////////////////////////////////////////
// Fog material
bool RendererSceneRenderRD::FogMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
uniform_set_updated = true;
return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL);
}
RendererSceneRenderRD::FogMaterialData::~FogMaterialData() {
free_parameters_uniform_set(uniform_set);
}
RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_fog_shader_func() {
FogShaderData *shader_data = memnew(FogShaderData);
return shader_data;
}
RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_fog_shader_funcs() {
return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->_create_fog_shader_func();
};
RendererStorageRD::MaterialData *RendererSceneRenderRD::_create_fog_material_func(FogShaderData *p_shader) {
FogMaterialData *material_data = memnew(FogMaterialData);
material_data->shader_data = p_shader;
material_data->last_frame = false;
//update will happen later anyway so do nothing.
return material_data;
}
RendererStorageRD::MaterialData *RendererSceneRenderRD::_create_fog_material_funcs(RendererStorageRD::ShaderData *p_shader) {
return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->_create_fog_material_func(static_cast<FogShaderData *>(p_shader));
};
////////////////////////////////////////////////////////////////////////////////
// Volumetric Fog
void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
ERR_FAIL_COND(!rb->volumetric_fog);
@ -3479,11 +3684,14 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
RD::get_singleton()->free(rb->volumetric_fog->light_density_map);
RD::get_singleton()->free(rb->volumetric_fog->fog_map);
if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
if (rb->volumetric_fog->fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) {
RD::get_singleton()->free(rb->volumetric_fog->fog_uniform_set);
}
if (rb->volumetric_fog->uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set2)) {
RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
if (rb->volumetric_fog->process_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set)) {
RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set);
}
if (rb->volumetric_fog->process_uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set2)) {
RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set2);
}
if (rb->volumetric_fog->sdfgi_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sdfgi_uniform_set)) {
RD::get_singleton()->free(rb->volumetric_fog->sdfgi_uniform_set);
@ -3497,7 +3705,26 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
rb->volumetric_fog = nullptr;
}
void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count) {
Vector3i RendererSceneRenderRD::_point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform) {
Vector3 view_position = p_cam_transform.affine_inverse().xform(p_point);
view_position.z = MIN(view_position.z, -0.01); // Clamp to the front of camera
Vector3 fog_position = Vector3(0, 0, 0);
view_position.y = -view_position.y;
fog_position.z = -view_position.z / fog_end;
fog_position.x = (view_position.x / (2 * (fog_near_size.x * (1.0 - fog_position.z) + fog_far_size.x * fog_position.z))) + 0.5;
fog_position.y = (view_position.y / (2 * (fog_near_size.y * (1.0 - fog_position.z) + fog_far_size.y * fog_position.z))) + 0.5;
fog_position.z = Math::pow(float(fog_position.z), float(1.0 / volumetric_fog_detail_spread));
fog_position = fog_position * fog_size - Vector3(0.5, 0.5, 0.5);
fog_position.x = CLAMP(fog_position.x, 0.0, fog_size.x);
fog_position.y = CLAMP(fog_position.y, 0.0, fog_size.y);
fog_position.z = CLAMP(fog_position.z, 0.0, fog_size.z);
return Vector3i(fog_position);
}
void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes) {
ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered
RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb);
@ -3520,6 +3747,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
}
RENDER_TIMESTAMP(">Volumetric Fog");
RD::get_singleton()->draw_command_begin_label("Volumetric Fog");
if (env && env->volumetric_fog_enabled && !rb->volumetric_fog) {
//required volumetric fog but not existing, create
@ -3537,15 +3765,30 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
rb->volumetric_fog->light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_density_map, "Fog light-density map");
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
rb->volumetric_fog->prev_light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->volumetric_fog->prev_light_density_map, "Fog previous light-density map");
RD::get_singleton()->texture_clear(rb->volumetric_fog->prev_light_density_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->volumetric_fog->fog_map, "Fog map");
tf.format = RD::DATA_FORMAT_R32_UINT;
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
rb->volumetric_fog->density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->volumetric_fog->density_map, "Fog density map");
RD::get_singleton()->texture_clear(rb->volumetric_fog->density_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
rb->volumetric_fog->light_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_map, "Fog light map");
RD::get_singleton()->texture_clear(rb->volumetric_fog->light_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
rb->volumetric_fog->emissive_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->volumetric_fog->emissive_map, "Fog emissive map");
RD::get_singleton()->texture_clear(rb->volumetric_fog->emissive_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
Vector<RD::Uniform> uniforms;
{
@ -3559,12 +3802,194 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky.sky_shader.default_shader_rd, RendererSceneSkyRD::SKY_SET_FOG);
}
//update volumetric fog
if (p_fog_volumes.size() > 0) {
RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog Volumes");
if (rb->volumetric_fog->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
RENDER_TIMESTAMP("Render Fog Volumes");
VolumetricFogShader::VolumeUBO params;
Vector2 frustum_near_size = p_cam_projection.get_viewport_half_extents();
Vector2 frustum_far_size = p_cam_projection.get_far_plane_half_extents();
float z_near = p_cam_projection.get_z_near();
float z_far = p_cam_projection.get_z_far();
float fog_end = env->volumetric_fog_length;
Vector2 fog_far_size = frustum_near_size.lerp(frustum_far_size, (fog_end - z_near) / (z_far - z_near));
Vector2 fog_near_size;
if (p_cam_projection.is_orthogonal()) {
fog_near_size = fog_far_size;
} else {
fog_near_size = Vector2();
}
params.fog_frustum_size_begin[0] = fog_near_size.x;
params.fog_frustum_size_begin[1] = fog_near_size.y;
params.fog_frustum_size_end[0] = fog_far_size.x;
params.fog_frustum_size_end[1] = fog_far_size.y;
params.fog_frustum_end = fog_end;
params.z_near = z_near;
params.z_far = z_far;
params.time = time;
params.fog_volume_size[0] = rb->volumetric_fog->width;
params.fog_volume_size[1] = rb->volumetric_fog->height;
params.fog_volume_size[2] = rb->volumetric_fog->depth;
params.use_temporal_reprojection = env->volumetric_fog_temporal_reprojection;
params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES;
params.detail_spread = env->volumetric_fog_detail_spread;
params.temporal_blend = env->volumetric_fog_temporal_reprojection_amount;
Transform3D to_prev_cam_view = rb->volumetric_fog->prev_cam_transform.affine_inverse() * p_cam_transform;
storage->store_transform(to_prev_cam_view, params.to_prev_view);
storage->store_transform(p_cam_transform, params.transform);
RD::get_singleton()->buffer_update(volumetric_fog.volume_ubo, 0, sizeof(VolumetricFogShader::VolumeUBO), &params, RD::BARRIER_MASK_COMPUTE);
if (rb->volumetric_fog->fog_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) {
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 1;
u.ids.push_back(rb->volumetric_fog->emissive_map);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 2;
u.ids.push_back(volumetric_fog.volume_ubo);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 3;
u.ids.push_back(rb->volumetric_fog->density_map);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 4;
u.ids.push_back(rb->volumetric_fog->light_map);
uniforms.push_back(u);
}
rb->volumetric_fog->fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS);
}
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
bool any_uses_time = false;
for (int i = 0; i < (int)p_fog_volumes.size(); i++) {
FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null(p_fog_volumes[i]);
ERR_FAIL_COND(!fog_volume_instance);
RID fog_volume = fog_volume_instance->volume;
RID fog_material = storage->fog_volume_get_material(fog_volume);
FogMaterialData *material = nullptr;
if (fog_material.is_valid()) {
material = (FogMaterialData *)storage->material_get_data(fog_material, RendererStorageRD::SHADER_TYPE_FOG);
if (!material || !material->shader_data->valid) {
material = nullptr;
}
}
if (!material) {
fog_material = volumetric_fog.default_material;
material = (FogMaterialData *)storage->material_get_data(fog_material, RendererStorageRD::SHADER_TYPE_FOG);
}
ERR_FAIL_COND(!material);
FogShaderData *shader_data = material->shader_data;
ERR_FAIL_COND(!shader_data);
any_uses_time |= shader_data->uses_time;
Vector3i min = Vector3i();
Vector3i max = Vector3i();
Vector3i kernel_size = Vector3i();
Vector3 position = fog_volume_instance->transform.get_origin();
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) {
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);
points[2] = _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[3] = _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[4] = _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[5] = _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[6] = _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[7] = _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);
min = Vector3i(int32_t(rb->volumetric_fog->width) - 1, int32_t(rb->volumetric_fog->height) - 1, int32_t(rb->volumetric_fog->depth) - 1);
max = Vector3i(1, 1, 1);
for (int j = 0; j < 8; j++) {
min = Vector3i(MIN(min.x, points[j].x), MIN(min.y, points[j].y), MIN(min.z, points[j].z));
max = Vector3i(MAX(max.x, points[j].x), MAX(max.y, points[j].y), MAX(max.z, points[j].z));
}
kernel_size = max - min;
} else {
// Volume type global runs on all cells
extents = Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth);
min = Vector3i(0, 0, 0);
kernel_size = Vector3i(int32_t(rb->volumetric_fog->width), int32_t(rb->volumetric_fog->height), int32_t(rb->volumetric_fog->depth));
}
volumetric_fog.push_constant.position[0] = position.x;
volumetric_fog.push_constant.position[1] = position.y;
volumetric_fog.push_constant.position[2] = position.z;
volumetric_fog.push_constant.extents[0] = extents.x;
volumetric_fog.push_constant.extents[1] = extents.y;
volumetric_fog.push_constant.extents[2] = extents.z;
volumetric_fog.push_constant.corner[0] = min.x;
volumetric_fog.push_constant.corner[1] = min.y;
volumetric_fog.push_constant.corner[2] = min.z;
volumetric_fog.push_constant.shape = uint32_t(storage->fog_volume_get_shape(fog_volume));
storage->store_transform(fog_volume_instance->transform.affine_inverse(), volumetric_fog.push_constant.transform);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shader_data->pipeline);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->fog_uniform_set, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &volumetric_fog.push_constant, sizeof(VolumetricFogShader::FogPushConstant));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, volumetric_fog.base_uniform_set, VolumetricFogShader::FogSet::FOG_SET_BASE);
if (material->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material->uniform_set)) { // Material may not have a uniform set.
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, material->uniform_set, VolumetricFogShader::FogSet::FOG_SET_MATERIAL);
}
RD::get_singleton()->compute_list_dispatch_threads(compute_list, kernel_size.x, kernel_size.y, kernel_size.z);
}
if (any_uses_time || env->volumetric_fog_temporal_reprojection) {
RenderingServerDefault::redraw_request();
}
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->compute_list_end();
}
if (rb->volumetric_fog->process_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set)) {
//re create uniform set if needed
Vector<RD::Uniform> uniforms;
Vector<RD::Uniform> copy_uniforms;
{
RD::Uniform u;
@ -3578,6 +4003,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
}
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
@ -3590,6 +4016,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK));
}
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
@ -3598,6 +4025,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 3;
u.ids.push_back(get_omni_light_buffer());
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
RD::Uniform u;
@ -3605,6 +4033,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 4;
u.ids.push_back(get_spot_light_buffer());
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
@ -3613,6 +4042,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 5;
u.ids.push_back(get_directional_light_buffer());
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
@ -3621,6 +4051,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 6;
u.ids.push_back(rb->cluster_builder->get_cluster_buffer());
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
@ -3629,6 +4060,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 7;
u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
@ -3637,6 +4069,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 8;
u.ids.push_back(rb->volumetric_fog->light_density_map);
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
@ -3647,12 +4080,21 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 9;
u.ids.push_back(rb->volumetric_fog->prev_light_density_map);
copy_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 10;
u.ids.push_back(shadow_sampler);
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
@ -3661,6 +4103,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 11;
u.ids.push_back(render_buffers_get_voxel_gi_buffer(p_render_buffers));
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
@ -3671,6 +4114,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.ids.push_back(rb->gi.voxel_gi_textures[i]);
}
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
RD::Uniform u;
@ -3678,6 +4122,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 13;
u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
RD::Uniform u;
@ -3685,6 +4130,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.binding = 14;
u.ids.push_back(volumetric_fog.params_ubo);
uniforms.push_back(u);
copy_uniforms.push_back(u);
}
{
RD::Uniform u;
@ -3693,12 +4139,46 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
u.ids.push_back(rb->volumetric_fog->prev_light_density_map);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 16;
u.ids.push_back(rb->volumetric_fog->density_map);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 17;
u.ids.push_back(rb->volumetric_fog->light_map);
uniforms.push_back(u);
}
rb->volumetric_fog->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0);
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 18;
u.ids.push_back(rb->volumetric_fog->emissive_map);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 19;
RID radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
RID sky_texture = sky.sky_get_radiance_texture_rd(env->sky);
u.ids.push_back(sky_texture.is_valid() ? sky_texture : radiance_texture);
uniforms.push_back(u);
}
rb->volumetric_fog->copy_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY), 0);
rb->volumetric_fog->process_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY), 0);
SWAP(uniforms.write[7].ids.write[0], uniforms.write[8].ids.write[0]);
rb->volumetric_fog->uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0);
rb->volumetric_fog->process_uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, 0), 0);
}
bool using_sdfgi = env->volumetric_fog_gi_inject > 0.0001 && env->sdfgi_enabled && (rb->sdfgi != nullptr);
@ -3731,7 +4211,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
uniforms.push_back(u);
}
rb->volumetric_fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI), 1);
rb->volumetric_fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI), 1);
}
}
@ -3760,23 +4240,35 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
params.fog_frustum_size_end[0] = fog_far_size.x;
params.fog_frustum_size_end[1] = fog_far_size.y;
params.z_near = z_near;
params.ambient_inject = env->volumetric_fog_ambient_inject * env->ambient_light_energy;
params.z_far = z_far;
params.fog_frustum_end = fog_end;
Color ambient_color = env->ambient_light.to_linear();
params.ambient_color[0] = ambient_color.r;
params.ambient_color[1] = ambient_color.g;
params.ambient_color[2] = ambient_color.b;
params.sky_contribution = env->ambient_sky_contribution;
params.fog_volume_size[0] = rb->volumetric_fog->width;
params.fog_volume_size[1] = rb->volumetric_fog->height;
params.fog_volume_size[2] = rb->volumetric_fog->depth;
params.directional_light_count = p_directional_light_count;
Color light = env->volumetric_fog_light.to_linear();
params.light_energy[0] = light.r * env->volumetric_fog_light_energy;
params.light_energy[1] = light.g * env->volumetric_fog_light_energy;
params.light_energy[2] = light.b * env->volumetric_fog_light_energy;
Color emission = env->volumetric_fog_emission.to_linear();
params.base_emission[0] = emission.r * env->volumetric_fog_emission_energy;
params.base_emission[1] = emission.g * env->volumetric_fog_emission_energy;
params.base_emission[2] = emission.b * env->volumetric_fog_emission_energy;
params.base_density = env->volumetric_fog_density;
Color base_scattering = env->volumetric_fog_scattering.to_linear();
params.base_scattering[0] = base_scattering.r;
params.base_scattering[1] = base_scattering.g;
params.base_scattering[2] = base_scattering.b;
params.phase_g = env->volumetric_fog_anisotropy;
params.detail_spread = env->volumetric_fog_detail_spread;
params.gi_inject = env->volumetric_fog_gi_inject;
@ -3816,10 +4308,9 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
params.screen_size[1] = rb->height;
}
/* Vector2 dssize = directional_shadow_get_size();
push_constant.directional_shadow_pixel_size[0] = 1.0 / dssize.x;
push_constant.directional_shadow_pixel_size[1] = 1.0 / dssize.y;
*/
Basis sky_transform = env->sky_orientation;
sky_transform = sky_transform.inverse() * p_cam_transform.basis;
RendererStorageRD::store_transform_3x3(sky_transform, params.radiance_inverse_xform);
RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog");
@ -3828,33 +4319,32 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
bool use_filter = volumetric_fog_filter_active;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[using_sdfgi ? VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI : VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[using_sdfgi ? VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI : VOLUMETRIC_FOG_SHADER_DENSITY]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0);
if (using_sdfgi) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1);
}
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth);
RD::get_singleton()->compute_list_add_barrier(compute_list);
// Copy fog to history buffer
if (env->volumetric_fog_temporal_reprojection) {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->copy_uniform_set, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth);
RD::get_singleton()->compute_list_add_barrier(compute_list);
}
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->compute_list_end();
RD::get_singleton()->texture_copy(rb->volumetric_fog->light_density_map, rb->volumetric_fog->prev_light_density_map, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), 0, 0, 0, 0);
compute_list = RD::get_singleton()->compute_list_begin();
if (use_filter) {
if (volumetric_fog_filter_active) {
RD::get_singleton()->draw_command_begin_label("Filter Fog");
RENDER_TIMESTAMP("Filter Fog");
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth);
RD::get_singleton()->compute_list_end();
@ -3864,11 +4354,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), &params);
compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set2, 0);
if (using_sdfgi) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1);
}
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set2, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth);
RD::get_singleton()->compute_list_add_barrier(compute_list);
@ -3878,14 +4365,15 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RENDER_TIMESTAMP("Integrate Fog");
RD::get_singleton()->draw_command_begin_label("Integrate Fog");
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FOG]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, 1);
RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER);
RENDER_TIMESTAMP("<Volumetric Fog");
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->draw_command_end_label();
rb->volumetric_fog->prev_cam_transform = p_cam_transform;
}
@ -4053,12 +4541,12 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
}
if (is_volumetric_supported()) {
_update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count);
_update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count, *p_render_data->fog_volumes);
}
}
}
void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) {
// getting this here now so we can direct call a bunch of things more easily
RenderBuffers *rb = nullptr;
if (p_render_buffers.is_valid()) {
@ -4091,6 +4579,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
render_data.voxel_gi_instances = &p_voxel_gi_instances;
render_data.decals = &p_decals;
render_data.lightmaps = &p_lightmaps;
render_data.fog_volumes = &p_fog_volumes;
render_data.environment = p_environment;
render_data.camera_effects = p_camera_effects;
render_data.shadow_atlas = p_shadow_atlas;
@ -4512,7 +5001,8 @@ bool RendererSceneRenderRD::free(RID p_rid) {
} else if (shadow_atlas_owner.owns(p_rid)) {
shadow_atlas_set_size(p_rid, 0);
shadow_atlas_owner.free(p_rid);
} else if (fog_volume_instance_owner.owns(p_rid)) {
fog_volume_instance_owner.free(p_rid);
} else {
return false;
}
@ -4753,18 +5243,124 @@ void RendererSceneRenderRD::init() {
}
if (is_volumetric_supported()) {
String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n";
Vector<String> volumetric_fog_modes;
volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n#define ENABLE_SDFGI\n");
volumetric_fog_modes.push_back("\n#define MODE_FILTER\n");
volumetric_fog_modes.push_back("\n#define MODE_FOG\n");
volumetric_fog.shader.initialize(volumetric_fog_modes, defines);
volumetric_fog.shader_version = volumetric_fog.shader.version_create();
for (int i = 0; i < VOLUMETRIC_FOG_SHADER_MAX; i++) {
volumetric_fog.pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, i));
{
// Initialize local fog shader
Vector<String> volumetric_fog_modes;
volumetric_fog_modes.push_back("");
volumetric_fog.shader.initialize(volumetric_fog_modes);
storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_FOG, _create_fog_shader_funcs);
storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_FOG, _create_fog_material_funcs);
volumetric_fog.volume_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::VolumeUBO));
}
{
ShaderCompilerRD::DefaultIdentifierActions actions;
actions.renames["TIME"] = "scene_params.time";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
actions.renames["WORLD_POSITION"] = "world.xyz";
actions.renames["OBJECT_POSITION"] = "params.position";
actions.renames["UVW"] = "uvw";
actions.renames["EXTENTS"] = "params.extents";
actions.renames["ALBEDO"] = "albedo";
actions.renames["DENSITY"] = "density";
actions.renames["EMISSION"] = "emission";
actions.renames["SDF"] = "sdf";
actions.usage_defines["SDF"] = "#define SDF_USED\n";
actions.usage_defines["DENSITY"] = "#define DENSITY_USED\n";
actions.usage_defines["ALBEDO"] = "#define ALBEDO_USED\n";
actions.usage_defines["EMISSION"] = "#define EMISSION_USED\n";
actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = VolumetricFogShader::FogSet::FOG_SET_MATERIAL;
actions.base_uniform_string = "material.";
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_DISABLE;
actions.global_buffer_array_variable = "global_variables.data";
volumetric_fog.compiler.initialize(actions);
}
{
// default material and shader for fog shader
volumetric_fog.default_shader = storage->shader_allocate();
storage->shader_initialize(volumetric_fog.default_shader);
storage->shader_set_code(volumetric_fog.default_shader, R"(
// Default fog shader.
shader_type fog;
void fog() {
DENSITY = 1.0;
ALBEDO = vec3(1.0);
}
)");
volumetric_fog.default_material = storage->material_allocate();
storage->material_initialize(volumetric_fog.default_material);
storage->material_set_shader(volumetric_fog.default_material, volumetric_fog.default_shader);
FogMaterialData *md = (FogMaterialData *)storage->material_get_data(volumetric_fog.default_material, RendererStorageRD::SHADER_TYPE_FOG);
volumetric_fog.default_shader_rd = volumetric_fog.shader.version_get_shader(md->shader_data->version, 0);
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 1;
u.ids.resize(12);
RID *ids_ptr = u.ids.ptrw();
ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
u.ids.push_back(storage->global_variables_get_storage_buffer());
uniforms.push_back(u);
}
volumetric_fog.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_BASE);
}
{
String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n";
defines += "\n#define MAX_SKY_LOD " + itos(get_roughness_layers() - 1) + ".0\n";
if (is_using_radiance_cubemap_array()) {
defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
}
Vector<String> volumetric_fog_modes;
volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n#define ENABLE_SDFGI\n");
volumetric_fog_modes.push_back("\n#define MODE_FILTER\n");
volumetric_fog_modes.push_back("\n#define MODE_FOG\n");
volumetric_fog_modes.push_back("\n#define MODE_COPY\n");
volumetric_fog.process_shader.initialize(volumetric_fog_modes, defines);
volumetric_fog.process_shader_version = volumetric_fog.process_shader.version_create();
for (int i = 0; i < VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_MAX; i++) {
volumetric_fog.process_pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, i));
}
volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO));
}
volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO));
}
{
@ -4815,9 +5411,14 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
if (is_dynamic_gi_supported()) {
gi.free();
}
volumetric_fog.shader.version_free(volumetric_fog.shader_version);
if (is_volumetric_supported()) {
volumetric_fog.process_shader.version_free(volumetric_fog.process_shader_version);
RD::get_singleton()->free(volumetric_fog.volume_ubo);
RD::get_singleton()->free(volumetric_fog.params_ubo);
storage->free(volumetric_fog.default_shader);
storage->free(volumetric_fog.default_material);
}
RendererSceneSkyRD::SkyMaterialData *md = (RendererSceneSkyRD::SkyMaterialData *)storage->material_get_data(sky.sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY);

View file

@ -40,6 +40,7 @@
#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
#include "servers/rendering/renderer_rd/shaders/volumetric_fog.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl.gen.h"
#include "servers/rendering/renderer_scene.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
@ -64,6 +65,7 @@ struct RenderDataRD {
const PagedArray<RID> *voxel_gi_instances = nullptr;
const PagedArray<RID> *decals = nullptr;
const PagedArray<RID> *lightmaps = nullptr;
const PagedArray<RID> *fog_volumes = nullptr;
RID environment = RID();
RID camera_effects = RID();
RID shadow_atlas = RID();
@ -393,6 +395,16 @@ private:
mutable RID_Owner<LightInstance> light_instance_owner;
/* FOG VOLUMES */
struct FogVolumeInstance {
RID volume;
Transform3D transform;
bool active = false;
};
mutable RID_Owner<FogVolumeInstance> fog_volume_instance_owner;
/* ENVIRONMENT */
RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
@ -718,10 +730,15 @@ private:
RID light_density_map;
RID prev_light_density_map;
RID fog_map;
RID uniform_set;
RID uniform_set2;
RID density_map;
RID light_map;
RID emissive_map;
RID fog_uniform_set;
RID copy_uniform_set;
RID process_uniform_set;
RID process_uniform_set2;
RID sdfgi_uniform_set;
RID sky_uniform_set;
@ -730,30 +747,91 @@ private:
Transform3D prev_cam_transform;
};
enum {
VOLUMETRIC_FOG_SHADER_DENSITY,
VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI,
VOLUMETRIC_FOG_SHADER_FILTER,
VOLUMETRIC_FOG_SHADER_FOG,
VOLUMETRIC_FOG_SHADER_MAX,
};
struct VolumetricFogShader {
struct ParamsUBO {
enum FogSet {
FOG_SET_BASE,
FOG_SET_UNIFORMS,
FOG_SET_MATERIAL,
FOG_SET_MAX,
};
struct FogPushConstant {
float position[3];
float pad;
float extents[3];
float pad2;
int32_t corner[3];
uint32_t shape;
float transform[16];
};
struct VolumeUBO {
float fog_frustum_size_begin[2];
float fog_frustum_size_end[2];
float fog_frustum_end;
float z_near;
float z_far;
uint32_t filter_axis;
float time;
int32_t fog_volume_size[3];
uint32_t directional_light_count;
float light_energy[3];
uint32_t use_temporal_reprojection;
uint32_t temporal_frame;
float detail_spread;
float temporal_blend;
float to_prev_view[16];
float transform[16];
};
ShaderCompilerRD compiler;
VolumetricFogShaderRD shader;
FogPushConstant push_constant;
RID volume_ubo;
RID default_shader;
RID default_material;
RID default_shader_rd;
RID base_uniform_set;
RID params_ubo;
enum {
VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY,
VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI,
VOLUMETRIC_FOG_PROCESS_SHADER_FILTER,
VOLUMETRIC_FOG_PROCESS_SHADER_FOG,
VOLUMETRIC_FOG_PROCESS_SHADER_COPY,
VOLUMETRIC_FOG_PROCESS_SHADER_MAX,
};
struct ParamsUBO {
float fog_frustum_size_begin[2];
float fog_frustum_size_end[2];
float fog_frustum_end;
float ambient_inject;
float z_far;
uint32_t filter_axis;
float ambient_color[3];
float sky_contribution;
int32_t fog_volume_size[3];
uint32_t directional_light_count;
float base_emission[3];
float base_density;
float base_scattering[3];
float phase_g;
float detail_spread;
float gi_inject;
uint32_t max_voxel_gi_instances;
@ -770,13 +848,13 @@ private:
float cam_rotation[12];
float to_prev_view[16];
float radiance_inverse_xform[12];
};
VolumetricFogShaderRD shader;
VolumetricFogProcessShaderRD process_shader;
RID params_ubo;
RID shader_version;
RID pipelines[VOLUMETRIC_FOG_SHADER_MAX];
RID process_shader_version;
RID process_pipelines[VOLUMETRIC_FOG_PROCESS_SHADER_MAX];
} volumetric_fog;
@ -784,8 +862,57 @@ private:
uint32_t volumetric_fog_size = 128;
bool volumetric_fog_filter_active = true;
Vector3i _point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform);
void _volumetric_fog_erase(RenderBuffers *rb);
void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count);
void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes);
struct FogShaderData : public RendererStorageRD::ShaderData {
bool valid;
RID version;
RID pipeline;
Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size;
String path;
String code;
Map<StringName, RID> default_texture_params;
bool uses_time;
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual Variant get_default_parameter(const StringName &p_parameter) const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
FogShaderData();
virtual ~FogShaderData();
};
struct FogMaterialData : public RendererStorageRD::MaterialData {
uint64_t last_frame;
FogShaderData *shader_data;
RID uniform_set;
bool uniform_set_updated;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
virtual ~FogMaterialData();
};
RendererStorageRD::ShaderData *_create_fog_shader_func();
static RendererStorageRD::ShaderData *_create_fog_shader_funcs();
RendererStorageRD::MaterialData *_create_fog_material_func(FogShaderData *p_shader);
static RendererStorageRD::MaterialData *_create_fog_material_funcs(RendererStorageRD::ShaderData *p_shader);
RID shadow_sampler;
@ -904,7 +1031,7 @@ public:
float environment_get_fog_height_density(RID p_env) const;
float environment_get_fog_aerial_perspective(RID p_env) const;
virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) override;
virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) override;
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) override;
@ -931,6 +1058,8 @@ public:
virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override;
/* CAMERA EFFECTS */
virtual RID camera_effects_allocate() override;
virtual void camera_effects_initialize(RID p_rid) override;
@ -946,6 +1075,8 @@ public:
return camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0;
}
/* LIGHT INSTANCE API */
virtual RID light_instance_create(RID p_light) override;
virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
@ -1082,6 +1213,14 @@ public:
return li->light_type;
}
/* FOG VOLUMES */
virtual RID fog_volume_instance_create(RID p_fog_volume) override;
virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override;
virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override;
virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override;
virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override;
virtual RID reflection_atlas_create() override;
virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
virtual int reflection_atlas_get_size(RID p_ref_atlas) const override;
@ -1224,7 +1363,7 @@ public:
float render_buffers_get_volumetric_fog_end(RID p_render_buffers);
float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers);
virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;

View file

@ -292,7 +292,12 @@ void RendererSceneSkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
}
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3);
// Fog uniform set can be invalidated before drawing, so validate at draw time
if (sky_scene_state.fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_uniform_set)) {
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3);
} else {
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.default_fog_uniform_set, 3);
}
}
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
@ -1165,14 +1170,8 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b
} else {
sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
}
}
RID fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
if (fog_uniform_set != RID()) {
sky_scene_state.fog_uniform_set = fog_uniform_set;
} else {
sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set;
sky_scene_state.fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
}
}

View file

@ -1399,6 +1399,8 @@ void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) {
new_type = SHADER_TYPE_3D;
} else if (mode_string == "sky") {
new_type = SHADER_TYPE_SKY;
} else if (mode_string == "fog") {
new_type = SHADER_TYPE_FOG;
} else {
new_type = SHADER_TYPE_MAX;
}
@ -2692,20 +2694,56 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari
if (textures.is_empty()) {
//check default usage
switch (p_texture_uniforms[i].hint) {
case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK);
switch (p_texture_uniforms[i].type) {
case ShaderLanguage::TYPE_ISAMPLER2D:
case ShaderLanguage::TYPE_USAMPLER2D:
case ShaderLanguage::TYPE_SAMPLER2D: {
switch (p_texture_uniforms[i].hint) {
case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK);
} break;
case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
} break;
case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO);
} break;
default: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
} break;
}
} break;
case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
case ShaderLanguage::TYPE_SAMPLERCUBE: {
switch (p_texture_uniforms[i].hint) {
case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
} break;
default: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_WHITE);
} break;
}
} break;
case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO);
case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK);
} break;
case ShaderLanguage::TYPE_ISAMPLER3D:
case ShaderLanguage::TYPE_USAMPLER3D:
case ShaderLanguage::TYPE_SAMPLER3D: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_3D_WHITE);
} break;
case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
case ShaderLanguage::TYPE_USAMPLER2DARRAY:
case ShaderLanguage::TYPE_SAMPLER2DARRAY: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
} break;
default: {
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
} break;
}
}
#ifdef TOOLS_ENABLED
if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) {
@ -6002,6 +6040,82 @@ void RendererStorageRD::particles_collision_instance_set_active(RID p_collision_
pci->active = p_active;
}
/* FOG VOLUMES */
RID RendererStorageRD::fog_volume_allocate() {
return fog_volume_owner.allocate_rid();
}
void RendererStorageRD::fog_volume_initialize(RID p_rid) {
fog_volume_owner.initialize_rid(p_rid, FogVolume());
}
void RendererStorageRD::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
ERR_FAIL_COND(!fog_volume);
if (p_shape == fog_volume->shape) {
return;
}
fog_volume->shape = p_shape;
fog_volume->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
}
void RendererStorageRD::fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
ERR_FAIL_COND(!fog_volume);
fog_volume->extents = p_extents;
fog_volume->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
}
void RendererStorageRD::fog_volume_set_material(RID p_fog_volume, RID p_material) {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
ERR_FAIL_COND(!fog_volume);
fog_volume->material = p_material;
}
RID RendererStorageRD::fog_volume_get_material(RID p_fog_volume) const {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
ERR_FAIL_COND_V(!fog_volume, RID());
return fog_volume->material;
}
RS::FogVolumeShape RendererStorageRD::fog_volume_get_shape(RID p_fog_volume) const {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
ERR_FAIL_COND_V(!fog_volume, RS::FOG_VOLUME_SHAPE_BOX);
return fog_volume->shape;
}
AABB RendererStorageRD::fog_volume_get_aabb(RID p_fog_volume) const {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
ERR_FAIL_COND_V(!fog_volume, AABB());
switch (fog_volume->shape) {
case RS::FOG_VOLUME_SHAPE_ELLIPSOID:
case RS::FOG_VOLUME_SHAPE_BOX: {
AABB aabb;
aabb.position = -fog_volume->extents;
aabb.size = fog_volume->extents * 2;
return aabb;
}
default: {
// Need some size otherwise will get culled
return AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
}
}
return AABB();
}
Vector3 RendererStorageRD::fog_volume_get_extents(RID p_fog_volume) const {
const FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
ERR_FAIL_COND_V(!fog_volume, Vector3());
return fog_volume->extents;
}
/* VISIBILITY NOTIFIER */
RID RendererStorageRD::visibility_notifier_allocate() {
@ -8083,6 +8197,9 @@ void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_
} else if (particles_collision_owner.owns(p_base)) {
ParticlesCollision *pc = particles_collision_owner.get_or_null(p_base);
p_instance->update_dependency(&pc->dependency);
} else if (fog_volume_owner.owns(p_base)) {
FogVolume *fv = fog_volume_owner.get_or_null(p_base);
p_instance->update_dependency(&fv->dependency);
} else if (visibility_notifier_owner.owns(p_base)) {
VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_base);
p_instance->update_dependency(&vn->dependency);
@ -8124,6 +8241,9 @@ RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const {
if (particles_collision_owner.owns(p_rid)) {
return RS::INSTANCE_PARTICLES_COLLISION;
}
if (fog_volume_owner.owns(p_rid)) {
return RS::INSTANCE_FOG_VOLUME;
}
if (visibility_notifier_owner.owns(p_rid)) {
return RS::INSTANCE_VISIBLITY_NOTIFIER;
}
@ -9206,6 +9326,10 @@ bool RendererStorageRD::free(RID p_rid) {
visibility_notifier_owner.free(p_rid);
} else if (particles_collision_instance_owner.owns(p_rid)) {
particles_collision_instance_owner.free(p_rid);
} else if (fog_volume_owner.owns(p_rid)) {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_rid);
fog_volume->dependency.deleted_notify(p_rid);
fog_volume_owner.free(p_rid);
} else if (render_target_owner.owns(p_rid)) {
RenderTarget *rt = render_target_owner.get_or_null(p_rid);
@ -9499,6 +9623,18 @@ RendererStorageRD::RendererStorageRD() {
pv.set(i * 4 + 3, 0);
}
{
Vector<Vector<uint8_t>> vpv;
vpv.push_back(pv);
default_rd_textures[DEFAULT_RD_TEXTURE_3D_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
}
for (int i = 0; i < 64; i++) {
pv.set(i * 4 + 0, 255);
pv.set(i * 4 + 1, 255);
pv.set(i * 4 + 2, 255);
pv.set(i * 4 + 3, 255);
}
{
Vector<Vector<uint8_t>> vpv;
vpv.push_back(pv);

View file

@ -129,6 +129,7 @@ public:
SHADER_TYPE_3D,
SHADER_TYPE_PARTICLES,
SHADER_TYPE_SKY,
SHADER_TYPE_FOG,
SHADER_TYPE_MAX
};
@ -188,6 +189,7 @@ public:
DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK,
DEFAULT_RD_TEXTURE_CUBEMAP_WHITE,
DEFAULT_RD_TEXTURE_3D_WHITE,
DEFAULT_RD_TEXTURE_3D_BLACK,
DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE,
DEFAULT_RD_TEXTURE_2D_UINT,
DEFAULT_RD_TEXTURE_MAX
@ -957,6 +959,19 @@ private:
mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner;
/* FOG VOLUMES */
struct FogVolume {
RID material;
Vector3 extents = Vector3(1, 1, 1);
RS::FogVolumeShape shape = RS::FOG_VOLUME_SHAPE_BOX;
Dependency dependency;
};
mutable RID_Owner<FogVolume, true> fog_volume_owner;
/* visibility_notifier */
struct VisibilityNotifier {
@ -2259,6 +2274,21 @@ public:
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const;
RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
/* FOG VOLUMES */
virtual RID fog_volume_allocate();
virtual void fog_volume_initialize(RID p_rid);
virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape);
virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents);
virtual void fog_volume_set_material(RID p_fog_volume, RID p_material);
virtual RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const;
virtual RID fog_volume_get_material(RID p_fog_volume) const;
virtual AABB fog_volume_get_aabb(RID p_fog_volume) const;
virtual Vector3 fog_volume_get_extents(RID p_fog_volume) const;
/* VISIBILITY NOTIFIER */
virtual RID visibility_notifier_allocate();
virtual void visibility_notifier_initialize(RID p_notifier);
virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb);

View file

@ -4,219 +4,88 @@
#VERSION_DEFINES
/* Do not use subgroups here, seems there is not much advantage and causes glitches
#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
#extension GL_KHR_shader_subgroup_ballot: enable
#extension GL_KHR_shader_subgroup_arithmetic: enable
#define USE_SUBGROUPS
#endif
*/
#if defined(MODE_FOG) || defined(MODE_FILTER)
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#endif
#if defined(MODE_DENSITY)
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
#endif
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
#define SAMPLER_NEAREST_REPEAT 6
#define SAMPLER_LINEAR_REPEAT 7
#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
#define DENSITY_SCALE 1024.0
#include "cluster_data_inc.glsl"
#include "light_data_inc.glsl"
#define M_PI 3.14159265359
layout(set = 0, binding = 1) uniform texture2D shadow_atlas;
layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas;
layout(set = 0, binding = 1) uniform sampler material_samplers[12];
layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
LightData data[];
layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalVariableData {
vec4 data[];
}
omni_lights;
global_variables;
layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
LightData data[];
}
spot_lights;
layout(set = 0, binding = 5, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer {
uint data[];
}
cluster_buffer;
layout(set = 0, binding = 7) uniform sampler linear_sampler;
#ifdef MODE_DENSITY
layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map;
layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused
#endif
#ifdef MODE_FOG
layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map;
layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map;
#endif
#ifdef MODE_FILTER
layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
#endif
layout(set = 0, binding = 10) uniform sampler shadow_sampler;
#define MAX_VOXEL_GI_INSTANCES 8
struct VoxelGIData {
mat4 xform;
vec3 bounds;
float dynamic_range;
float bias;
float normal_bias;
bool blend_ambient;
uint texture_slot;
float anisotropy_strength;
float ambient_occlusion;
float ambient_occlusion_size;
uint mipmaps;
};
layout(set = 0, binding = 11, std140) uniform VoxelGIs {
VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
voxel_gi_instances;
layout(set = 0, binding = 12) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps;
#ifdef ENABLE_SDFGI
// SDFGI Integration on set 1
#define SDFGI_MAX_CASCADES 8
struct SDFVoxelGICascadeData {
layout(push_constant, binding = 0, std430) uniform Params {
vec3 position;
float to_probe;
ivec3 probe_world_offset;
float to_cell; // 1/bounds * grid_size
};
float pad;
layout(set = 1, binding = 0, std140) uniform SDFGI {
vec3 grid_size;
uint max_cascades;
vec3 extents;
float pad2;
bool use_occlusion;
int probe_axis_size;
float probe_to_uvw;
float normal_bias;
ivec3 corner;
uint shape;
vec3 lightprobe_tex_pixel_size;
float energy;
vec3 lightprobe_uv_offset;
float y_mult;
vec3 occlusion_clamp;
uint pad3;
vec3 occlusion_renormalize;
uint pad4;
vec3 cascade_probe_size;
uint pad5;
SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES];
mat4 transform;
}
sdfgi;
params;
layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture;
layout(r32ui, set = 1, binding = 1) uniform volatile uimage3D emissive_only_map;
layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture;
#endif //SDFGI
layout(set = 0, binding = 14, std140) uniform Params {
layout(set = 1, binding = 2, std140) uniform SceneParams {
vec2 fog_frustum_size_begin;
vec2 fog_frustum_size_end;
float fog_frustum_end;
float z_near;
float z_far;
int filter_axis;
float z_near; //
float z_far; //
float time;
ivec3 fog_volume_size;
uint directional_light_count;
uint directional_light_count; //
vec3 light_color;
float base_density;
float detail_spread;
float gi_inject;
uint max_voxel_gi_instances;
uint cluster_type_size;
vec2 screen_size;
uint cluster_shift;
uint cluster_width;
uint max_cluster_element_count_div_32;
bool use_temporal_reprojection;
uint temporal_frame;
float detail_spread;
float temporal_blend;
mat3x4 cam_rotation;
mat4 to_prev_view;
mat4 transform;
}
params;
scene_params;
layout(set = 0, binding = 15) uniform texture3D prev_density_texture;
layout(r32ui, set = 1, binding = 3) uniform volatile uimage3D density_only_map;
layout(r32ui, set = 1, binding = 4) uniform volatile uimage3D light_only_map;
#ifdef MATERIAL_UNIFORMS_USED
layout(set = 2, binding = 0, std140) uniform MaterialUniforms{
#MATERIAL_UNIFORMS
} material;
#endif
#GLOBALS
float get_depth_at_pos(float cell_depth_size, int z) {
float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels
d = pow(d, params.detail_spread);
return params.fog_frustum_end * d;
}
vec3 hash3f(uvec3 x) {
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF));
}
float get_omni_attenuation(float distance, float inv_range, float decay) {
float nd = distance * inv_range;
nd *= nd;
nd *= nd; // nd^4
nd = max(1.0 - nd, 0.0);
nd *= nd; // nd^2
return nd * pow(max(distance, 0.0001), -decay);
}
void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) {
uint item_min_max = cluster_buffer.data[p_offset];
item_min = item_min_max & 0xFFFF;
item_max = item_min_max >> 16;
;
item_from = item_min >> 5;
item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements
}
uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) {
int local_min = clamp(int(z_min) - int(i) * 32, 0, 31);
int mask_width = min(int(z_max) - int(z_min), 32 - local_min);
return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width);
d = pow(d, scene_params.detail_spread);
return scene_params.fog_frustum_end * d;
}
#define TEMPORAL_FRAMES 16
@ -240,464 +109,144 @@ const vec3 halton_map[TEMPORAL_FRAMES] = vec3[](
vec3(0.03125, 0.59259259, 0.32));
void main() {
vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size);
vec3 fog_cell_size = 1.0 / vec3(scene_params.fog_volume_size);
#ifdef MODE_DENSITY
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
if (any(greaterThanEqual(pos, params.fog_volume_size))) {
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz) + params.corner;
if (any(greaterThanEqual(pos, scene_params.fog_volume_size))) {
return; //do not compute
}
vec3 posf = vec3(pos);
//posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0;
vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels
uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
uvec2 cluster_pos = screen_pos >> params.cluster_shift;
uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
//positions in screen are too spread apart, no hopes for optimizing with subgroups
fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
fog_unit_pos.z = pow(fog_unit_pos.z, scene_params.detail_spread);
vec3 view_pos;
view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z));
view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z;
view_pos.y = -view_pos.y;
vec4 reprojected_density = vec4(0.0);
float reproject_amount = 0.0;
if (params.use_temporal_reprojection) {
vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz;
if (scene_params.use_temporal_reprojection) {
vec3 prev_view = (scene_params.to_prev_view * vec4(view_pos, 1.0)).xyz;
//undo transform into prev view
prev_view.y = -prev_view.y;
//z back to unit size
prev_view.z /= -params.fog_frustum_end;
prev_view.z /= -scene_params.fog_frustum_end;
//xy back to unit size
prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z));
prev_view.xy /= mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(prev_view.z));
prev_view.xy = prev_view.xy * 0.5 + 0.5;
//z back to unspread value
prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread);
prev_view.z = pow(prev_view.z, 1.0 / scene_params.detail_spread);
if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) {
//reprojectinon fits
reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0);
reproject_amount = params.temporal_blend;
// Since we can reproject, now we must jitter the current view pos.
// This is done here because cells that can't reproject should not jitter.
fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table
fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[scene_params.temporal_frame]; //center of voxels, offset by halton table
fog_unit_pos.z = pow(fog_unit_pos.z, scene_params.detail_spread);
screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
cluster_pos = screen_pos >> params.cluster_shift;
cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
//positions in screen are too spread apart, no hopes for optimizing with subgroups
fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z));
view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z;
view_pos.y = -view_pos.y;
}
}
uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0));
float density = 0.0;
vec3 emission = vec3(0.0);
vec3 albedo = vec3(0.0);
vec3 total_light = params.light_color;
float total_density = params.base_density;
float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1));
//compute directional lights
for (uint i = 0; i < params.directional_light_count; i++) {
vec3 shadow_attenuation = vec3(1.0);
vec4 world = scene_params.transform * vec4(view_pos, 1.0);
world.xyz /= world.w;
if (directional_lights.data[i].shadow_enabled) {
float depth_z = -view_pos.z;
vec3 uvw = fog_unit_pos;
vec4 pssm_coord;
vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb;
vec3 light_dir = directional_lights.data[i].direction;
vec4 v = vec4(view_pos, 1.0);
float z_range;
vec4 local_pos = params.transform * world;
local_pos.xyz /= local_pos.w;
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
pssm_coord /= pssm_coord.w;
z_range = directional_lights.data[i].shadow_z_range.x;
float sdf = -1.0;
if (params.shape == 0) {
//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) {
// Box
// https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
vec3 q = abs(local_pos.xyz) - params.extents;
sdf = length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
pssm_coord /= pssm_coord.w;
z_range = directional_lights.data[i].shadow_z_range.y;
float cull_mask = 1.0; //used to cull cells that do not contribute
if (params.shape <= 1) {
#ifndef SDF_USED
cull_mask = 1.0 - smoothstep(-0.1, 0.0, sdf);
#endif
uvw = clamp((local_pos.xyz + params.extents) / (2.0 * params.extents), 0.0, 1.0);
}
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
pssm_coord /= pssm_coord.w;
z_range = directional_lights.data[i].shadow_z_range.z;
} else {
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
pssm_coord /= pssm_coord.w;
z_range = directional_lights.data[i].shadow_z_range.w;
}
float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade);
/*
//float shadow = textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord);
float shadow = 0.0;
for(float xi=-1;xi<=1;xi++) {
for(float yi=-1;yi<=1;yi++) {
vec2 ofs = vec2(xi,yi) * 1.5 * params.directional_shadow_pixel_size;
shadow += textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord + vec4(ofs,0.0,0.0));
}
}
shadow /= 3.0 * 3.0;
*/
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance
shadow_attenuation = mix(shadow_color, vec3(1.0), shadow);
if (cull_mask > 0.0) {
{
#CODE : FOG
}
total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy / M_PI;
}
#ifdef DENSITY_USED
density *= cull_mask;
if (abs(density) > 0.001) {
int final_density = int(density * DENSITY_SCALE);
imageAtomicAdd(density_only_map, pos, uint(final_density));
//compute lights from cluster
#ifdef EMISSION_USED
{
emission *= clamp(density, 0.0, 1.0);
emission = clamp(emission, vec3(0.0), vec3(4.0));
// Scale to fit into R11G11B10 with a range of 0-4
uvec3 emission_u = uvec3(emission.r * 511.0, emission.g * 511.0, emission.b * 255.0);
// R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint
uint final_emission = emission_u.r << 21 | emission_u.g << 10 | emission_u.b;
uint prev_emission = imageAtomicAdd(emissive_only_map, pos, final_emission);
{ //omni lights
// Adding can lead to colors overflowing, so validate
uvec3 prev_emission_u = uvec3(prev_emission >> 21, (prev_emission << 11) >> 21, prev_emission % 1024);
uint add_emission = final_emission + prev_emission;
uvec3 add_emission_u = uvec3(add_emission >> 21, (add_emission << 11) >> 21, add_emission % 1024);
uint cluster_omni_offset = cluster_offset;
bvec3 overflowing = lessThan(add_emission_u, prev_emission_u + emission_u);
uint item_min;
uint item_max;
uint item_from;
uint item_to;
cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
for (uint i = item_from; i < item_to; i++) {
uint mask = cluster_buffer.data[cluster_omni_offset + i];
mask &= cluster_get_range_clip_mask(i, item_min, item_max);
#ifdef USE_SUBGROUPS
uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
#else
uint merged_mask = mask;
#endif
while (merged_mask != 0) {
uint bit = findMSB(merged_mask);
merged_mask &= ~(1 << bit);
#ifdef USE_SUBGROUPS
if (((1 << bit) & mask) == 0) { //do not process if not originally here
continue;
}
#endif
uint light_index = 32 * i + bit;
//if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) {
// continue; //not masked
//}
vec3 light_pos = omni_lights.data[light_index].position;
float d = distance(omni_lights.data[light_index].position, view_pos);
float shadow_attenuation = 1.0;
if (d * omni_lights.data[light_index].inv_radius < 1.0) {
float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation);
vec3 light = omni_lights.data[light_index].color / M_PI;
if (omni_lights.data[light_index].shadow_enabled) {
//has shadow
vec4 v = vec4(view_pos, 1.0);
vec4 splane = (omni_lights.data[light_index].shadow_matrix * v);
float shadow_len = length(splane.xyz); //need to remember shadow len from here
splane.xyz = normalize(splane.xyz);
vec4 clamp_rect = omni_lights.data[light_index].atlas_rect;
if (splane.z >= 0.0) {
splane.z += 1.0;
clamp_rect.y += clamp_rect.w;
} else {
splane.z = 1.0 - splane.z;
}
splane.xy /= splane.z;
splane.xy = splane.xy * 0.5 + 0.5;
splane.z = shadow_len * omni_lights.data[light_index].inv_radius;
splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
splane.w = 1.0; //needed? i think it should be 1 already
float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
shadow_attenuation = exp(min(0.0, (depth - splane.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade);
}
total_light += light * attenuation * shadow_attenuation;
if (any(overflowing)) {
uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing);
uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b;
imageAtomicOr(emissive_only_map, pos, force_max);
}
}
}
}
{ //spot lights
uint cluster_spot_offset = cluster_offset + params.cluster_type_size;
uint item_min;
uint item_max;
uint item_from;
uint item_to;
cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
#ifdef ALBEDO_USED
{
vec3 scattering = albedo * clamp(density, 0.0, 1.0);
scattering = clamp(scattering, vec3(0.0), vec3(1.0));
uvec3 scattering_u = uvec3(scattering.r * 2047.0, scattering.g * 2047.0, scattering.b * 1023.0);
// R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint
uint final_scattering = scattering_u.r << 21 | scattering_u.g << 10 | scattering_u.b;
uint prev_scattering = imageAtomicAdd(light_only_map, pos, final_scattering);
for (uint i = item_from; i < item_to; i++) {
uint mask = cluster_buffer.data[cluster_spot_offset + i];
mask &= cluster_get_range_clip_mask(i, item_min, item_max);
#ifdef USE_SUBGROUPS
uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
#else
uint merged_mask = mask;
#endif
// Adding can lead to colors overflowing, so validate
uvec3 prev_scattering_u = uvec3(prev_scattering >> 21, (prev_scattering << 11) >> 21, prev_scattering % 1024);
uint add_scattering = final_scattering + prev_scattering;
uvec3 add_scattering_u = uvec3(add_scattering >> 21, (add_scattering << 11) >> 21, add_scattering % 1024);
while (merged_mask != 0) {
uint bit = findMSB(merged_mask);
merged_mask &= ~(1 << bit);
#ifdef USE_SUBGROUPS
if (((1 << bit) & mask) == 0) { //do not process if not originally here
continue;
}
#endif
bvec3 overflowing = lessThan(add_scattering_u, prev_scattering_u + scattering_u);
//if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) {
// continue; //not masked
//}
uint light_index = 32 * i + bit;
vec3 light_pos = spot_lights.data[light_index].position;
vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos;
float d = length(light_rel_vec);
float shadow_attenuation = 1.0;
if (d * spot_lights.data[light_index].inv_radius < 1.0) {
float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation);
vec3 spot_dir = spot_lights.data[light_index].direction;
float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle);
float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle));
attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation);
vec3 light = spot_lights.data[light_index].color / M_PI;
if (spot_lights.data[light_index].shadow_enabled) {
//has shadow
vec4 v = vec4(view_pos, 1.0);
vec4 splane = (spot_lights.data[light_index].shadow_matrix * v);
splane /= splane.w;
float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade);
}
total_light += light * attenuation * shadow_attenuation;
if (any(overflowing)) {
uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing);
uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b;
imageAtomicOr(light_only_map, pos, force_max);
}
}
#endif // ALBEDO_USED
}
#endif // DENSITY_USED
}
vec3 world_pos = mat3(params.cam_rotation) * view_pos;
for (uint i = 0; i < params.max_voxel_gi_instances; i++) {
vec3 position = (voxel_gi_instances.data[i].xform * vec4(world_pos, 1.0)).xyz;
//this causes corrupted pixels, i have no idea why..
if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, voxel_gi_instances.data[i].bounds))))) {
position /= voxel_gi_instances.data[i].bounds;
vec4 light = vec4(0.0);
for (uint j = 0; j < voxel_gi_instances.data[i].mipmaps; j++) {
vec4 slight = textureLod(sampler3D(voxel_gi_textures[i], linear_sampler_with_mipmaps), position, float(j));
float a = (1.0 - light.a);
light += a * slight;
}
light.rgb *= voxel_gi_instances.data[i].dynamic_range * params.gi_inject;
total_light += light.rgb;
}
}
//sdfgi
#ifdef ENABLE_SDFGI
{
float blend = -1.0;
vec3 ambient_total = vec3(0.0);
for (uint i = 0; i < sdfgi.max_cascades; i++) {
vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe;
if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) {
continue; //skip cascade
}
vec3 base_pos = floor(cascade_pos);
ivec3 probe_base_pos = ivec3(base_pos);
vec4 ambient_accum = vec4(0.0);
ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i));
tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
for (uint j = 0; j < 8; j++) {
ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
ivec3 probe_posi = probe_base_pos;
probe_posi += offset;
// Compute weight
vec3 probe_pos = vec3(probe_posi);
vec3 probe_to_pos = cascade_pos - probe_pos;
vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
float weight = trilinear.x * trilinear.y * trilinear.z;
// Compute lightprobe occlusion
if (sdfgi.use_occlusion) {
ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
occ_pos.z += float(i);
if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
occ_pos.x += 1.0;
}
occ_pos *= sdfgi.occlusion_renormalize;
float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask);
weight *= max(occlusion, 0.01);
}
// Compute ambient texture position
ivec3 uvw = tex_pos;
uvw.xy += offset.xy;
uvw.x += offset.z * sdfgi.probe_axis_size;
vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb;
ambient_accum.rgb += ambient * weight;
ambient_accum.a += weight;
}
if (ambient_accum.a > 0) {
ambient_accum.rgb /= ambient_accum.a;
}
ambient_total = ambient_accum.rgb;
break;
}
total_light += ambient_total * params.gi_inject;
}
#endif
vec4 final_density = vec4(total_light, total_density);
final_density = mix(final_density, reprojected_density, reproject_amount);
imageStore(density_map, pos, final_density);
#endif
#ifdef MODE_FOG
ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0);
if (any(greaterThanEqual(pos, params.fog_volume_size))) {
return; //do not compute
}
vec4 fog_accum = vec4(0.0);
float prev_z = 0.0;
float t = 1.0;
for (int i = 0; i < params.fog_volume_size.z; i++) {
//compute fog position
ivec3 fog_pos = pos + ivec3(0, 0, i);
//get fog value
vec4 fog = imageLoad(density_map, fog_pos);
//get depth at cell pos
float z = get_depth_at_pos(fog_cell_size.z, i);
//get distance from previous pos
float d = abs(prev_z - z);
//compute exinction based on beer's
float extinction = t * exp(-d * fog.a);
//compute alpha based on different of extinctions
float alpha = t - extinction;
//update extinction
t = extinction;
fog_accum += vec4(fog.rgb * alpha, alpha);
prev_z = z;
vec4 fog_value;
if (fog_accum.a > 0.0) {
fog_value = vec4(fog_accum.rgb / fog_accum.a, 1.0 - t);
} else {
fog_value = vec4(0.0);
}
imageStore(fog_map, fog_pos, fog_value);
}
#endif
#ifdef MODE_FILTER
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303);
const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1));
ivec3 offset = filter_dir[params.filter_axis];
vec4 accum = vec4(0.0);
for (int i = -3; i <= 3; i++) {
accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3];
}
imageStore(dest_map, pos, accum);
#endif
}

View file

@ -0,0 +1,741 @@
#[compute]
#version 450
#VERSION_DEFINES
/* Do not use subgroups here, seems there is not much advantage and causes glitches
#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
#extension GL_KHR_shader_subgroup_ballot: enable
#extension GL_KHR_shader_subgroup_arithmetic: enable
#define USE_SUBGROUPS
#endif
*/
#ifdef MODE_DENSITY
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
#else
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#endif
#include "cluster_data_inc.glsl"
#include "light_data_inc.glsl"
#define M_PI 3.14159265359
#define DENSITY_SCALE 1024.0
layout(set = 0, binding = 1) uniform texture2D shadow_atlas;
layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas;
layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
LightData data[];
}
omni_lights;
layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
LightData data[];
}
spot_lights;
layout(set = 0, binding = 5, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer {
uint data[];
}
cluster_buffer;
layout(set = 0, binding = 7) uniform sampler linear_sampler;
#ifdef MODE_DENSITY
layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map;
layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused
#endif
#ifdef MODE_FOG
layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map;
layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map;
#endif
#ifdef MODE_COPY
layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
#endif
#ifdef MODE_FILTER
layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map;
layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map;
#endif
layout(set = 0, binding = 10) uniform sampler shadow_sampler;
#define MAX_VOXEL_GI_INSTANCES 8
struct VoxelGIData {
mat4 xform;
vec3 bounds;
float dynamic_range;
float bias;
float normal_bias;
bool blend_ambient;
uint texture_slot;
float anisotropy_strength;
float ambient_occlusion;
float ambient_occlusion_size;
uint mipmaps;
};
layout(set = 0, binding = 11, std140) uniform VoxelGIs {
VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
voxel_gi_instances;
layout(set = 0, binding = 12) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps;
#ifdef ENABLE_SDFGI
// SDFGI Integration on set 1
#define SDFGI_MAX_CASCADES 8
struct SDFVoxelGICascadeData {
vec3 position;
float to_probe;
ivec3 probe_world_offset;
float to_cell; // 1/bounds * grid_size
};
layout(set = 1, binding = 0, std140) uniform SDFGI {
vec3 grid_size;
uint max_cascades;
bool use_occlusion;
int probe_axis_size;
float probe_to_uvw;
float normal_bias;
vec3 lightprobe_tex_pixel_size;
float energy;
vec3 lightprobe_uv_offset;
float y_mult;
vec3 occlusion_clamp;
uint pad3;
vec3 occlusion_renormalize;
uint pad4;
vec3 cascade_probe_size;
uint pad5;
SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES];
}
sdfgi;
layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture;
layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture;
#endif //SDFGI
layout(set = 0, binding = 14, std140) uniform Params {
vec2 fog_frustum_size_begin;
vec2 fog_frustum_size_end;
float fog_frustum_end;
float ambient_inject;
float z_far;
int filter_axis;
vec3 ambient_color;
float sky_contribution;
ivec3 fog_volume_size;
uint directional_light_count;
vec3 base_emission;
float base_density;
vec3 base_scattering;
float phase_g;
float detail_spread;
float gi_inject;
uint max_voxel_gi_instances;
uint cluster_type_size;
vec2 screen_size;
uint cluster_shift;
uint cluster_width;
uint max_cluster_element_count_div_32;
bool use_temporal_reprojection;
uint temporal_frame;
float temporal_blend;
mat3x4 cam_rotation;
mat4 to_prev_view;
mat3 radiance_inverse_xform;
}
params;
#ifndef MODE_COPY
layout(set = 0, binding = 15) uniform texture3D prev_density_texture;
layout(r32ui, set = 0, binding = 16) uniform uimage3D density_only_map;
layout(r32ui, set = 0, binding = 17) uniform uimage3D light_only_map;
layout(r32ui, set = 0, binding = 18) uniform uimage3D emissive_only_map;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
layout(set = 0, binding = 19) uniform textureCubeArray sky_texture;
#else
layout(set = 0, binding = 19) uniform textureCube sky_texture;
#endif
#endif // MODE_COPY
float get_depth_at_pos(float cell_depth_size, int z) {
float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels
d = pow(d, params.detail_spread);
return params.fog_frustum_end * d;
}
vec3 hash3f(uvec3 x) {
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF));
}
float get_omni_attenuation(float dist, float inv_range, float decay) {
float nd = dist * inv_range;
nd *= nd;
nd *= nd; // nd^4
nd = max(1.0 - nd, 0.0);
nd *= nd; // nd^2
return nd * pow(max(dist, 0.0001), -decay);
}
void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) {
uint item_min_max = cluster_buffer.data[p_offset];
item_min = item_min_max & 0xFFFF;
item_max = item_min_max >> 16;
;
item_from = item_min >> 5;
item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements
}
uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) {
int local_min = clamp(int(z_min) - int(i) * 32, 0, 31);
int mask_width = min(int(z_max) - int(z_min), 32 - local_min);
return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width);
}
float henyey_greenstein(float cos_theta, float g) {
const float k = 0.0795774715459; // 1 / (4 * PI)
return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));
}
#define TEMPORAL_FRAMES 16
const vec3 halton_map[TEMPORAL_FRAMES] = vec3[](
vec3(0.5, 0.33333333, 0.2),
vec3(0.25, 0.66666667, 0.4),
vec3(0.75, 0.11111111, 0.6),
vec3(0.125, 0.44444444, 0.8),
vec3(0.625, 0.77777778, 0.04),
vec3(0.375, 0.22222222, 0.24),
vec3(0.875, 0.55555556, 0.44),
vec3(0.0625, 0.88888889, 0.64),
vec3(0.5625, 0.03703704, 0.84),
vec3(0.3125, 0.37037037, 0.08),
vec3(0.8125, 0.7037037, 0.28),
vec3(0.1875, 0.14814815, 0.48),
vec3(0.6875, 0.48148148, 0.68),
vec3(0.4375, 0.81481481, 0.88),
vec3(0.9375, 0.25925926, 0.12),
vec3(0.03125, 0.59259259, 0.32));
void main() {
vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size);
#ifdef MODE_DENSITY
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
if (any(greaterThanEqual(pos, params.fog_volume_size))) {
return; //do not compute
}
vec3 posf = vec3(pos);
//posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0;
vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels
uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
uvec2 cluster_pos = screen_pos >> params.cluster_shift;
uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
//positions in screen are too spread apart, no hopes for optimizing with subgroups
fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
vec3 view_pos;
view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
view_pos.y = -view_pos.y;
vec4 reprojected_density = vec4(0.0);
float reproject_amount = 0.0;
if (params.use_temporal_reprojection) {
vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz;
//undo transform into prev view
prev_view.y = -prev_view.y;
//z back to unit size
prev_view.z /= -params.fog_frustum_end;
//xy back to unit size
prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z));
prev_view.xy = prev_view.xy * 0.5 + 0.5;
//z back to unspread value
prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread);
if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) {
//reprojectinon fits
reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0);
reproject_amount = params.temporal_blend;
// Since we can reproject, now we must jitter the current view pos.
// This is done here because cells that can't reproject should not jitter.
fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table
screen_pos = uvec2(fog_unit_pos.xy * params.screen_size);
cluster_pos = screen_pos >> params.cluster_shift;
cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32);
//positions in screen are too spread apart, no hopes for optimizing with subgroups
fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread);
view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z));
view_pos.z = -params.fog_frustum_end * fog_unit_pos.z;
view_pos.y = -view_pos.y;
}
}
uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0));
vec3 total_light = vec3(0.0);
float total_density = params.base_density;
uint local_density = imageLoad(density_only_map, pos).x;
total_density += float(int(local_density)) / DENSITY_SCALE;
total_density = max(0.0, total_density);
uint scattering_u = imageLoad(light_only_map, pos).x;
vec3 scattering = vec3(scattering_u >> 21, (scattering_u << 11) >> 21, scattering_u % 1024) / vec3(2047.0, 2047.0, 1023.0);
scattering += params.base_scattering * params.base_density;
uint emission_u = imageLoad(emissive_only_map, pos).x;
vec3 emission = vec3(emission_u >> 21, (emission_u << 11) >> 21, emission_u % 1024) / vec3(511.0, 511.0, 255.0);
emission += params.base_emission * params.base_density;
float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1));
//compute directional lights
if (total_density > 0.001) {
for (uint i = 0; i < params.directional_light_count; i++) {
vec3 shadow_attenuation = vec3(1.0);
if (directional_lights.data[i].shadow_enabled) {
float depth_z = -view_pos.z;
vec4 pssm_coord;
vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb;
vec3 light_dir = directional_lights.data[i].direction;
vec4 v = vec4(view_pos, 1.0);
float z_range;
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
pssm_coord /= pssm_coord.w;
z_range = directional_lights.data[i].shadow_z_range.x;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
pssm_coord /= pssm_coord.w;
z_range = directional_lights.data[i].shadow_z_range.y;
} else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
pssm_coord /= pssm_coord.w;
z_range = directional_lights.data[i].shadow_z_range.z;
} else {
pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
pssm_coord /= pssm_coord.w;
z_range = directional_lights.data[i].shadow_z_range.w;
}
float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade);
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance
shadow_attenuation = mix(shadow_color, vec3(1.0), shadow);
}
total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy * henyey_greenstein(dot(normalize(view_pos), normalize(directional_lights.data[i].direction)), params.phase_g);
}
// Compute light from sky
if (params.ambient_inject > 0.0) {
vec3 isotropic = vec3(0.0);
vec3 anisotropic = vec3(0.0);
if (params.sky_contribution > 0.0) {
float mip_bias = 2.0 + total_density * (MAX_SKY_LOD - 2.0); // Not physically based, but looks nice
vec3 scatter_direction = (params.radiance_inverse_xform * normalize(view_pos)) * sign(params.phase_g);
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
isotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(0.0, 1.0, 0.0, mip_bias)).rgb;
anisotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(scatter_direction, mip_bias)).rgb;
#else
isotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(0.0, 1.0, 0.0), mip_bias).rgb;
anisotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(scatter_direction), mip_bias).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
}
total_light += mix(params.ambient_color, mix(isotropic, anisotropic, abs(params.phase_g)), params.sky_contribution) * params.ambient_inject;
}
//compute lights from cluster
{ //omni lights
uint cluster_omni_offset = cluster_offset;
uint item_min;
uint item_max;
uint item_from;
uint item_to;
cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
for (uint i = item_from; i < item_to; i++) {
uint mask = cluster_buffer.data[cluster_omni_offset + i];
mask &= cluster_get_range_clip_mask(i, item_min, item_max);
#ifdef USE_SUBGROUPS
uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
#else
uint merged_mask = mask;
#endif
while (merged_mask != 0) {
uint bit = findMSB(merged_mask);
merged_mask &= ~(1 << bit);
#ifdef USE_SUBGROUPS
if (((1 << bit) & mask) == 0) { //do not process if not originally here
continue;
}
#endif
uint light_index = 32 * i + bit;
//if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) {
// continue; //not masked
//}
vec3 light_pos = omni_lights.data[light_index].position;
float d = distance(omni_lights.data[light_index].position, view_pos);
float shadow_attenuation = 1.0;
if (d * omni_lights.data[light_index].inv_radius < 1.0) {
float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation);
vec3 light = omni_lights.data[light_index].color;
if (omni_lights.data[light_index].shadow_enabled) {
//has shadow
vec4 uv_rect = omni_lights.data[light_index].atlas_rect;
vec2 flip_offset = omni_lights.data[light_index].direction.xy;
vec3 local_vert = (omni_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz;
float shadow_len = length(local_vert); //need to remember shadow len from here
vec3 shadow_sample = normalize(local_vert);
if (shadow_sample.z >= 0.0) {
uv_rect.xy += flip_offset;
}
shadow_sample.z = 1.0 + abs(shadow_sample.z);
vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - omni_lights.data[light_index].shadow_bias);
pos.z *= omni_lights.data[light_index].inv_radius;
pos.xy = pos.xy * 0.5 + 0.5;
pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r;
shadow_attenuation = exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade);
}
total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g);
}
}
}
}
{ //spot lights
uint cluster_spot_offset = cluster_offset + params.cluster_type_size;
uint item_min;
uint item_max;
uint item_from;
uint item_to;
cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
for (uint i = item_from; i < item_to; i++) {
uint mask = cluster_buffer.data[cluster_spot_offset + i];
mask &= cluster_get_range_clip_mask(i, item_min, item_max);
#ifdef USE_SUBGROUPS
uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask));
#else
uint merged_mask = mask;
#endif
while (merged_mask != 0) {
uint bit = findMSB(merged_mask);
merged_mask &= ~(1 << bit);
#ifdef USE_SUBGROUPS
if (((1 << bit) & mask) == 0) { //do not process if not originally here
continue;
}
#endif
//if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) {
// continue; //not masked
//}
uint light_index = 32 * i + bit;
vec3 light_pos = spot_lights.data[light_index].position;
vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos;
float d = length(light_rel_vec);
float shadow_attenuation = 1.0;
if (d * spot_lights.data[light_index].inv_radius < 1.0) {
float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation);
vec3 spot_dir = spot_lights.data[light_index].direction;
float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle);
float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle));
attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation);
vec3 light = spot_lights.data[light_index].color;
if (spot_lights.data[light_index].shadow_enabled) {
//has shadow
vec4 v = vec4(view_pos, 1.0);
vec4 splane = (spot_lights.data[light_index].shadow_matrix * v);
splane /= splane.w;
float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade);
}
total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g);
}
}
}
}
vec3 world_pos = mat3(params.cam_rotation) * view_pos;
for (uint i = 0; i < params.max_voxel_gi_instances; i++) {
vec3 position = (voxel_gi_instances.data[i].xform * vec4(world_pos, 1.0)).xyz;
//this causes corrupted pixels, i have no idea why..
if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, voxel_gi_instances.data[i].bounds))))) {
position /= voxel_gi_instances.data[i].bounds;
vec4 light = vec4(0.0);
for (uint j = 0; j < voxel_gi_instances.data[i].mipmaps; j++) {
vec4 slight = textureLod(sampler3D(voxel_gi_textures[i], linear_sampler_with_mipmaps), position, float(j));
float a = (1.0 - light.a);
light += a * slight;
}
light.rgb *= voxel_gi_instances.data[i].dynamic_range * params.gi_inject;
total_light += light.rgb;
}
}
//sdfgi
#ifdef ENABLE_SDFGI
{
float blend = -1.0;
vec3 ambient_total = vec3(0.0);
for (uint i = 0; i < sdfgi.max_cascades; i++) {
vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe;
if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) {
continue; //skip cascade
}
vec3 base_pos = floor(cascade_pos);
ivec3 probe_base_pos = ivec3(base_pos);
vec4 ambient_accum = vec4(0.0);
ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i));
tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
for (uint j = 0; j < 8; j++) {
ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
ivec3 probe_posi = probe_base_pos;
probe_posi += offset;
// Compute weight
vec3 probe_pos = vec3(probe_posi);
vec3 probe_to_pos = cascade_pos - probe_pos;
vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
float weight = trilinear.x * trilinear.y * trilinear.z;
// Compute lightprobe occlusion
if (sdfgi.use_occlusion) {
ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
occ_pos.z += float(i);
if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
occ_pos.x += 1.0;
}
occ_pos *= sdfgi.occlusion_renormalize;
float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask);
weight *= max(occlusion, 0.01);
}
// Compute ambient texture position
ivec3 uvw = tex_pos;
uvw.xy += offset.xy;
uvw.x += offset.z * sdfgi.probe_axis_size;
vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb;
ambient_accum.rgb += ambient * weight;
ambient_accum.a += weight;
}
if (ambient_accum.a > 0) {
ambient_accum.rgb /= ambient_accum.a;
}
ambient_total = ambient_accum.rgb;
break;
}
total_light += ambient_total * params.gi_inject;
}
#endif
}
vec4 final_density = vec4(total_light * scattering + emission, total_density);
final_density = mix(final_density, reprojected_density, reproject_amount);
imageStore(density_map, pos, final_density);
imageStore(density_only_map, pos, uvec4(0));
imageStore(light_only_map, pos, uvec4(0));
imageStore(emissive_only_map, pos, uvec4(0));
#endif
#ifdef MODE_FOG
ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0);
if (any(greaterThanEqual(pos, params.fog_volume_size))) {
return; //do not compute
}
vec4 fog_accum = vec4(0.0, 0.0, 0.0, 1.0);
float prev_z = 0.0;
for (int i = 0; i < params.fog_volume_size.z; i++) {
//compute fog position
ivec3 fog_pos = pos + ivec3(0, 0, i);
//get fog value
vec4 fog = imageLoad(density_map, fog_pos);
//get depth at cell pos
float z = get_depth_at_pos(fog_cell_size.z, i);
//get distance from previous pos
float d = abs(prev_z - z);
//compute transmittance using beer's law
float transmittance = exp(-d * fog.a);
fog_accum.rgb += ((fog.rgb - fog.rgb * transmittance) / max(fog.a, 0.00001)) * fog_accum.a;
fog_accum.a *= transmittance;
prev_z = z;
imageStore(fog_map, fog_pos, vec4(fog_accum.rgb, 1.0 - fog_accum.a));
}
#endif
#ifdef MODE_FILTER
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303);
const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1));
ivec3 offset = filter_dir[params.filter_axis];
vec4 accum = vec4(0.0);
for (int i = -3; i <= 3; i++) {
accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3];
}
imageStore(dest_map, pos, accum);
#endif
#ifdef MODE_COPY
ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);
if (any(greaterThanEqual(pos, params.fog_volume_size))) {
return; //do not compute
}
imageStore(dest_map, pos, imageLoad(source_map, pos));
#endif
}

View file

@ -85,6 +85,8 @@ public:
virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0;
virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0;
virtual void instance_set_ignore_culling(RID p_instance, bool p_enabled) = 0;
// don't use these in a game!
virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0;
virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const = 0;
@ -132,7 +134,7 @@ public:
virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
virtual void environment_glow_set_use_high_quality(bool p_enable) = 0;
virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0;
virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) = 0;
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;

View file

@ -540,6 +540,10 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data);
RSG::storage->free(collision->instance);
} break;
case RS::INSTANCE_FOG_VOLUME: {
InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(instance->base_data);
scene_render->free(volume->instance);
} break;
case RS::INSTANCE_VISIBLITY_NOTIFIER: {
//none
} break;
@ -657,6 +661,12 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
RSG::storage->particles_collision_instance_set_active(collision->instance, instance->visible);
instance->base_data = collision;
} break;
case RS::INSTANCE_FOG_VOLUME: {
InstanceFogVolumeData *volume = memnew(InstanceFogVolumeData);
volume->instance = scene_render->fog_volume_instance_create(p_base);
scene_render->fog_volume_instance_set_active(volume->instance, instance->visible);
instance->base_data = volume;
} break;
case RS::INSTANCE_VISIBLITY_NOTIFIER: {
InstanceVisibilityNotifierData *vnd = memnew(InstanceVisibilityNotifierData);
vnd->base = p_base;
@ -930,6 +940,11 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) {
RSG::storage->particles_collision_instance_set_active(collision->instance, p_visible);
}
if (instance->base_type == RS::INSTANCE_FOG_VOLUME) {
InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(instance->base_data);
scene_render->fog_volume_instance_set_active(volume->instance, p_visible);
}
if (instance->base_type == RS::INSTANCE_OCCLUDER) {
if (instance->scenario) {
RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(instance->scenario->self, p_instance, instance->base, instance->transform, p_visible);
@ -999,6 +1014,21 @@ void RendererSceneCull::instance_set_extra_visibility_margin(RID p_instance, rea
_instance_queue_update(instance, true, false);
}
void RendererSceneCull::instance_set_ignore_culling(RID p_instance, bool p_enabled) {
Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
instance->ignore_all_culling = p_enabled;
if (instance->scenario && instance->array_index >= 0) {
InstanceData &idata = instance->scenario->instance_data[instance->array_index];
if (instance->ignore_all_culling) {
idata.flags |= InstanceData::FLAG_IGNORE_ALL_CULLING;
} else {
idata.flags &= ~uint32_t(InstanceData::FLAG_IGNORE_ALL_CULLING);
}
}
}
Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const {
Vector<ObjectID> instances;
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
@ -1491,6 +1521,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
heightfield_particle_colliders_update_list.insert(p_instance);
}
RSG::storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform);
} else if (p_instance->base_type == RS::INSTANCE_FOG_VOLUME) {
InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(p_instance->base_data);
scene_render->fog_volume_instance_set_transform(volume->instance, p_instance->transform);
} else if (p_instance->base_type == RS::INSTANCE_OCCLUDER) {
if (p_instance->scenario) {
RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(p_instance->scenario->self, p_instance->self, p_instance->base, p_instance->transform, p_instance->visible);
@ -1612,6 +1645,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
case RS::INSTANCE_VOXEL_GI: {
idata.instance_data_rid = static_cast<InstanceVoxelGIData *>(p_instance->base_data)->probe_instance.get_id();
} break;
case RS::INSTANCE_FOG_VOLUME: {
idata.instance_data_rid = static_cast<InstanceFogVolumeData *>(p_instance->base_data)->instance.get_id();
} break;
case RS::INSTANCE_VISIBLITY_NOTIFIER: {
idata.visibility_notifier = static_cast<InstanceVisibilityNotifierData *>(p_instance->base_data);
} break;
@ -1642,6 +1678,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
if (p_instance->ignore_occlusion_culling) {
idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING;
}
if (p_instance->ignore_all_culling) {
idata.flags |= InstanceData::FLAG_IGNORE_ALL_CULLING;
}
p_instance->scenario->instance_data.push_back(idata);
p_instance->scenario->instance_aabbs.push_back(InstanceBounds(p_instance->transformed_aabb));
@ -1816,6 +1855,9 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base);
} break;
case RenderingServer::INSTANCE_FOG_VOLUME: {
new_aabb = RSG::storage->fog_volume_get_aabb(p_instance->base);
} break;
case RenderingServer::INSTANCE_VISIBLITY_NOTIFIER: {
new_aabb = RSG::storage->visibility_notifier_get_aabb(p_instance->base);
} break;
@ -2590,7 +2632,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near))
if (!HIDDEN_BY_VISIBILITY_CHECKS) {
if (LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) {
if ((LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) || (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_ALL_CULLING)) {
uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
if (base_type == RS::INSTANCE_LIGHT) {
cull_result.lights.push_back(idata.instance);
@ -2633,6 +2675,8 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
} else if (base_type == RS::INSTANCE_LIGHTMAP) {
cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid));
} else if (base_type == RS::INSTANCE_FOG_VOLUME) {
cull_result.fog_volumes.push_back(RID::from_uint64(idata.instance_data_rid));
} else if (base_type == RS::INSTANCE_VISIBLITY_NOTIFIER) {
InstanceVisibilityNotifierData *vnd = idata.visibility_notifier;
if (!vnd->list_element.in_list()) {
@ -3157,7 +3201,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
}
RENDER_TIMESTAMP("Render Scene ");
scene_render->render_scene(p_render_buffers, p_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data, r_render_info);
scene_render->render_scene(p_render_buffers, p_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, scene_cull_result.fog_volumes, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data, r_render_info);
for (uint32_t i = 0; i < max_shadows_used; i++) {
render_shadow_data[i].instances.clear();
@ -3207,7 +3251,7 @@ void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario,
RendererSceneRender::CameraData camera_data;
camera_data.set_camera(Transform3D(), CameraMatrix(), true, false);
scene_render->render_scene(p_render_buffers, &camera_data, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr);
scene_render->render_scene(p_render_buffers, &camera_data, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr);
#endif
}

View file

@ -269,6 +269,7 @@ public:
FLAG_VISIBILITY_DEPENDENCY_HIDDEN = (1 << 21),
FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN = (1 << 22),
FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY = (1 << 23),
FLAG_IGNORE_ALL_CULLING = (1 << 24),
};
uint32_t flags = 0;
@ -397,6 +398,7 @@ public:
float lod_bias;
bool ignore_occlusion_culling;
bool ignore_all_culling;
Vector<RID> materials;
@ -535,6 +537,7 @@ public:
lightmap_cull_index = 0;
lod_bias = 1.0;
ignore_occlusion_culling = false;
ignore_all_culling = false;
scenario = nullptr;
@ -628,6 +631,11 @@ public:
RID instance;
};
struct InstanceFogVolumeData : public InstanceBaseData {
RID instance;
bool is_global;
};
struct InstanceVisibilityNotifierData : public InstanceBaseData {
bool just_visible = false;
uint64_t visible_in_frame = 0;
@ -792,6 +800,7 @@ public:
PagedArray<RID> decals;
PagedArray<RID> voxel_gi_instances;
PagedArray<RID> mesh_instances;
PagedArray<RID> fog_volumes;
struct DirectionalShadow {
PagedArray<RendererSceneRender::GeometryInstance *> cascade_geometry_instances[RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES];
@ -809,6 +818,7 @@ public:
decals.clear();
voxel_gi_instances.clear();
mesh_instances.clear();
fog_volumes.clear();
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
directional_shadows[i].cascade_geometry_instances[j].clear();
@ -833,6 +843,7 @@ public:
decals.reset();
voxel_gi_instances.reset();
mesh_instances.reset();
fog_volumes.reset();
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
directional_shadows[i].cascade_geometry_instances[j].reset();
@ -857,6 +868,7 @@ public:
decals.merge_unordered(p_cull_result.decals);
voxel_gi_instances.merge_unordered(p_cull_result.voxel_gi_instances);
mesh_instances.merge_unordered(p_cull_result.mesh_instances);
fog_volumes.merge_unordered(p_cull_result.fog_volumes);
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
@ -882,6 +894,7 @@ public:
decals.set_page_pool(p_rid_pool);
voxel_gi_instances.set_page_pool(p_rid_pool);
mesh_instances.set_page_pool(p_rid_pool);
fog_volumes.set_page_pool(p_rid_pool);
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
directional_shadows[i].cascade_geometry_instances[j].set_page_pool(p_geometry_instance_pool);
@ -934,6 +947,8 @@ public:
virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance);
virtual void instance_set_ignore_culling(RID p_instance, bool p_enabled);
bool _update_instance_visibility_depth(Instance *p_instance);
void _update_instance_visibility_dependencies(Instance *p_instance);
@ -1101,7 +1116,7 @@ public:
PASS7(environment_set_adjustment, RID, bool, float, float, float, bool, RID)
PASS9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
PASS10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float)
PASS13(environment_set_volumetric_fog, RID, bool, float, const Color &, const Color &, float, float, float, float, float, bool, float, float)
PASS2(environment_set_volumetric_fog_volume_size, int, int)
PASS1(environment_set_volumetric_fog_filter_active, bool)

View file

@ -126,7 +126,7 @@ public:
virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
virtual void environment_glow_set_use_high_quality(bool p_enable) = 0;
virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0;
virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) = 0;
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
@ -176,6 +176,12 @@ public:
return true;
}
virtual RID fog_volume_instance_create(RID p_fog_volume) = 0;
virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) = 0;
virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) = 0;
virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const = 0;
virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const = 0;
virtual RID reflection_atlas_create() = 0;
virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0;
virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 0;
@ -240,7 +246,7 @@ public:
void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const CameraMatrix *p_projections, bool p_is_ortogonal, bool p_vaspect);
};
virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) = 0;
virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) = 0;
virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0;

View file

@ -535,6 +535,19 @@ public:
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0;
virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0;
/* FOG VOLUMES */
virtual RID fog_volume_allocate() = 0;
virtual void fog_volume_initialize(RID p_rid) = 0;
virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) = 0;
virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) = 0;
virtual void fog_volume_set_material(RID p_fog_volume, RID p_material) = 0;
virtual AABB fog_volume_get_aabb(RID p_fog_volume) const = 0;
virtual RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const = 0;
/* VISIBILITY NOTIFIER */
virtual RID visibility_notifier_allocate() = 0;
virtual void visibility_notifier_initialize(RID p_notifier) = 0;
virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) = 0;

View file

@ -487,6 +487,14 @@ public:
FUNC1(particles_collision_height_field_update, RID)
FUNC2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution)
/* FOG VOLUME */
FUNCRIDSPLIT(fog_volume)
FUNC2(fog_volume_set_shape, RID, FogVolumeShape)
FUNC2(fog_volume_set_extents, RID, const Vector3 &)
FUNC2(fog_volume_set_material, RID, RID)
/* VISIBILITY_NOTIFIER */
FUNCRIDSPLIT(visibility_notifier)
@ -629,7 +637,7 @@ public:
FUNC7(environment_set_adjustment, RID, bool, float, float, float, bool, RID)
FUNC9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
FUNC10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float)
FUNC13(environment_set_volumetric_fog, RID, bool, float, const Color &, const Color &, float, float, float, float, float, bool, float, float)
FUNC2(environment_set_volumetric_fog_volume_size, int, int)
FUNC1(environment_set_volumetric_fog_filter_active, bool)
@ -693,6 +701,8 @@ public:
FUNC2(instance_set_extra_visibility_margin, RID, real_t)
FUNC2(instance_set_visibility_parent, RID, RID)
FUNC2(instance_set_ignore_culling, RID, bool)
// don't use these in a game!
FUNC2RC(Vector<ObjectID>, instances_cull_aabb, const AABB &, RID)
FUNC3RC(Vector<ObjectID>, instances_cull_ray, const Vector3 &, const Vector3 &, RID)

View file

@ -7645,7 +7645,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
bool uniform = tk.type == TK_UNIFORM;
if (!uniform) {
if (shader_type_identifier == "particles" || shader_type_identifier == "sky") {
if (shader_type_identifier == "particles" || shader_type_identifier == "sky" || shader_type_identifier == "fog") {
_set_error(vformat("Varyings cannot be used in '%s' shaders!", shader_type_identifier));
return ERR_PARSE_ERROR;
}

View file

@ -443,10 +443,29 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass");
shader_modes[RS::SHADER_SKY].modes.push_back("disable_fog");
/************ FOG **************************/
shader_modes[RS::SHADER_FOG].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_FOG].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_FOG].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_FOG].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["WORLD_POSITION"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["OBJECT_POSITION"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["UVW"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["EXTENTS"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["SDF"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["ALBEDO"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["DENSITY"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_FOG].functions["fog"].main_function = true;
shader_types_list.push_back("spatial");
shader_types_list.push_back("canvas_item");
shader_types_list.push_back("particles");
shader_types_list.push_back("sky");
shader_types_list.push_back("fog");
for (int i = 0; i < shader_types_list.size(); i++) {
shader_types.insert(shader_types_list[i]);

View file

@ -1723,6 +1723,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(SHADER_CANVAS_ITEM);
BIND_ENUM_CONSTANT(SHADER_PARTICLES);
BIND_ENUM_CONSTANT(SHADER_SKY);
BIND_ENUM_CONSTANT(SHADER_FOG);
BIND_ENUM_CONSTANT(SHADER_MAX);
/* MATERIAL */
@ -2126,6 +2127,17 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_8192);
BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX);
/* FOG VOLUMES */
ClassDB::bind_method(D_METHOD("fog_volume_create"), &RenderingServer::fog_volume_create);
ClassDB::bind_method(D_METHOD("fog_volume_set_shape", "fog_volume", "shape"), &RenderingServer::fog_volume_set_shape);
ClassDB::bind_method(D_METHOD("fog_volume_set_extents", "fog_volume", "extents"), &RenderingServer::fog_volume_set_extents);
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_BOX);
BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_WORLD);
/* VISIBILITY NOTIFIER */
ClassDB::bind_method(D_METHOD("visibility_notifier_create"), &RenderingServer::visibility_notifier_create);
@ -2301,7 +2313,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "power", "detail", "horizon", "sharpness", "light_affect", "ao_channel_affect"), &RenderingServer::environment_set_ssao);
ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective"), &RenderingServer::environment_set_fog);
ClassDB::bind_method(D_METHOD("environment_set_sdfgi", "env", "enable", "cascades", "min_cell_size", "y_scale", "use_occlusion", "bounce_feedback", "read_sky", "energy", "normal_bias", "probe_bias"), &RenderingServer::environment_set_sdfgi);
ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog", "env", "enable", "density", "light", "light_energy", "length", "p_detail_spread", "gi_inject", "temporal_reprojection", "temporal_reprojection_amount"), &RenderingServer::environment_set_volumetric_fog);
ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog", "env", "enable", "density", "albedo", "emission", "emission_energy", "anisotropy", "length", "p_detail_spread", "gi_inject", "temporal_reprojection", "temporal_reprojection_amount", "ambient_inject"), &RenderingServer::environment_set_volumetric_fog);
ClassDB::bind_method(D_METHOD("environment_glow_set_use_bicubic_upscale", "enable"), &RenderingServer::environment_glow_set_use_bicubic_upscale);
ClassDB::bind_method(D_METHOD("environment_glow_set_use_high_quality", "enable"), &RenderingServer::environment_glow_set_use_high_quality);
@ -2440,6 +2452,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("instance_attach_skeleton", "instance", "skeleton"), &RenderingServer::instance_attach_skeleton);
ClassDB::bind_method(D_METHOD("instance_set_extra_visibility_margin", "instance", "margin"), &RenderingServer::instance_set_extra_visibility_margin);
ClassDB::bind_method(D_METHOD("instance_set_visibility_parent", "instance", "parent"), &RenderingServer::instance_set_visibility_parent);
ClassDB::bind_method(D_METHOD("instance_set_ignore_culling", "instance", "enabled"), &RenderingServer::instance_set_ignore_culling);
ClassDB::bind_method(D_METHOD("instance_geometry_set_flag", "instance", "flag", "enabled"), &RenderingServer::instance_geometry_set_flag);
ClassDB::bind_method(D_METHOD("instance_geometry_set_cast_shadows_setting", "instance", "shadow_casting_setting"), &RenderingServer::instance_geometry_set_cast_shadows_setting);
@ -2469,6 +2482,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP);
BIND_ENUM_CONSTANT(INSTANCE_OCCLUDER);
BIND_ENUM_CONSTANT(INSTANCE_VISIBLITY_NOTIFIER);
BIND_ENUM_CONSTANT(INSTANCE_FOG_VOLUME);
BIND_ENUM_CONSTANT(INSTANCE_MAX);
BIND_ENUM_CONSTANT(INSTANCE_GEOMETRY_MASK);
@ -2836,7 +2850,7 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug.release", true);
GLOBAL_DEF("rendering/reflections/sky_reflections/roughness_layers", 8);
GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections", true);
GLOBAL_DEF_RST("rendering/reflections/sky_reflections/texture_array_reflections", true);
GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false);
GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples", 1024);
GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples.mobile", 128);
@ -2927,7 +2941,7 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/environment/volumetric_fog/volume_size", 64);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/volume_size", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_size", PROPERTY_HINT_RANGE, "16,512,1"));
GLOBAL_DEF("rendering/environment/volumetric_fog/volume_depth", 128);
GLOBAL_DEF("rendering/environment/volumetric_fog/volume_depth", 64);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/volume_depth", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_depth", PROPERTY_HINT_RANGE, "16,512,1"));
GLOBAL_DEF("rendering/environment/volumetric_fog/use_filter", 1);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/use_filter", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/use_filter", PROPERTY_HINT_ENUM, "No (Faster),Yes (Higher Quality)"));

View file

@ -161,6 +161,7 @@ public:
SHADER_CANVAS_ITEM,
SHADER_PARTICLES,
SHADER_SKY,
SHADER_FOG,
SHADER_MAX
};
@ -709,6 +710,20 @@ public:
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field
/* FOG VOLUME API */
virtual RID fog_volume_create() = 0;
enum FogVolumeShape {
FOG_VOLUME_SHAPE_ELLIPSOID,
FOG_VOLUME_SHAPE_BOX,
FOG_VOLUME_SHAPE_WORLD,
};
virtual void fog_volume_set_shape(RID p_fog_volume, FogVolumeShape p_shape) = 0;
virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) = 0;
virtual void fog_volume_set_material(RID p_fog_volume, RID p_material) = 0;
/* VISIBILITY NOTIFIER API */
virtual RID visibility_notifier_create() = 0;
@ -1053,7 +1068,7 @@ public:
virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0;
virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0;
virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) = 0;
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
@ -1118,6 +1133,7 @@ public:
INSTANCE_LIGHTMAP,
INSTANCE_OCCLUDER,
INSTANCE_VISIBLITY_NOTIFIER,
INSTANCE_FOG_VOLUME,
INSTANCE_MAX,
INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_PARTICLES)
@ -1143,6 +1159,8 @@ public:
virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0;
virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0;
virtual void instance_set_ignore_culling(RID p_instance, bool p_enabled) = 0;
// don't use these in a game!
virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0;
virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const = 0;
@ -1542,6 +1560,7 @@ VARIANT_ENUM_CAST(RenderingServer::ParticlesDrawOrder);
VARIANT_ENUM_CAST(RenderingServer::ParticlesEmitFlags);
VARIANT_ENUM_CAST(RenderingServer::ParticlesCollisionType);
VARIANT_ENUM_CAST(RenderingServer::ParticlesCollisionHeightfieldResolution);
VARIANT_ENUM_CAST(RenderingServer::FogVolumeShape);
VARIANT_ENUM_CAST(RenderingServer::ViewportUpdateMode);
VARIANT_ENUM_CAST(RenderingServer::ViewportClearMode);
VARIANT_ENUM_CAST(RenderingServer::ViewportMSAA);