diff options
Diffstat (limited to 'servers/rendering/renderer_rd')
15 files changed, 377 insertions, 157 deletions
| diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 6c28cfd134..fe3863fec7 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -332,7 +332,7 @@ void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer  	RD::get_singleton()->draw_list_draw(draw_list, true);  } -void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary) { +void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview) {  	memset(©_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant));  	if (p_flip_y) { @@ -348,10 +348,18 @@ void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer,  		copy_to_fb.push_constant.srgb = true;  	} +	CopyToFBMode mode; +	if (p_multiview) { +		mode = p_secondary.is_valid() ? COPY_TO_FB_MULTIVIEW_WITH_DEPTH : COPY_TO_FB_MULTIVIEW; +	} else { +		mode = p_secondary.is_valid() ? COPY_TO_FB_COPY2 : COPY_TO_FB_COPY; +	} +  	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect); -	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[p_secondary.is_valid() ? COPY_TO_FB_COPY2 : COPY_TO_FB_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); +	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));  	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);  	if (p_secondary.is_valid()) { +		// TODO may need to do this differently when reading from depth buffer for multiview  		RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_secondary), 1);  	}  	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); @@ -638,13 +646,13 @@ void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, R  		ssr.push_constant.metallic_mask[3] = CLAMP(p_metallic_mask.a * 255.0, 0, 255);  		store_camera(p_camera, ssr.push_constant.projection); -		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[(p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL]); +		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[(p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL]);  		RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr.push_constant, sizeof(ScreenSpaceReflectionPushConstant));  		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output_blur, p_scale_depth), 0); -		if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) { +		if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {  			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output, p_blur_radius), 1);  		} else {  			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_output), 1); @@ -655,7 +663,7 @@ void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, R  		RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);  	} -	if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) { +	if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {  		//blur  		RD::get_singleton()->compute_list_add_barrier(compute_list); @@ -667,10 +675,10 @@ void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, R  		ssr_filter.push_constant.proj_info[2] = (1.0f - p_camera.matrix[0][2]) / p_camera.matrix[0][0];  		ssr_filter.push_constant.proj_info[3] = (1.0f + p_camera.matrix[1][2]) / p_camera.matrix[1][1];  		ssr_filter.push_constant.vertical = 0; -		if (p_roughness_quality == RS::ENV_SSR_ROUGNESS_QUALITY_LOW) { +		if (p_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_LOW) {  			ssr_filter.push_constant.steps = p_max_steps / 3;  			ssr_filter.push_constant.increment = 3; -		} else if (p_roughness_quality == RS::ENV_SSR_ROUGNESS_QUALITY_MEDIUM) { +		} else if (p_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_MEDIUM) {  			ssr_filter.push_constant.steps = p_max_steps / 2;  			ssr_filter.push_constant.increment = 2;  		} else { @@ -2032,7 +2040,7 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, u  	memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));  	roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id; -	roughness.push_constant.roughness = p_roughness; +	roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in.  	roughness.push_constant.sample_count = p_sample_count;  	roughness.push_constant.use_direct_write = p_roughness == 0.0;  	roughness.push_constant.face_size = p_size; @@ -2060,7 +2068,7 @@ void EffectsRD::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_fra  	memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));  	roughness.push_constant.face_id = p_face_id; -	roughness.push_constant.roughness = p_roughness; +	roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in.  	roughness.push_constant.sample_count = p_sample_count;  	roughness.push_constant.use_direct_write = p_roughness == 0.0;  	roughness.push_constant.face_size = p_size; @@ -2367,15 +2375,26 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {  		copy_modes.push_back("\n");  		copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n");  		copy_modes.push_back("\n#define MODE_TWO_SOURCES\n"); +		copy_modes.push_back("\n#define MULTIVIEW\n"); +		copy_modes.push_back("\n#define MULTIVIEW\n#define MODE_TWO_SOURCES\n");  		copy_to_fb.shader.initialize(copy_modes); +		if (!RendererCompositorRD::singleton->is_xr_enabled()) { +			copy_to_fb.shader.set_variant_enabled(COPY_TO_FB_MULTIVIEW, false); +			copy_to_fb.shader.set_variant_enabled(COPY_TO_FB_MULTIVIEW_WITH_DEPTH, false); +		} +  		copy_to_fb.shader_version = copy_to_fb.shader.version_create();  		//use additive  		for (int i = 0; i < COPY_TO_FB_MAX; i++) { -			copy_to_fb.pipelines[i].setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); +			if (copy_to_fb.shader.is_variant_enabled(i)) { +				copy_to_fb.pipelines[i].setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); +			} else { +				copy_to_fb.pipelines[i].clear(); +			}  		}  	} diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index f5e5b1ace7..eca5e09800 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -203,6 +203,9 @@ private:  		COPY_TO_FB_COPY,  		COPY_TO_FB_COPY_PANORAMA_TO_DP,  		COPY_TO_FB_COPY2, + +		COPY_TO_FB_MULTIVIEW, +		COPY_TO_FB_MULTIVIEW_WITH_DEPTH,  		COPY_TO_FB_MAX,  	}; @@ -893,7 +896,7 @@ public:  	bool get_prefer_raster_effects();  	void fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness); -	void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID()); +	void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false);  	void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false);  	void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);  	void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 7987a98b0e..24be451e78 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -557,7 +557,7 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin  		actions.renames["RIM"] = "rim";  		actions.renames["RIM_TINT"] = "rim_tint";  		actions.renames["CLEARCOAT"] = "clearcoat"; -		actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; +		actions.renames["CLEARCOAT_ROUGHNESS"] = "clearcoat_roughness";  		actions.renames["ANISOTROPY"] = "anisotropy";  		actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";  		actions.renames["SSS_STRENGTH"] = "sss_strength"; @@ -607,7 +607,7 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin  		actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";  		actions.usage_defines["RIM_TINT"] = "@RIM";  		actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n"; -		actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; +		actions.usage_defines["CLEARCOAT_ROUGHNESS"] = "@CLEARCOAT";  		actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";  		actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";  		actions.usage_defines["AO"] = "#define AO_USED\n"; @@ -663,20 +663,12 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin  		actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; -		bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); - -		if (!force_blinn) { -			actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; -		} else { -			actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; -		} +		actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";  		actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; // linear filter with mipmaps  		actions.custom_samplers["DEPTH_TEXTURE"] = "material_samplers[3]";  		actions.custom_samplers["NORMAL_ROUGHNESS_TEXTURE"] = "material_samplers[1]"; // linear filter -		actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; -		actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";  		actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";  		actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";  		actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 0b99948063..34b2fa9440 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -545,7 +545,7 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p  		actions.renames["RIM"] = "rim";  		actions.renames["RIM_TINT"] = "rim_tint";  		actions.renames["CLEARCOAT"] = "clearcoat"; -		actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; +		actions.renames["CLEARCOAT_ROUGHNESS"] = "clearcoat_roughness";  		actions.renames["ANISOTROPY"] = "anisotropy";  		actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";  		actions.renames["SSS_STRENGTH"] = "sss_strength"; @@ -594,7 +594,7 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p  		actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";  		actions.usage_defines["RIM_TINT"] = "@RIM";  		actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n"; -		actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; +		actions.usage_defines["CLEARCOAT_ROUGHNESS"] = "@CLEARCOAT";  		actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";  		actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";  		actions.usage_defines["AO"] = "#define AO_USED\n"; @@ -649,15 +649,8 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p  		actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; -		bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx"); -		if (!force_blinn) { -			actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; -		} else { -			actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; -		} +		actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; -		actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; -		actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";  		actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";  		actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";  		actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 948340f469..8814822cda 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1980,7 +1980,7 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb  		rb->ssr.normal_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView());  	} -	if (ssr_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) { +	if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) {  		RD::TextureFormat tf;  		tf.format = RD::DATA_FORMAT_R8_UNORM;  		tf.width = rb->internal_width / 2; @@ -3440,8 +3440,22 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const  					continue;  				} +				const real_t distance = camera_plane.distance_to(li->transform.origin); + +				if (storage->light_is_distance_fade_enabled(li->light)) { +					const float fade_begin = storage->light_get_distance_fade_begin(li->light); +					const float fade_length = storage->light_get_distance_fade_length(li->light); + +					if (distance > fade_begin) { +						if (distance > fade_begin + fade_length) { +							// Out of range, don't draw this light to improve performance. +							continue; +						} +					} +				} +  				cluster.omni_light_sort[cluster.omni_light_count].instance = li; -				cluster.omni_light_sort[cluster.omni_light_count].depth = camera_plane.distance_to(li->transform.origin); +				cluster.omni_light_sort[cluster.omni_light_count].depth = distance;  				cluster.omni_light_count++;  			} break;  			case RS::LIGHT_SPOT: { @@ -3449,8 +3463,22 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const  					continue;  				} +				const real_t distance = camera_plane.distance_to(li->transform.origin); + +				if (storage->light_is_distance_fade_enabled(li->light)) { +					const float fade_begin = storage->light_get_distance_fade_begin(li->light); +					const float fade_length = storage->light_get_distance_fade_length(li->light); + +					if (distance > fade_begin) { +						if (distance > fade_begin + fade_length) { +							// Out of range, don't draw this light to improve performance. +							continue; +						} +					} +				} +  				cluster.spot_light_sort[cluster.spot_light_count].instance = li; -				cluster.spot_light_sort[cluster.spot_light_count].depth = camera_plane.distance_to(li->transform.origin); +				cluster.spot_light_sort[cluster.spot_light_count].depth = distance;  				cluster.spot_light_count++;  			} break;  		} @@ -3494,7 +3522,24 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const  		light_data.attenuation = storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION); -		float energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI; +		// Reuse fade begin, fade length and distance for shadow LOD determination later. +		float fade_begin = 0.0; +		float fade_length = 0.0; +		real_t distance = 0.0; + +		float fade = 1.0; +		if (storage->light_is_distance_fade_enabled(li->light)) { +			fade_begin = storage->light_get_distance_fade_begin(li->light); +			fade_length = storage->light_get_distance_fade_length(li->light); +			distance = camera_plane.distance_to(li->transform.origin); + +			if (distance > fade_begin) { +				// Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. +				fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length); +			} +		} + +		float energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI * fade;  		light_data.color[0] = linear_col.r * energy;  		light_data.color[1] = linear_col.g * energy; @@ -3555,7 +3600,17 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const  			light_data.projector_rect[3] = 0;  		} -		if (shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { +		const bool needs_shadow = shadow_atlas && shadow_atlas->shadow_owners.has(li->self); + +		bool in_shadow_range = true; +		if (needs_shadow && storage->light_is_distance_fade_enabled(li->light)) { +			if (distance > storage->light_get_distance_fade_shadow(li->light)) { +				// Out of range, don't draw shadows to improve performance. +				in_shadow_range = false; +			} +		} + +		if (needs_shadow && in_shadow_range) {  			// fill in the shadow information  			light_data.shadow_enabled = true; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 09c828ba37..47bc0af1db 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -428,7 +428,7 @@ private:  	bool glow_bicubic_upscale = false;  	bool glow_high_quality = false; -	RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW; +	RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;  	mutable RID_Owner<RendererSceneEnvironmentRD, true> environment_owner; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index e3829eb5ed..35aa0f1f31 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -5712,6 +5712,21 @@ void RendererStorageRD::update_particles() {  				total_amount *= particles->trail_bind_poses.size();  			} +			// Affect 2D only. +			if (particles->use_local_coords) { +				// In local mode, particle positions are calculated locally (relative to the node position) +				// and they're also drawn locally. +				// It works as expected, so we just pass an identity transform. +				store_transform(Transform3D(), copy_push_constant.inv_emission_transform); +			} else { +				// In global mode, particle positions are calculated globally (relative to the canvas origin) +				// but they're drawn locally. +				// So, we need to pass the inverse of the emission transform to bring the +				// particles to local coordinates before drawing. +				Transform3D inv = particles->emission_transform.affine_inverse(); +				store_transform(inv, copy_push_constant.inv_emission_transform); +			} +  			copy_push_constant.total_particles = total_amount;  			copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0;  			copy_push_constant.align_mode = particles->transform_align; @@ -6585,6 +6600,16 @@ void RendererStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) {  	light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT);  } +void RendererStorageRD::light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) { +	Light *light = light_owner.get_or_null(p_light); +	ERR_FAIL_COND(!light); + +	light->distance_fade = p_enabled; +	light->distance_fade_begin = p_begin; +	light->distance_fade_shadow = p_shadow; +	light->distance_fade_length = p_length; +} +  void RendererStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {  	Light *light = light_owner.get_or_null(p_light);  	ERR_FAIL_COND(!light); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index ee4d18210a..cb35c2bf65 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -852,6 +852,8 @@ private:  			uint32_t lifetime_split;  			uint32_t lifetime_reverse;  			uint32_t copy_mode_2d; + +			float inv_emission_transform[16];  		};  		enum { @@ -1031,6 +1033,10 @@ private:  		RS::LightBakeMode bake_mode = RS::LIGHT_BAKE_DYNAMIC;  		uint32_t max_sdfgi_cascade = 2;  		uint32_t cull_mask = 0xFFFFFFFF; +		bool distance_fade = false; +		real_t distance_fade_begin = 40.0; +		real_t distance_fade_shadow = 50.0; +		real_t distance_fade_length = 10.0;  		RS::LightOmniShadowMode omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;  		RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;  		bool directional_blend_splits = false; @@ -1839,6 +1845,7 @@ public:  	void light_set_projector(RID p_light, RID p_texture);  	void light_set_negative(RID p_light, bool p_enable);  	void light_set_cull_mask(RID p_light, uint32_t p_mask); +	void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length);  	void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled);  	void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode);  	void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade); @@ -1897,6 +1904,26 @@ public:  		return light->cull_mask;  	} +	_FORCE_INLINE_ bool light_is_distance_fade_enabled(RID p_light) { +		const Light *light = light_owner.get_or_null(p_light); +		return light->distance_fade; +	} + +	_FORCE_INLINE_ float light_get_distance_fade_begin(RID p_light) { +		const Light *light = light_owner.get_or_null(p_light); +		return light->distance_fade_begin; +	} + +	_FORCE_INLINE_ float light_get_distance_fade_shadow(RID p_light) { +		const Light *light = light_owner.get_or_null(p_light); +		return light->distance_fade_shadow; +	} + +	_FORCE_INLINE_ float light_get_distance_fade_length(RID p_light) { +		const Light *light = light_owner.get_or_null(p_light); +		return light->distance_fade_length; +	} +  	_FORCE_INLINE_ bool light_has_shadow(RID p_light) const {  		const Light *light = light_owner.get_or_null(p_light);  		ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL); diff --git a/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl index 2f1f9c4765..9787c9879d 100644 --- a/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl +++ b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl @@ -4,7 +4,20 @@  #VERSION_DEFINES +#ifdef MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +#endif //MULTIVIEW + +#ifdef MULTIVIEW +layout(location = 0) out vec3 uv_interp; +#else  layout(location = 0) out vec2 uv_interp; +#endif  layout(push_constant, std430) uniform Params {  	vec4 section; @@ -19,9 +32,11 @@ params;  void main() {  	vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); -	uv_interp = base_arr[gl_VertexIndex]; - -	vec2 vpos = uv_interp; +	uv_interp.xy = base_arr[gl_VertexIndex]; +#ifdef MULTIVIEW +	uv_interp.z = ViewIndex; +#endif +	vec2 vpos = uv_interp.xy;  	if (params.use_section) {  		vpos = params.section.xy + vpos * params.section.zw;  	} @@ -39,6 +54,15 @@ void main() {  #VERSION_DEFINES +#ifdef MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +#endif //MULTIVIEW +  layout(push_constant, std430) uniform Params {  	vec4 section;  	vec2 pixel_size; @@ -52,12 +76,25 @@ layout(push_constant, std430) uniform Params {  }  params; +#ifdef MULTIVIEW +layout(location = 0) in vec3 uv_interp; +#else  layout(location = 0) in vec2 uv_interp; +#endif +#ifdef MULTIVIEW +layout(set = 0, binding = 0) uniform sampler2DArray source_color; +#ifdef MODE_TWO_SOURCES +layout(set = 1, binding = 0) uniform sampler2DArray source_depth; +layout(location = 1) out float depth; +#endif /* MODE_TWO_SOURCES */ +#else  layout(set = 0, binding = 0) uniform sampler2D source_color;  #ifdef MODE_TWO_SOURCES  layout(set = 1, binding = 0) uniform sampler2D source_color2; -#endif +#endif /* MODE_TWO_SOURCES */ +#endif /* MULTIVIEW */ +  layout(location = 0) out vec4 frag_color;  vec3 linear_to_srgb(vec3 color) { @@ -68,9 +105,14 @@ vec3 linear_to_srgb(vec3 color) {  }  void main() { +#ifdef MULTIVIEW +	vec3 uv = uv_interp; +#else  	vec2 uv = uv_interp; +#endif  #ifdef MODE_PANORAMA_TO_DP +	// Note, multiview and panorama should not be mixed at this time  	//obtain normal from dual paraboloid uv  #define M_PI 3.14159265359 @@ -98,10 +140,20 @@ void main() {  		uv = 1.0 - uv;  	}  #endif + +#ifdef MULTIVIEW +	vec4 color = textureLod(source_color, uv, 0.0); +#ifdef MODE_TWO_SOURCES +	// In multiview our 2nd input will be our depth map +	depth = textureLod(source_depth, uv, 0.0).r; +#endif /* MODE_TWO_SOURCES */ + +#else  	vec4 color = textureLod(source_color, uv, 0.0);  #ifdef MODE_TWO_SOURCES  	color += textureLod(source_color2, uv, 0.0); -#endif +#endif /* MODE_TWO_SOURCES */ +#endif /* MULTIVIEW */  	if (params.force_luminance) {  		color.rgb = vec3(max(max(color.r, color.g), color.b));  	} diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl index b991880cd9..afbd5a9caa 100644 --- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl +++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl @@ -61,6 +61,8 @@ layout(push_constant, std430) uniform Params {  	uint lifetime_split;  	bool lifetime_reverse;  	bool copy_mode_2d; + +	mat4 inv_emission_transform;  }  params; @@ -199,6 +201,12 @@ void main() {  			txform = txform * trail_bind_poses.data[part_ofs];  		} +		if (params.copy_mode_2d) { +			// In global mode, bring 2D particles to local coordinates +			// as they will be drawn with the node position as origin. +			txform = params.inv_emission_transform * txform; +		} +  		txform = transpose(txform);  	} else {  		txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index 5d65b00bee..a8648fc96a 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -478,8 +478,8 @@ layout(location = 0) out vec4 frag_color;  #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) -/* Make a default specular mode SPECULAR_SCHLICK_GGX. */ -#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON) +// Default to SPECULAR_SCHLICK_GGX. +#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON)  #define SPECULAR_SCHLICK_GGX  #endif @@ -589,7 +589,7 @@ void main() {  	float rim = 0.0;  	float rim_tint = 0.0;  	float clearcoat = 0.0; -	float clearcoat_gloss = 0.0; +	float clearcoat_roughness = 0.0;  	float anisotropy = 0.0;  	vec2 anisotropy_flow = vec2(1.0, 0.0);  	vec4 fog = vec4(0.0); @@ -912,7 +912,17 @@ void main() {  #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)  	if (scene_data.use_reflection_cubemap) { +#ifdef LIGHT_ANISOTROPY_USED +		// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy +		vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; +		vec3 anisotropic_tangent = cross(anisotropic_direction, view); +		vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction); +		vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); +		vec3 ref_vec = reflect(-view, bent_normal); +#else  		vec3 ref_vec = reflect(-view, normal); +#endif +  		float horizon = min(1.0 + dot(ref_vec, normal), 1.0);  		ref_vec = scene_data.radiance_inverse_xform * ref_vec;  #ifdef USE_RADIANCE_CUBEMAP_ARRAY @@ -954,6 +964,36 @@ void main() {  #if defined(CUSTOM_IRRADIANCE_USED)  	ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a);  #endif + +#ifdef LIGHT_CLEARCOAT_USED + +	if (scene_data.use_reflection_cubemap) { +		vec3 n = normalize(normal_interp); // We want to use geometric normal, not normal_map +		float NoV = max(dot(n, view), 0.0001); +		vec3 ref_vec = reflect(-view, n); +		// The clear coat layer assumes an IOR of 1.5 (4% reflectance) +		float Fc = clearcoat * (0.04 + 0.96 * SchlickFresnel(NoV)); +		float attenuation = 1.0 - Fc; +		ambient_light *= attenuation; +		specular_light *= attenuation; + +		float horizon = min(1.0 + dot(ref_vec, normal), 1.0); +		ref_vec = scene_data.radiance_inverse_xform * ref_vec; +		float roughness_lod = mix(0.001, 0.1, clearcoat_roughness) * MAX_ROUGHNESS_LOD; +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + +		float lod, blend; +		blend = modf(roughness_lod, lod); +		vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb; +		clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend); + +#else +		vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness_lod).rgb; + +#endif //USE_RADIANCE_CUBEMAP_ARRAY +		specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a; +	} +#endif  #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)  	//radiance @@ -1202,8 +1242,16 @@ void main() {  				if (!bool(reflections.data[reflection_index].mask & instances.data[instance_index].layer_mask)) {  					continue; //not masked  				} - -				reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); +#ifdef LIGHT_ANISOTROPY_USED +				// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy +				vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; +				vec3 anisotropic_tangent = cross(anisotropic_direction, view); +				vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction); +				vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); +#else +				vec3 bent_normal = normal; +#endif +				reflection_process(reflection_index, vertex, bent_normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum);  			}  		} @@ -1555,10 +1603,11 @@ void main() {  					rim, rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -					clearcoat, clearcoat_gloss, +					clearcoat, clearcoat_roughness, normalize(normal_interp),  #endif  #ifdef LIGHT_ANISOTROPY_USED -					binormal, tangent, anisotropy, +					binormal, +					tangent, anisotropy,  #endif  					diffuse_light,  					specular_light); @@ -1626,7 +1675,7 @@ void main() {  						rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -						clearcoat, clearcoat_gloss, +						clearcoat, clearcoat_roughness, normalize(normal_interp),  #endif  #ifdef LIGHT_ANISOTROPY_USED  						tangent, binormal, anisotropy, @@ -1698,10 +1747,11 @@ void main() {  						rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -						clearcoat, clearcoat_gloss, +						clearcoat, clearcoat_roughness, normalize(normal_interp),  #endif  #ifdef LIGHT_ANISOTROPY_USED -						tangent, binormal, anisotropy, +						tangent, +						binormal, anisotropy,  #endif  						diffuse_light, specular_light);  			} @@ -1904,7 +1954,7 @@ void main() {  	frag_color = vec4(albedo, alpha);  #else  	frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha); -	//frag_color = vec4(1.0); +//frag_color = vec4(1.0);  #endif //USE_NO_SHADING  	// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl index 084e2a0673..3b110aded2 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl @@ -15,7 +15,7 @@  #include "cluster_data_inc.glsl"  #include "decal_data_inc.glsl" -#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)  #ifndef NORMAL_USED  #define NORMAL_USED  #endif diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index 16f77fb91a..1c9b08b6d3 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -1,55 +1,29 @@  // Functions related to lighting -// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. -// We're dividing this factor off because the overall term we'll end up looks like -// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): -// -//   F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) -// -// We're basically regouping this as -// -//   F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] -// -// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. -// -// The contents of the D and G (G1) functions (GGX) are taken from -// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). -// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). - -float G_GGX_2cos(float cos_theta_m, float alpha) { -	// Schlick's approximation -	// C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) -	// Eq. (19), although see Heitz (2014) the about the problems with his derivation. -	// It nevertheless approximates GGX well with k = alpha/2. -	float k = 0.5 * alpha; -	return 0.5 / (cos_theta_m * (1.0 - k) + k); - -	// float cos2 = cos_theta_m * cos_theta_m; -	// float sin2 = (1.0 - cos2); -	// return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); -} -  float D_GGX(float cos_theta_m, float alpha) {  	float alpha2 = alpha * alpha;  	float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m;  	return alpha2 / (M_PI * d * d);  } -float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { -	float cos2 = cos_theta_m * cos_theta_m; -	float sin2 = (1.0 - cos2); -	float s_x = alpha_x * cos_phi; -	float s_y = alpha_y * sin_phi; -	return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); +// From Earl Hammon, Jr. "PBR Diffuse Lighting for GGX+Smith Microsurfaces" https://www.gdcvault.com/play/1024478/PBR-Diffuse-Lighting-for-GGX +float V_GGX(float NdotL, float NdotV, float alpha) { +	return 0.5 / mix(2.0 * NdotL * NdotV, NdotL + NdotV, alpha);  }  float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { -	float cos2 = cos_theta_m * cos_theta_m; -	float sin2 = (1.0 - cos2); -	float r_x = cos_phi / alpha_x; -	float r_y = sin_phi / alpha_y; -	float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); -	return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); +	float alpha2 = alpha_x * alpha_y; +	highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * cos_theta_m); +	highp float v2 = dot(v, v); +	float w2 = alpha2 / v2; +	float D = alpha2 * w2 * w2 * (1.0 / M_PI); +	return D; +} + +float V_GGX_anisotropic(float alpha_x, float alpha_y, float TdotV, float TdotL, float BdotV, float BdotL, float NdotV, float NdotL) { +	float Lambda_V = NdotL * length(vec3(alpha_x * TdotV, alpha_y * BdotV, NdotV)); +	float Lambda_L = NdotV * length(vec3(alpha_x * TdotL, alpha_y * BdotL, NdotL)); +	return 0.5 / (Lambda_V + Lambda_L);  }  float SchlickFresnel(float u) { @@ -58,14 +32,6 @@ float SchlickFresnel(float u) {  	return m2 * m2 * m; // pow(m,5)  } -float GTR1(float NdotH, float a) { -	if (a >= 1.0) -		return 1.0 / M_PI; -	float a2 = a * a; -	float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; -	return (a2 - 1.0) / (M_PI * log(a2) * t); -} -  vec3 F0(float metallic, float specular, vec3 albedo) {  	float dielectric = 0.16 * specular * specular;  	// use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; @@ -87,7 +53,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte  		float rim, float rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -		float clearcoat, float clearcoat_gloss, +		float clearcoat, float clearcoat_roughness, vec3 vertex_normal,  #endif  #ifdef LIGHT_ANISOTROPY_USED  		vec3 B, vec3 T, float anisotropy, @@ -113,13 +79,13 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte  	float NdotL = min(A + dot(N, L), 1.0);  	float cNdotL = max(NdotL, 0.0); // clamped NdotL  	float NdotV = dot(N, V); -	float cNdotV = max(NdotV, 0.0); +	float cNdotV = max(NdotV, 1e-4); -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)  	vec3 H = normalize(V + L);  #endif -#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) +#if defined(SPECULAR_SCHLICK_GGX)  	float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);  #endif @@ -203,26 +169,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte  		// D -#if defined(SPECULAR_BLINN) - -		//normalized blinn -		float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; -		float blinn = pow(cNdotH, shininess); -		blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI)); - -		specular_light += light_color * attenuation * specular_amount * blinn * f0 * orms_unpacked.w; - -#elif defined(SPECULAR_PHONG) - -		vec3 R = normalize(-reflect(L, N)); -		float cRdotV = clamp(A + dot(R, V), 0.0, 1.0); -		float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; -		float phong = pow(cRdotV, shininess); -		phong *= (shininess + 1.0) * (1.0 / (8.0 * M_PI)); - -		specular_light += light_color * attenuation * specular_amount * phong * f0 * orms_unpacked.w; - -#elif defined(SPECULAR_TOON) +#if defined(SPECULAR_TOON)  		vec3 R = normalize(-reflect(L, N));  		float RdotV = dot(R, V); @@ -236,24 +183,21 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte  #elif defined(SPECULAR_SCHLICK_GGX)  		// shlick+ggx as default - +		float alpha_ggx = roughness * roughness;  #if defined(LIGHT_ANISOTROPY_USED) -		float alpha_ggx = roughness * roughness;  		float aspect = sqrt(1.0 - anisotropy * 0.9);  		float ax = alpha_ggx / aspect;  		float ay = alpha_ggx * aspect;  		float XdotH = dot(T, H);  		float YdotH = dot(B, H);  		float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); -		float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); - -#else -		float alpha_ggx = roughness * roughness; +		float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL); +#else // LIGHT_ANISOTROPY_USED  		float D = D_GGX(cNdotH, alpha_ggx); -		float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); -#endif -		// F +		float G = V_GGX(cNdotL, cNdotV, alpha_ggx); +#endif // LIGHT_ANISOTROPY_USED +	   // F  		float cLdotH5 = SchlickFresnel(cLdotH);  		vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); @@ -263,18 +207,23 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte  #endif  #if defined(LIGHT_CLEARCOAT_USED) +		// Clearcoat ignores normal_map, use vertex normal instead +		float ccNdotL = max(min(A + dot(vertex_normal, L), 1.0), 0.0); +		float ccNdotH = clamp(A + dot(vertex_normal, H), 0.0, 1.0); +		float ccNdotV = max(dot(vertex_normal, V), 1e-4);  #if !defined(SPECULAR_SCHLICK_GGX)  		float cLdotH5 = SchlickFresnel(cLdotH);  #endif -		float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); +		float Dr = D_GGX(ccNdotH, mix(0.001, 0.1, clearcoat_roughness)); +		float Gr = 0.25 / (cLdotH * cLdotH);  		float Fr = mix(.04, 1.0, cLdotH5); -		float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); - -		float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; +		float clearcoat_specular_brdf_NL = clearcoat * Gr * Fr * Dr * cNdotL;  		specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; -#endif +		// TODO: Clearcoat adds light to the scene right now (it is non-energy conserving), both diffuse and specular need to be scaled by (1.0 - FR) +		// but to do so we need to rearrange this entire function +#endif // LIGHT_CLEARCOAT_USED  	}  #ifdef USE_SHADOW_TO_OPACITY @@ -587,7 +536,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v  		float rim, float rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -		float clearcoat, float clearcoat_gloss, +		float clearcoat, float clearcoat_roughness, vec3 vertex_normal,  #endif  #ifdef LIGHT_ANISOTROPY_USED  		vec3 binormal, vec3 tangent, float anisotropy, @@ -711,7 +660,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v  			rim * omni_attenuation, rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -			clearcoat, clearcoat_gloss, +			clearcoat, clearcoat_roughness, vertex_normal,  #endif  #ifdef LIGHT_ANISOTROPY_USED  			binormal, tangent, anisotropy, @@ -827,7 +776,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v  		float rim, float rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -		float clearcoat, float clearcoat_gloss, +		float clearcoat, float clearcoat_roughness, vec3 vertex_normal,  #endif  #ifdef LIGHT_ANISOTROPY_USED  		vec3 binormal, vec3 tangent, float anisotropy, @@ -912,7 +861,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v  			rim * spot_attenuation, rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -			clearcoat, clearcoat_gloss, +			clearcoat, clearcoat_roughness, vertex_normal,  #endif  #ifdef LIGHT_ANISOTROPY_USED  			binormal, tangent, anisotropy, diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl index 4d6a3b5864..a1cf1d3c04 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -511,8 +511,8 @@ layout(location = 0) out mediump vec4 frag_color;  #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) -/* Make a default specular mode SPECULAR_SCHLICK_GGX. */ -#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON) +// Default to SPECULAR_SCHLICK_GGX. +#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON)  #define SPECULAR_SCHLICK_GGX  #endif @@ -596,7 +596,7 @@ void main() {  	float rim = 0.0;  	float rim_tint = 0.0;  	float clearcoat = 0.0; -	float clearcoat_gloss = 0.0; +	float clearcoat_roughness = 0.0;  	float anisotropy = 0.0;  	vec2 anisotropy_flow = vec2(1.0, 0.0);  	vec4 fog = vec4(0.0); @@ -874,7 +874,16 @@ void main() {  #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)  	if (scene_data.use_reflection_cubemap) { +#ifdef LIGHT_ANISOTROPY_USED +		// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy +		vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; +		vec3 anisotropic_tangent = cross(anisotropic_direction, view); +		vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction); +		vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); +		vec3 ref_vec = reflect(-view, bent_normal); +#else  		vec3 ref_vec = reflect(-view, normal); +#endif  		float horizon = min(1.0 + dot(ref_vec, normal), 1.0);  		ref_vec = scene_data.radiance_inverse_xform * ref_vec;  #ifdef USE_RADIANCE_CUBEMAP_ARRAY @@ -917,7 +926,35 @@ void main() {  #if defined(CUSTOM_IRRADIANCE_USED)  	ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a);  #endif // CUSTOM_IRRADIANCE_USED +#ifdef LIGHT_CLEARCOAT_USED + +	if (scene_data.use_reflection_cubemap) { +		vec3 n = normalize(normal_interp); // We want to use geometric normal, not normal_map +		float NoV = max(dot(n, view), 0.0001); +		vec3 ref_vec = reflect(-view, n); +		// The clear coat layer assumes an IOR of 1.5 (4% reflectance) +		float Fc = clearcoat * (0.04 + 0.96 * SchlickFresnel(NoV)); +		float attenuation = 1.0 - Fc; +		ambient_light *= attenuation; +		specular_light *= attenuation; +		float horizon = min(1.0 + dot(ref_vec, normal), 1.0); +		ref_vec = scene_data.radiance_inverse_xform * ref_vec; +		float roughness_lod = mix(0.001, 0.1, clearcoat_roughness) * MAX_ROUGHNESS_LOD; +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + +		float lod, blend; +		blend = modf(roughness_lod, lod); +		vec3 clearcoat_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb; +		clearcoat_light = mix(clearcoat_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend); + +#else +		vec3 clearcoat_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness_lod).rgb; + +#endif //USE_RADIANCE_CUBEMAP_ARRAY +		specular_light += clearcoat_light * horizon * horizon * Fc * scene_data.ambient_light_color_energy.a; +	} +#endif  #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)  	//radiance @@ -1002,8 +1039,16 @@ void main() {  			if (reflection_index == 0xFF) {  				break;  			} - -			reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum); +#ifdef LIGHT_ANISOTROPY_USED +			// https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy +			vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent; +			vec3 anisotropic_tangent = cross(anisotropic_direction, view); +			vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction); +			vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0))); +#else +			vec3 bent_normal = normal; +#endif +			reflection_process(reflection_index, vertex, bent_normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum);  		}  		if (reflection_accum.a > 0.0) { @@ -1368,7 +1413,7 @@ void main() {  					rim, rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -					clearcoat, clearcoat_gloss, +					clearcoat, clearcoat_roughness, normalize(normal_interp),  #endif  #ifdef LIGHT_ANISOTROPY_USED  					binormal, tangent, anisotropy, @@ -1415,10 +1460,11 @@ void main() {  					rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -					clearcoat, clearcoat_gloss, +					clearcoat, clearcoat_roughness, normalize(normal_interp),  #endif  #ifdef LIGHT_ANISOTROPY_USED -					tangent, binormal, anisotropy, +					tangent, +					binormal, anisotropy,  #endif  					diffuse_light, specular_light);  		} @@ -1459,10 +1505,11 @@ void main() {  					rim_tint,  #endif  #ifdef LIGHT_CLEARCOAT_USED -					clearcoat, clearcoat_gloss, +					clearcoat, clearcoat_roughness, normalize(normal_interp),  #endif  #ifdef LIGHT_ANISOTROPY_USED -					tangent, binormal, anisotropy, +					tangent, +					binormal, anisotropy,  #endif  					diffuse_light, specular_light);  		} diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl index 541c0b0603..7a624c3b95 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl @@ -7,7 +7,7 @@  #include "decal_data_inc.glsl" -#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)  #ifndef NORMAL_USED  #define NORMAL_USED  #endif |