mirror of https://github.com/godotengine/godot
Add transparency support for LightmapGI
Co-authored-by: Guerro323 <kaltobattle@gmail.com>
This commit is contained in:
parent
7f5c469292
commit
a3525bc015
|
|
@ -2730,6 +2730,9 @@
|
|||
<member name="rendering/lightmapping/bake_performance/max_rays_per_probe_pass" type="int" setter="" getter="" default="64">
|
||||
The maximum number of rays that can be thrown per pass when baking dynamic object lighting in [LightmapProbe]s with [LightmapGI]. Depending on the scene, adjusting this value may result in higher GPU utilization when baking lightmaps, leading to faster bake times.
|
||||
</member>
|
||||
<member name="rendering/lightmapping/bake_performance/max_transparency_rays" type="int" setter="" getter="" default="8">
|
||||
The maximum number of retry rays that can be thrown per pass when hitting a transparent surface when baking lightmaps with [LightmapGI]. Depending on the scene, reducing this value may lead to faster bake times.
|
||||
</member>
|
||||
<member name="rendering/lightmapping/bake_performance/region_size" type="int" setter="" getter="" default="512">
|
||||
The region size to use when baking lightmaps with [LightmapGI].
|
||||
</member>
|
||||
|
|
|
|||
|
|
@ -977,7 +977,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
|
|||
glBindFramebuffer(GL_FRAMEBUFFER, sky->radiance_framebuffer);
|
||||
|
||||
scene_state.reset_gl_state();
|
||||
scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED);
|
||||
scene_state.set_gl_cull_mode(RS::CULL_MODE_DISABLED);
|
||||
scene_state.enable_gl_blend(false);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
|
|
@ -1000,7 +1000,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
|
|||
} else {
|
||||
if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
|
||||
scene_state.reset_gl_state();
|
||||
scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED);
|
||||
scene_state.set_gl_cull_mode(RS::CULL_MODE_DISABLED);
|
||||
scene_state.enable_gl_blend(false);
|
||||
|
||||
cubemap_filter->filter_radiance(sky->raw_radiance, sky->radiance, sky->radiance_framebuffer, sky->radiance_size, sky->mipmap_count, sky->processing_layer);
|
||||
|
|
@ -1433,6 +1433,10 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
|
|||
if (surf->flags & GeometryInstanceSurface::FLAG_PASS_SHADOW) {
|
||||
rl->add_element(surf);
|
||||
}
|
||||
} else if (p_pass_mode == PASS_MODE_MATERIAL) {
|
||||
if (surf->flags & (GeometryInstanceSurface::FLAG_PASS_DEPTH | GeometryInstanceSurface::FLAG_PASS_OPAQUE | GeometryInstanceSurface::FLAG_PASS_ALPHA)) {
|
||||
rl->add_element(surf);
|
||||
}
|
||||
} else {
|
||||
if (surf->flags & (GeometryInstanceSurface::FLAG_PASS_DEPTH | GeometryInstanceSurface::FLAG_PASS_OPAQUE)) {
|
||||
rl->add_element(surf);
|
||||
|
|
@ -2210,7 +2214,7 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
|
|||
scene_state.enable_gl_depth_test(false);
|
||||
scene_state.enable_gl_depth_draw(true);
|
||||
glDisable(GL_CULL_FACE);
|
||||
scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
|
||||
scene_state.cull_mode = RS::CULL_MODE_DISABLED;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
}
|
||||
|
||||
|
|
@ -2587,7 +2591,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
scene_state.enable_gl_depth_draw(false);
|
||||
scene_state.enable_gl_depth_test(false);
|
||||
scene_state.enable_gl_blend(false);
|
||||
scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_BACK);
|
||||
scene_state.set_gl_cull_mode(RS::CULL_MODE_BACK);
|
||||
|
||||
Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id);
|
||||
|
||||
|
|
@ -2615,7 +2619,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
|
||||
scene_state.enable_gl_depth_test(true);
|
||||
scene_state.enable_gl_blend(false);
|
||||
scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_BACK);
|
||||
scene_state.set_gl_cull_mode(RS::CULL_MODE_BACK);
|
||||
|
||||
Transform3D transform = render_data.cam_transform;
|
||||
Projection projection = render_data.cam_projection;
|
||||
|
|
@ -3099,19 +3103,19 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
|||
}
|
||||
|
||||
// Find cull variant.
|
||||
GLES3::SceneShaderData::Cull cull_mode = shader->cull_mode;
|
||||
RS::CullMode cull_mode = shader->cull_mode;
|
||||
|
||||
if (p_pass_mode == PASS_MODE_MATERIAL || (surf->flags & GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
|
||||
cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
|
||||
cull_mode = RS::CULL_MODE_DISABLED;
|
||||
} else {
|
||||
bool mirror = inst->mirror;
|
||||
if (p_params->reverse_cull) {
|
||||
mirror = !mirror;
|
||||
}
|
||||
if (cull_mode == GLES3::SceneShaderData::CULL_FRONT && mirror) {
|
||||
cull_mode = GLES3::SceneShaderData::CULL_BACK;
|
||||
} else if (cull_mode == GLES3::SceneShaderData::CULL_BACK && mirror) {
|
||||
cull_mode = GLES3::SceneShaderData::CULL_FRONT;
|
||||
if (cull_mode == RS::CULL_MODE_FRONT && mirror) {
|
||||
cull_mode = RS::CULL_MODE_BACK;
|
||||
} else if (cull_mode == RS::CULL_MODE_BACK && mirror) {
|
||||
cull_mode = RS::CULL_MODE_FRONT;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3832,7 +3836,7 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
scene_state.enable_gl_depth_draw(true);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
scene_state.set_gl_cull_mode(GLES3::SceneShaderData::CULL_DISABLED);
|
||||
scene_state.set_gl_cull_mode(RS::CULL_MODE_DISABLED);
|
||||
|
||||
// Loop through quadrants and copy shadows over.
|
||||
for (int quadrant = 0; quadrant < 4; quadrant++) {
|
||||
|
|
|
|||
|
|
@ -461,7 +461,7 @@ private:
|
|||
bool used_depth_prepass = false;
|
||||
|
||||
GLES3::SceneShaderData::BlendMode current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
|
||||
GLES3::SceneShaderData::Cull cull_mode = GLES3::SceneShaderData::CULL_BACK;
|
||||
RS::CullMode cull_mode = RS::CULL_MODE_BACK;
|
||||
|
||||
bool current_blend_enabled = false;
|
||||
bool current_depth_draw_enabled = false;
|
||||
|
|
@ -477,7 +477,7 @@ private:
|
|||
|
||||
glCullFace(GL_BACK);
|
||||
glEnable(GL_CULL_FACE);
|
||||
cull_mode = GLES3::SceneShaderData::CULL_BACK;
|
||||
cull_mode = RS::CULL_MODE_BACK;
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
current_depth_draw_enabled = false;
|
||||
|
|
@ -485,16 +485,16 @@ private:
|
|||
current_depth_test_enabled = false;
|
||||
}
|
||||
|
||||
void set_gl_cull_mode(GLES3::SceneShaderData::Cull p_mode) {
|
||||
void set_gl_cull_mode(RS::CullMode p_mode) {
|
||||
if (cull_mode != p_mode) {
|
||||
if (p_mode == GLES3::SceneShaderData::CULL_DISABLED) {
|
||||
if (p_mode == RS::CULL_MODE_DISABLED) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
} else {
|
||||
if (cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
|
||||
if (cull_mode == RS::CULL_MODE_DISABLED) {
|
||||
// Last time was disabled, so enable and set proper face.
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
glCullFace(p_mode == GLES3::SceneShaderData::CULL_FRONT ? GL_FRONT : GL_BACK);
|
||||
glCullFace(p_mode == RS::CULL_MODE_FRONT ? GL_FRONT : GL_BACK);
|
||||
}
|
||||
cull_mode = p_mode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1882,10 +1882,18 @@ void main() {
|
|||
#ifndef USE_SHADOW_TO_OPACITY
|
||||
|
||||
#if defined(ALPHA_SCISSOR_USED)
|
||||
#ifdef RENDER_MATERIAL
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
alpha = 0.0;
|
||||
} else {
|
||||
alpha = 1.0;
|
||||
}
|
||||
#else
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
discard;
|
||||
}
|
||||
alpha = 1.0;
|
||||
#endif // RENDER_MATERIAL
|
||||
#else
|
||||
#ifdef MODE_RENDER_DEPTH
|
||||
#ifdef USE_OPAQUE_PREPASS
|
||||
|
|
@ -2215,9 +2223,17 @@ void main() {
|
|||
alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
|
||||
|
||||
#if defined(ALPHA_SCISSOR_USED)
|
||||
#ifdef RENDER_MATERIAL
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
alpha = 0.0;
|
||||
} else {
|
||||
alpha = 1.0;
|
||||
}
|
||||
#else
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
discard;
|
||||
}
|
||||
#endif // RENDER_MATERIAL
|
||||
#endif // !ALPHA_SCISSOR_USED
|
||||
|
||||
#endif // !MODE_RENDER_DEPTH
|
||||
|
|
|
|||
|
|
@ -2505,6 +2505,19 @@ bool MaterialStorage::material_casts_shadows(RID p_material) {
|
|||
return true; //by default everything casts shadows
|
||||
}
|
||||
|
||||
RS::CullMode MaterialStorage::material_get_cull_mode(RID p_material) const {
|
||||
const GLES3::Material *material = material_owner.get_or_null(p_material);
|
||||
ERR_FAIL_NULL_V(material, RS::CULL_MODE_DISABLED);
|
||||
ERR_FAIL_NULL_V(material->shader, RS::CULL_MODE_DISABLED);
|
||||
if (material->shader->data) {
|
||||
SceneShaderData *data = dynamic_cast<SceneShaderData *>(material->shader->data);
|
||||
if (data) {
|
||||
return (RS::CullMode)data->cull_mode;
|
||||
}
|
||||
}
|
||||
return RS::CULL_MODE_DISABLED;
|
||||
}
|
||||
|
||||
void MaterialStorage::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) {
|
||||
GLES3::Material *material = material_owner.get_or_null(p_material);
|
||||
ERR_FAIL_NULL(material);
|
||||
|
|
@ -2907,7 +2920,7 @@ void SceneShaderData::set_code(const String &p_code) {
|
|||
int blend_modei = BLEND_MODE_MIX;
|
||||
int depth_testi = DEPTH_TEST_ENABLED;
|
||||
int alpha_antialiasing_modei = ALPHA_ANTIALIASING_OFF;
|
||||
int cull_modei = CULL_BACK;
|
||||
int cull_modei = RS::CULL_MODE_BACK;
|
||||
int depth_drawi = DEPTH_DRAW_OPAQUE;
|
||||
|
||||
ShaderCompiler::IdentifierActions actions;
|
||||
|
|
@ -2930,9 +2943,9 @@ void SceneShaderData::set_code(const String &p_code) {
|
|||
|
||||
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
|
||||
|
||||
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, CULL_DISABLED);
|
||||
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, CULL_FRONT);
|
||||
actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull_modei, CULL_BACK);
|
||||
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_DISABLED);
|
||||
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_FRONT);
|
||||
actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_BACK);
|
||||
|
||||
actions.render_mode_flags["unshaded"] = &unshaded;
|
||||
actions.render_mode_flags["wireframe"] = &wireframe;
|
||||
|
|
@ -2990,7 +3003,7 @@ void SceneShaderData::set_code(const String &p_code) {
|
|||
alpha_antialiasing_mode = AlphaAntiAliasing(alpha_antialiasing_modei);
|
||||
depth_draw = DepthDraw(depth_drawi);
|
||||
depth_test = DepthTest(depth_testi);
|
||||
cull_mode = Cull(cull_modei);
|
||||
cull_mode = RS::CullMode(cull_modei);
|
||||
|
||||
vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL; // We can always read vertices and normals.
|
||||
vertex_input_mask |= uses_tangent << RS::ARRAY_TANGENT;
|
||||
|
|
|
|||
|
|
@ -263,12 +263,6 @@ struct SceneShaderData : public ShaderData {
|
|||
DEPTH_TEST_ENABLED
|
||||
};
|
||||
|
||||
enum Cull {
|
||||
CULL_DISABLED,
|
||||
CULL_FRONT,
|
||||
CULL_BACK
|
||||
};
|
||||
|
||||
enum AlphaAntiAliasing {
|
||||
ALPHA_ANTIALIASING_OFF,
|
||||
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
|
||||
|
|
@ -292,7 +286,7 @@ struct SceneShaderData : public ShaderData {
|
|||
AlphaAntiAliasing alpha_antialiasing_mode;
|
||||
DepthDraw depth_draw;
|
||||
DepthTest depth_test;
|
||||
Cull cull_mode;
|
||||
RS::CullMode cull_mode;
|
||||
|
||||
bool uses_point_size;
|
||||
bool uses_alpha;
|
||||
|
|
@ -618,6 +612,7 @@ public:
|
|||
|
||||
virtual bool material_is_animated(RID p_material) override;
|
||||
virtual bool material_casts_shadows(RID p_material) override;
|
||||
virtual RS::CullMode material_get_cull_mode(RID p_material) const override;
|
||||
|
||||
virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "lightmapper_rd.h"
|
||||
|
||||
#include "core/string/print_string.h"
|
||||
#include "lm_blendseams.glsl.gen.h"
|
||||
#include "lm_compute.glsl.gen.h"
|
||||
#include "lm_raster.glsl.gen.h"
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
#include "editor/editor_paths.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "servers/rendering/rendering_device_binds.h"
|
||||
#include "servers/rendering/rendering_server_globals.h"
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
#include "drivers/vulkan/rendering_context_driver_vulkan.h"
|
||||
|
|
@ -477,7 +479,16 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
|
|||
t.max_bounds[0] = taabb.position.x + MAX(taabb.size.x, 0.0001);
|
||||
t.max_bounds[1] = taabb.position.y + MAX(taabb.size.y, 0.0001);
|
||||
t.max_bounds[2] = taabb.position.z + MAX(taabb.size.z, 0.0001);
|
||||
t.pad0 = t.pad1 = 0; //make valgrind not complain
|
||||
|
||||
t.cull_mode = RS::CULL_MODE_BACK;
|
||||
|
||||
RID material = mi.data.material[i];
|
||||
if (material.is_valid()) {
|
||||
t.cull_mode = RSG::material_storage->material_get_cull_mode(material);
|
||||
} else {
|
||||
print_line("No material for mesh with vertex count ", mi.data.points.size());
|
||||
}
|
||||
t.pad1 = 0; //make valgrind not complain
|
||||
triangles.push_back(t);
|
||||
slice_triangle_count.write[t.slice]++;
|
||||
}
|
||||
|
|
@ -1319,6 +1330,8 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||
bake_parameters.bounces = p_bounces;
|
||||
bake_parameters.bounce_indirect_energy = p_bounce_indirect_energy;
|
||||
bake_parameters.shadowmask_light_idx = shadowmask_light_idx;
|
||||
// Same number of rays for transparency regardless of quality (it's more of a retry rather than shooting new ones).
|
||||
bake_parameters.transparency_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_transparency_rays");
|
||||
|
||||
bake_parameters_buffer = rd->uniform_buffer_create(sizeof(BakeParameters));
|
||||
rd->buffer_update(bake_parameters_buffer, 0, sizeof(BakeParameters), &bake_parameters);
|
||||
|
|
|
|||
|
|
@ -57,8 +57,9 @@ class LightmapperRD : public Lightmapper {
|
|||
uint32_t bounces = 0;
|
||||
|
||||
float bounce_indirect_energy = 0.0f;
|
||||
int shadowmask_light_idx = 0;
|
||||
uint32_t pad[2] = {};
|
||||
uint32_t shadowmask_light_idx = 0;
|
||||
uint32_t transparency_rays = 0;
|
||||
uint32_t pad[1] = {};
|
||||
};
|
||||
|
||||
struct MeshInstance {
|
||||
|
|
@ -185,7 +186,7 @@ class LightmapperRD : public Lightmapper {
|
|||
uint32_t indices[3] = {};
|
||||
uint32_t slice = 0;
|
||||
float min_bounds[3] = {};
|
||||
float pad0 = 0.0;
|
||||
uint32_t cull_mode = 0;
|
||||
float max_bounds[3] = {};
|
||||
float pad1 = 0.0;
|
||||
bool operator<(const Triangle &p_triangle) const {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
/* SET 0, static data that does not change between any call */
|
||||
|
||||
layout(set = 0, binding = 0) uniform BakeParameters {
|
||||
vec3 world_size;
|
||||
|
|
@ -18,8 +17,8 @@ layout(set = 0, binding = 0) uniform BakeParameters {
|
|||
|
||||
float bounce_indirect_energy;
|
||||
int shadowmask_light_idx;
|
||||
uint transparency_rays;
|
||||
uint pad0;
|
||||
uint pad1;
|
||||
}
|
||||
bake_params;
|
||||
|
||||
|
|
@ -35,11 +34,15 @@ layout(set = 0, binding = 1, std430) restrict readonly buffer Vertices {
|
|||
}
|
||||
vertices;
|
||||
|
||||
#define CULL_DISABLED 0
|
||||
#define CULL_FRONT 1
|
||||
#define CULL_BACK 2
|
||||
|
||||
struct Triangle {
|
||||
uvec3 indices;
|
||||
uint slice;
|
||||
vec3 min_bounds;
|
||||
uint pad0;
|
||||
uint cull_mode;
|
||||
vec3 max_bounds;
|
||||
uint pad1;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -154,7 +154,8 @@ uint trace_ray(vec3 p_from, vec3 p_to, bool p_any_hit, out float r_distance, out
|
|||
vec3 dir_cell = normalize(rel_cell);
|
||||
vec3 delta = min(abs(1.0 / dir_cell), bake_params.grid_size); // Use bake_params.grid_size as max to prevent infinity values.
|
||||
ivec3 step = ivec3(sign(rel_cell));
|
||||
vec3 side = (sign(rel_cell) * (vec3(icell) - from_cell) + (sign(rel_cell) * 0.5) + 0.5) * delta;
|
||||
const vec3 init_next_cell = vec3(icell) + max(vec3(0), sign(step));
|
||||
vec3 t_max = mix(vec3(0), (init_next_cell - from_cell) / dir_cell, notEqual(step, vec3(0))); // Distance to next boundary.
|
||||
|
||||
uint iters = 0;
|
||||
while (all(greaterThanEqual(icell, ivec3(0))) && all(lessThan(icell, ivec3(bake_params.grid_size))) && (iters < 1000)) {
|
||||
|
|
@ -225,7 +226,6 @@ uint trace_ray(vec3 p_from, vec3 p_to, bool p_any_hit, out float r_distance, out
|
|||
// Return early if any hit was requested.
|
||||
return RAY_ANY;
|
||||
}
|
||||
|
||||
vec3 position = p_from + dir * distance;
|
||||
vec3 hit_cell = (position - bake_params.to_cell_offset) * bake_params.to_cell_size;
|
||||
if (icell != ivec3(hit_cell)) {
|
||||
|
|
@ -242,6 +242,17 @@ uint trace_ray(vec3 p_from, vec3 p_to, bool p_any_hit, out float r_distance, out
|
|||
}
|
||||
|
||||
if (distance < best_distance) {
|
||||
switch (triangle.cull_mode) {
|
||||
case CULL_DISABLED:
|
||||
backface = false;
|
||||
break;
|
||||
case CULL_FRONT:
|
||||
backface = !backface;
|
||||
break;
|
||||
case CULL_BACK: // Default behavior.
|
||||
break;
|
||||
}
|
||||
|
||||
hit = backface ? RAY_BACK : RAY_FRONT;
|
||||
best_distance = distance;
|
||||
r_distance = distance;
|
||||
|
|
@ -271,17 +282,16 @@ uint trace_ray(vec3 p_from, vec3 p_to, bool p_any_hit, out float r_distance, out
|
|||
}
|
||||
|
||||
// There should be only one axis updated at a time for DDA to work properly.
|
||||
bvec3 mask = bvec3(true, false, false);
|
||||
float m = side.x;
|
||||
if (side.y < m) {
|
||||
m = side.y;
|
||||
mask = bvec3(false, true, false);
|
||||
if (t_max.x < t_max.y && t_max.x < t_max.z) {
|
||||
icell.x += step.x;
|
||||
t_max.x += delta.x;
|
||||
} else if (t_max.y < t_max.z) {
|
||||
icell.y += step.y;
|
||||
t_max.y += delta.y;
|
||||
} else {
|
||||
icell.z += step.z;
|
||||
t_max.z += delta.z;
|
||||
}
|
||||
if (side.z < m) {
|
||||
mask = bvec3(false, false, true);
|
||||
}
|
||||
side += vec3(mask) * delta;
|
||||
icell += ivec3(vec3(mask)) * step;
|
||||
iters++;
|
||||
}
|
||||
|
||||
|
|
@ -294,6 +304,27 @@ uint trace_ray_closest_hit_triangle(vec3 p_from, vec3 p_to, out uint r_triangle,
|
|||
return trace_ray(p_from, p_to, false, distance, normal, r_triangle, r_barycentric);
|
||||
}
|
||||
|
||||
uint trace_ray_closest_hit_triangle_albedo_alpha(vec3 p_from, vec3 p_to, out vec4 albedo_alpha, out vec3 hit_position) {
|
||||
float distance;
|
||||
vec3 normal;
|
||||
uint tidx;
|
||||
vec3 barycentric;
|
||||
|
||||
uint ret = trace_ray(p_from, p_to, false, distance, normal, tidx, barycentric);
|
||||
if (ret != RAY_MISS) {
|
||||
Vertex vert0 = vertices.data[triangles.data[tidx].indices.x];
|
||||
Vertex vert1 = vertices.data[triangles.data[tidx].indices.y];
|
||||
Vertex vert2 = vertices.data[triangles.data[tidx].indices.z];
|
||||
|
||||
vec3 uvw = vec3(barycentric.x * vert0.uv + barycentric.y * vert1.uv + barycentric.z * vert2.uv, float(triangles.data[tidx].slice));
|
||||
|
||||
albedo_alpha = textureLod(sampler2DArray(albedo_tex, linear_sampler), uvw, 0);
|
||||
hit_position = barycentric.x * vert0.position + barycentric.y * vert1.position + barycentric.z * vert2.position;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint trace_ray_closest_hit_distance(vec3 p_from, vec3 p_to, out float r_distance, out vec3 r_normal) {
|
||||
uint triangle;
|
||||
vec3 barycentric;
|
||||
|
|
@ -392,6 +423,8 @@ vec2 get_vogel_disk(float p_i, float p_rotation, float p_sample_count_sqrt) {
|
|||
}
|
||||
|
||||
void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool p_soft_shadowing, out vec3 r_light, out vec3 r_light_dir, inout uint r_noise, float p_texel_size, out float r_shadow) {
|
||||
const float EPSILON = 0.00001;
|
||||
|
||||
r_light = vec3(0.0f);
|
||||
r_shadow = 0.0f;
|
||||
|
||||
|
|
@ -460,6 +493,7 @@ void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool
|
|||
vec3 light_to_point_bitan = normalize(cross(light_to_point, light_to_point_tan));
|
||||
|
||||
uint hits = 0;
|
||||
float aa_power = 0.0;
|
||||
for (uint i = 0; i < ray_count; i++) {
|
||||
// Create a random sample within the texel.
|
||||
vec2 disk_sample = (halton_map[i] - vec2(0.5)) * p_texel_size * light_data.shadow_blur;
|
||||
|
|
@ -468,9 +502,13 @@ void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool
|
|||
vec3 origin = p_position - disk_aligned;
|
||||
vec3 light_dir = normalize(light_pos - origin);
|
||||
|
||||
float power = 0.0;
|
||||
uint power_accm = 0;
|
||||
vec3 prev_pos = origin;
|
||||
if (use_soft_shadows) {
|
||||
uint soft_shadow_hits = 0;
|
||||
for (uint j = 0; j < shadowing_ray_count; j++) {
|
||||
origin = prev_pos;
|
||||
// Optimization:
|
||||
// Once already traced an important proportion of rays, if all are hits or misses,
|
||||
// assume we're not in the penumbra so we can infer the rest would have the same result.
|
||||
|
|
@ -490,24 +528,116 @@ void trace_direct_light(vec3 p_position, vec3 p_normal, uint p_light_index, bool
|
|||
float vogel_index = float(total_ray_count - 1 - (i * shadowing_ray_count + j)); // Start from (total_ray_count - 1) so we check the outer points first.
|
||||
vec2 light_disk_sample = get_vogel_disk(vogel_index, a, shadowing_ray_count_sqrt) * soft_shadowing_disk_size * light_data.shadow_blur;
|
||||
vec3 light_disk_to_point = normalize(light_to_point + light_disk_sample.x * light_to_point_tan + light_disk_sample.y * light_to_point_bitan);
|
||||
float sample_penumbra = 0.0;
|
||||
bool sample_did_hit = false;
|
||||
|
||||
for (uint iter = 0; iter < bake_params.transparency_rays; iter++) {
|
||||
vec4 hit_albedo = vec4(1.0);
|
||||
vec3 hit_position;
|
||||
// Offset the ray origin for AA, offset the light position for soft shadows.
|
||||
uint ret = trace_ray_closest_hit_triangle_albedo_alpha(origin - light_disk_to_point * (bake_params.bias + length(disk_sample)), p_position - light_disk_to_point * dist, hit_albedo, hit_position);
|
||||
if (ret == RAY_MISS) {
|
||||
if (!sample_did_hit) {
|
||||
sample_penumbra = 1.0;
|
||||
}
|
||||
soft_shadow_hits += 1;
|
||||
break;
|
||||
} else if (ret == RAY_FRONT || ret == RAY_BACK) {
|
||||
bool contribute = ret == RAY_FRONT || !sample_did_hit;
|
||||
if (!sample_did_hit) {
|
||||
sample_penumbra = 1.0;
|
||||
sample_did_hit = true;
|
||||
}
|
||||
|
||||
soft_shadow_hits += 1;
|
||||
|
||||
if (contribute) {
|
||||
sample_penumbra = max(sample_penumbra - hit_albedo.a - EPSILON, 0.0);
|
||||
}
|
||||
origin = hit_position + r_light_dir * bake_params.bias;
|
||||
|
||||
if (sample_penumbra - EPSILON <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
power += sample_penumbra;
|
||||
power_accm++;
|
||||
}
|
||||
|
||||
hits += soft_shadow_hits;
|
||||
} else { // No soft shadows.
|
||||
float sample_penumbra = 0.0;
|
||||
bool sample_did_hit = false;
|
||||
for (uint iter = 0; iter < bake_params.transparency_rays; iter++) {
|
||||
vec4 hit_albedo = vec4(1.0);
|
||||
vec3 hit_position;
|
||||
// Offset the ray origin for AA, offset the light position for soft shadows.
|
||||
if (trace_ray_any_hit(origin - light_disk_to_point * (bake_params.bias + length(disk_sample)), p_position - light_disk_to_point * dist) == RAY_MISS) {
|
||||
soft_shadow_hits++;
|
||||
uint ret = trace_ray_closest_hit_triangle_albedo_alpha(origin + light_dir * (bake_params.bias + length(disk_sample)), light_pos, hit_albedo, hit_position);
|
||||
if (ret == RAY_MISS) {
|
||||
if (!sample_did_hit) {
|
||||
sample_penumbra = 1.0;
|
||||
}
|
||||
hits++;
|
||||
break;
|
||||
} else if (ret == RAY_FRONT || ret == RAY_BACK) {
|
||||
bool contribute = ret == RAY_FRONT || !sample_did_hit;
|
||||
if (!sample_did_hit) {
|
||||
sample_penumbra = 1.0;
|
||||
sample_did_hit = true;
|
||||
}
|
||||
|
||||
hits++;
|
||||
|
||||
if (contribute) {
|
||||
sample_penumbra = max(sample_penumbra - hit_albedo.a - EPSILON, 0.0);
|
||||
}
|
||||
origin = hit_position + r_light_dir * bake_params.bias;
|
||||
|
||||
if (sample_penumbra - EPSILON <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
hits += soft_shadow_hits;
|
||||
} else {
|
||||
// Offset the ray origin based on the disk. Also increase the bias for further samples to avoid bleeding.
|
||||
if (trace_ray_any_hit(origin + light_dir * (bake_params.bias + length(disk_sample)), light_pos) == RAY_MISS) {
|
||||
hits++;
|
||||
power += sample_penumbra;
|
||||
power_accm = 1;
|
||||
}
|
||||
aa_power = power / float(power_accm);
|
||||
}
|
||||
penumbra = aa_power;
|
||||
} else { // No soft shadows.
|
||||
bool did_hit = false;
|
||||
penumbra = 0.0;
|
||||
for (uint iter = 0; iter < bake_params.transparency_rays; iter++) {
|
||||
vec4 hit_albedo = vec4(1.0);
|
||||
vec3 hit_position;
|
||||
uint ret = trace_ray_closest_hit_triangle_albedo_alpha(p_position + r_light_dir * bake_params.bias, light_pos, hit_albedo, hit_position);
|
||||
if (ret == RAY_MISS) {
|
||||
if (!did_hit) {
|
||||
penumbra = 1.0;
|
||||
}
|
||||
break;
|
||||
} else if (ret == RAY_FRONT || ret == RAY_BACK) {
|
||||
bool contribute = (ret == RAY_FRONT || !did_hit);
|
||||
if (!did_hit) {
|
||||
penumbra = 1.0;
|
||||
did_hit = true;
|
||||
}
|
||||
|
||||
if (contribute) {
|
||||
penumbra = max(penumbra - hit_albedo.a - EPSILON, 0.0);
|
||||
}
|
||||
|
||||
p_position = hit_position + r_light_dir * bake_params.bias;
|
||||
|
||||
if (penumbra - EPSILON <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
penumbra = float(hits) / float(total_ray_count);
|
||||
} else {
|
||||
if (trace_ray_any_hit(p_position + r_light_dir * bake_params.bias, light_pos) == RAY_MISS) {
|
||||
penumbra = 1.0;
|
||||
}
|
||||
|
||||
penumbra = clamp(penumbra, 0.0, 1.0);
|
||||
}
|
||||
|
||||
r_shadow = penumbra;
|
||||
|
|
@ -533,6 +663,7 @@ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise, f
|
|||
vec3 position = p_position;
|
||||
vec3 ray_dir = p_ray_dir;
|
||||
uint max_depth = max(bake_params.bounces, 1);
|
||||
uint transparency_rays_left = bake_params.transparency_rays;
|
||||
vec3 throughput = vec3(1.0);
|
||||
vec3 light = vec3(0.0);
|
||||
for (uint depth = 0; depth < max_depth; depth++) {
|
||||
|
|
@ -546,6 +677,8 @@ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise, f
|
|||
vec3 uvw = vec3(barycentric.x * vert0.uv + barycentric.y * vert1.uv + barycentric.z * vert2.uv, float(triangles.data[tidx].slice));
|
||||
position = barycentric.x * vert0.position + barycentric.y * vert1.position + barycentric.z * vert2.position;
|
||||
|
||||
vec3 prev_normal = ray_dir;
|
||||
|
||||
vec3 norm0 = vec3(vert0.normal_xy, vert0.normal_z);
|
||||
vec3 norm1 = vec3(vert1.normal_xy, vert1.normal_z);
|
||||
vec3 norm2 = vec3(vert2.normal_xy, vert2.normal_z);
|
||||
|
|
@ -568,13 +701,29 @@ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise, f
|
|||
direct_light *= bake_params.exposure_normalization;
|
||||
#endif
|
||||
|
||||
vec3 albedo = textureLod(sampler2DArray(albedo_tex, linear_sampler), uvw, 0).rgb;
|
||||
vec4 albedo_alpha = textureLod(sampler2DArray(albedo_tex, linear_sampler), uvw, 0).rgba;
|
||||
vec3 emissive = textureLod(sampler2DArray(emission_tex, linear_sampler), uvw, 0).rgb;
|
||||
emissive *= bake_params.exposure_normalization;
|
||||
|
||||
light += throughput * emissive;
|
||||
throughput *= albedo;
|
||||
light += throughput * direct_light * bake_params.bounce_indirect_energy;
|
||||
light += throughput * emissive * albedo_alpha.a;
|
||||
throughput = mix(throughput, throughput * albedo_alpha.rgb, albedo_alpha.a);
|
||||
light += throughput * direct_light * bake_params.bounce_indirect_energy * albedo_alpha.a;
|
||||
|
||||
if (albedo_alpha.a < 1.0) {
|
||||
transparency_rays_left -= 1;
|
||||
depth -= 1;
|
||||
if (transparency_rays_left <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Either bounce off the transparent surface or keep going forward.
|
||||
float pa = albedo_alpha.a * albedo_alpha.a;
|
||||
if (randomize(r_noise) > pa) {
|
||||
normal = prev_normal;
|
||||
}
|
||||
|
||||
position += normal * bake_params.bias;
|
||||
}
|
||||
|
||||
// Use Russian Roulette to determine a probability to terminate the bounce earlier as an optimization.
|
||||
// <https://computergraphics.stackexchange.com/questions/2316/is-russian-roulette-really-the-answer>
|
||||
|
|
@ -592,9 +741,55 @@ vec3 trace_indirect_light(vec3 p_position, vec3 p_ray_dir, inout uint r_noise, f
|
|||
// Look for the environment color and stop bouncing.
|
||||
light += throughput * trace_environment_color(ray_dir);
|
||||
break;
|
||||
} else {
|
||||
// Ignore any other trace results.
|
||||
break;
|
||||
} else if (trace_result == RAY_BACK) {
|
||||
Vertex vert0 = vertices.data[triangles.data[tidx].indices.x];
|
||||
Vertex vert1 = vertices.data[triangles.data[tidx].indices.y];
|
||||
Vertex vert2 = vertices.data[triangles.data[tidx].indices.z];
|
||||
vec3 uvw = vec3(barycentric.x * vert0.uv + barycentric.y * vert1.uv + barycentric.z * vert2.uv, float(triangles.data[tidx].slice));
|
||||
position = barycentric.x * vert0.position + barycentric.y * vert1.position + barycentric.z * vert2.position;
|
||||
|
||||
vec4 albedo_alpha = textureLod(sampler2DArray(albedo_tex, linear_sampler), uvw, 0).rgba;
|
||||
|
||||
if (albedo_alpha.a > 1.0) {
|
||||
break;
|
||||
}
|
||||
|
||||
transparency_rays_left -= 1;
|
||||
depth -= 1;
|
||||
if (transparency_rays_left <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
vec3 norm0 = vec3(vert0.normal_xy, vert0.normal_z);
|
||||
vec3 norm1 = vec3(vert1.normal_xy, vert1.normal_z);
|
||||
vec3 norm2 = vec3(vert2.normal_xy, vert2.normal_z);
|
||||
vec3 normal = barycentric.x * norm0 + barycentric.y * norm1 + barycentric.z * norm2;
|
||||
|
||||
vec3 direct_light = vec3(0.0f);
|
||||
#ifdef USE_LIGHT_TEXTURE_FOR_BOUNCES
|
||||
direct_light += textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
|
||||
#else
|
||||
// Trace the lights directly. Significantly more expensive but more accurate in scenarios
|
||||
// where the lightmap texture isn't reliable.
|
||||
for (uint i = 0; i < bake_params.light_count; i++) {
|
||||
vec3 light;
|
||||
vec3 light_dir;
|
||||
float shadow;
|
||||
trace_direct_light(position, normal, i, false, light, light_dir, r_noise, p_texel_size, shadow);
|
||||
direct_light += light * lights.data[i].indirect_energy;
|
||||
}
|
||||
|
||||
direct_light *= bake_params.exposure_normalization;
|
||||
#endif
|
||||
|
||||
vec3 emissive = textureLod(sampler2DArray(emission_tex, linear_sampler), uvw, 0).rgb;
|
||||
emissive *= bake_params.exposure_normalization;
|
||||
|
||||
light += throughput * emissive * albedo_alpha.a;
|
||||
throughput = mix(mix(throughput, throughput * albedo_alpha.rgb, albedo_alpha.a), vec3(0.0), albedo_alpha.a);
|
||||
light += throughput * direct_light * bake_params.bounce_indirect_energy * albedo_alpha.a;
|
||||
|
||||
position += ray_dir * bake_params.bias;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) {
|
|||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/ultra_quality_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 2048);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_rays_per_pass", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 32);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/region_size", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 512);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_performance/max_transparency_rays", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 8);
|
||||
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/low_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 64);
|
||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/bake_quality/medium_quality_probe_ray_count", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 256);
|
||||
|
|
|
|||
|
|
@ -981,7 +981,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
|
|||
w_albedo[i + 0] = uint8_t(CLAMP(float(r_aa[i + 0]) * (1.0 - float(r_orm[i + 2] / 255.0)), 0, 255));
|
||||
w_albedo[i + 1] = uint8_t(CLAMP(float(r_aa[i + 1]) * (1.0 - float(r_orm[i + 2] / 255.0)), 0, 255));
|
||||
w_albedo[i + 2] = uint8_t(CLAMP(float(r_aa[i + 2]) * (1.0 - float(r_orm[i + 2] / 255.0)), 0, 255));
|
||||
w_albedo[i + 3] = 255;
|
||||
w_albedo[i + 3] = r_aa[i + 3];
|
||||
}
|
||||
|
||||
md.albedo_on_uv2.instantiate();
|
||||
|
|
@ -1002,6 +1002,11 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
|
|||
continue;
|
||||
}
|
||||
Array a = mf.mesh->surface_get_arrays(i);
|
||||
Ref<Material> mat = mf.mesh->surface_get_material(i);
|
||||
RID mat_rid;
|
||||
if (mat.is_valid()) {
|
||||
mat_rid = mat->get_rid();
|
||||
}
|
||||
|
||||
Vector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
|
||||
const Vector3 *vr = vertices.ptr();
|
||||
|
|
@ -1051,6 +1056,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
|
|||
|
||||
md.uv2.push_back(uvr[vidx[k]]);
|
||||
md.normal.push_back(normal_xform.xform(nr[vidx[k]]).normalized());
|
||||
md.material.push_back(mat_rid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ public:
|
|||
Vector<Vector3> points;
|
||||
Vector<Vector2> uv2;
|
||||
Vector<Vector3> normal;
|
||||
Vector<RID> material;
|
||||
Ref<Image> albedo_on_uv2;
|
||||
Ref<Image> emission_on_uv2;
|
||||
Variant userdata;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@ public:
|
|||
|
||||
virtual bool material_is_animated(RID p_material) override { return false; }
|
||||
virtual bool material_casts_shadows(RID p_material) override { return false; }
|
||||
virtual RS::CullMode material_get_cull_mode(RID p_material) const override { return RS::CULL_MODE_DISABLED; }
|
||||
|
||||
virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override {}
|
||||
virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) override {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1120,6 +1120,10 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
|
|||
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) {
|
||||
rl->add_element(surf);
|
||||
}
|
||||
} else if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL) {
|
||||
if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE | GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) {
|
||||
rl->add_element(surf);
|
||||
}
|
||||
} else {
|
||||
if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
|
||||
rl->add_element(surf);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
|
|||
blend_mode = BLEND_MODE_MIX;
|
||||
depth_testi = DEPTH_TEST_ENABLED;
|
||||
alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
|
||||
int cull_modei = CULL_BACK;
|
||||
int cull_modei = RS::CULL_MODE_BACK;
|
||||
|
||||
uses_point_size = false;
|
||||
uses_alpha = false;
|
||||
|
|
@ -101,9 +101,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
|
|||
|
||||
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
|
||||
|
||||
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, CULL_DISABLED);
|
||||
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, CULL_FRONT);
|
||||
actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull_modei, CULL_BACK);
|
||||
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_DISABLED);
|
||||
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_FRONT);
|
||||
actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_BACK);
|
||||
|
||||
actions.render_mode_flags["unshaded"] = &unshaded;
|
||||
actions.render_mode_flags["wireframe"] = &wireframe;
|
||||
|
|
@ -158,7 +158,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
|
|||
|
||||
depth_draw = DepthDraw(depth_drawi);
|
||||
depth_test = DepthTest(depth_testi);
|
||||
cull_mode = Cull(cull_modei);
|
||||
cull_mode = RS::CullMode(cull_modei);
|
||||
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
|
||||
uses_screen_texture = gen_code.uses_screen_texture;
|
||||
uses_depth_texture = gen_code.uses_depth_texture;
|
||||
|
|
|
|||
|
|
@ -153,12 +153,6 @@ public:
|
|||
DEPTH_TEST_ENABLED
|
||||
};
|
||||
|
||||
enum Cull {
|
||||
CULL_DISABLED,
|
||||
CULL_FRONT,
|
||||
CULL_BACK
|
||||
};
|
||||
|
||||
enum CullVariant {
|
||||
CULL_VARIANT_NORMAL,
|
||||
CULL_VARIANT_REVERSED,
|
||||
|
|
@ -250,7 +244,7 @@ public:
|
|||
bool writes_modelview_or_projection = false;
|
||||
bool uses_world_coordinates = false;
|
||||
bool uses_screen_texture_mipmaps = false;
|
||||
Cull cull_mode = CULL_DISABLED;
|
||||
RS::CullMode cull_mode = RS::CULL_MODE_DISABLED;
|
||||
|
||||
uint64_t last_pass = 0;
|
||||
uint32_t index = 0;
|
||||
|
|
@ -272,7 +266,7 @@ public:
|
|||
}
|
||||
|
||||
_FORCE_INLINE_ bool uses_shared_shadow_material() const {
|
||||
bool backface_culling = cull_mode == CULL_BACK;
|
||||
bool backface_culling = cull_mode == RS::CULL_MODE_BACK;
|
||||
return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_position && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && backface_culling && !uses_point_size && !uses_world_coordinates && !wireframe;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2061,6 +2061,10 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
|
|||
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) {
|
||||
rl->add_element(surf);
|
||||
}
|
||||
} else if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL) {
|
||||
if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE | GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) {
|
||||
rl->add_element(surf);
|
||||
}
|
||||
} else {
|
||||
if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
|
||||
rl->add_element(surf);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
|
|||
blend_mode = BLEND_MODE_MIX;
|
||||
depth_testi = DEPTH_TEST_ENABLED;
|
||||
alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
|
||||
cull_mode = CULL_BACK;
|
||||
cull_mode = RS::CULL_MODE_BACK;
|
||||
|
||||
uses_point_size = false;
|
||||
uses_alpha = false;
|
||||
|
|
@ -102,9 +102,9 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
|
|||
|
||||
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
|
||||
|
||||
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_mode, CULL_DISABLED);
|
||||
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_mode, CULL_FRONT);
|
||||
actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull_mode, CULL_BACK);
|
||||
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_mode, RS::CULL_MODE_DISABLED);
|
||||
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_mode, RS::CULL_MODE_FRONT);
|
||||
actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull_mode, RS::CULL_MODE_BACK);
|
||||
|
||||
actions.render_mode_flags["unshaded"] = &unshaded;
|
||||
actions.render_mode_flags["wireframe"] = &wireframe;
|
||||
|
|
|
|||
|
|
@ -141,12 +141,6 @@ public:
|
|||
DEPTH_TEST_ENABLED
|
||||
};
|
||||
|
||||
enum Cull {
|
||||
CULL_DISABLED,
|
||||
CULL_FRONT,
|
||||
CULL_BACK
|
||||
};
|
||||
|
||||
enum CullVariant {
|
||||
CULL_VARIANT_NORMAL,
|
||||
CULL_VARIANT_REVERSED,
|
||||
|
|
@ -209,7 +203,7 @@ public:
|
|||
int blend_mode = BLEND_MODE_MIX;
|
||||
int depth_testi = DEPTH_TEST_ENABLED;
|
||||
int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
|
||||
int cull_mode = CULL_BACK;
|
||||
int cull_mode = RS::CULL_MODE_BACK;
|
||||
|
||||
bool uses_point_size = false;
|
||||
bool uses_alpha = false;
|
||||
|
|
|
|||
|
|
@ -1256,21 +1256,37 @@ void fragment_shader(in SceneData scene_data) {
|
|||
#ifndef USE_SHADOW_TO_OPACITY
|
||||
|
||||
#ifdef ALPHA_SCISSOR_USED
|
||||
#ifdef MODE_RENDER_MATERIAL
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
alpha = 0.0;
|
||||
} else {
|
||||
alpha = 1.0;
|
||||
}
|
||||
#else
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
discard;
|
||||
}
|
||||
#endif // MODE_RENDER_MATERIAL
|
||||
#endif // ALPHA_SCISSOR_USED
|
||||
|
||||
// alpha hash can be used in unison with alpha antialiasing
|
||||
#ifdef ALPHA_HASH_USED
|
||||
vec3 object_pos = (inverse(read_model_matrix) * inv_view_matrix * vec4(vertex, 1.0)).xyz;
|
||||
#ifdef MODE_RENDER_MATERIAL
|
||||
if (alpha < compute_alpha_hash_threshold(object_pos, alpha_hash_scale)) {
|
||||
alpha = 0.0;
|
||||
} else {
|
||||
alpha = 1.0;
|
||||
}
|
||||
#else
|
||||
if (alpha < compute_alpha_hash_threshold(object_pos, alpha_hash_scale)) {
|
||||
discard;
|
||||
}
|
||||
#endif // MODE_RENDER_MATERIAL
|
||||
#endif // ALPHA_HASH_USED
|
||||
|
||||
// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash
|
||||
#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED)
|
||||
#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED) && !defined(MODE_RENDER_MATERIAL)
|
||||
alpha = 1.0;
|
||||
#endif
|
||||
|
||||
|
|
@ -1314,10 +1330,21 @@ void fragment_shader(in SceneData scene_data) {
|
|||
#endif
|
||||
|
||||
#ifdef ENABLE_CLIP_ALPHA
|
||||
#ifdef MODE_RENDER_MATERIAL
|
||||
if (albedo.a < 0.99) {
|
||||
// Used for doublepass and shadowmapping.
|
||||
albedo.a = 0.0;
|
||||
alpha = 0.0;
|
||||
} else {
|
||||
albedo.a = 1.0;
|
||||
alpha = 1.0;
|
||||
}
|
||||
#else
|
||||
if (albedo.a < 0.99) {
|
||||
//used for doublepass and shadowmapping
|
||||
discard;
|
||||
}
|
||||
#endif // MODE_RENDER_MATERIAL
|
||||
#endif
|
||||
|
||||
/////////////////////// FOG //////////////////////
|
||||
|
|
@ -2521,9 +2548,17 @@ void fragment_shader(in SceneData scene_data) {
|
|||
alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
|
||||
|
||||
#if defined(ALPHA_SCISSOR_USED)
|
||||
#ifdef MODE_RENDER_MATERIAL
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
alpha = 0.0;
|
||||
} else {
|
||||
alpha = 1.0;
|
||||
}
|
||||
#else
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
discard;
|
||||
}
|
||||
#endif // MODE_RENDER_MATERIAL
|
||||
#endif // ALPHA_SCISSOR_USED
|
||||
|
||||
#endif // !MODE_RENDER_DEPTH
|
||||
|
|
|
|||
|
|
@ -984,21 +984,37 @@ void main() {
|
|||
#ifndef USE_SHADOW_TO_OPACITY
|
||||
|
||||
#ifdef ALPHA_SCISSOR_USED
|
||||
#ifdef MODE_RENDER_MATERIAL
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
alpha = 0.0;
|
||||
} else {
|
||||
alpha = 1.0;
|
||||
}
|
||||
#else
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
discard;
|
||||
}
|
||||
#endif // MODE_RENDER_MATERIAL
|
||||
#endif // ALPHA_SCISSOR_USED
|
||||
|
||||
// alpha hash can be used in unison with alpha antialiasing
|
||||
#ifdef ALPHA_HASH_USED
|
||||
vec3 object_pos = (inverse(read_model_matrix) * inv_view_matrix * vec4(vertex, 1.0)).xyz;
|
||||
#ifdef MODE_RENDER_MATERIAL
|
||||
if (alpha < compute_alpha_hash_threshold(object_pos, alpha_hash_scale)) {
|
||||
alpha = 0.0;
|
||||
} else {
|
||||
alpha = 1.0;
|
||||
}
|
||||
#else
|
||||
if (alpha < compute_alpha_hash_threshold(object_pos, alpha_hash_scale)) {
|
||||
discard;
|
||||
}
|
||||
#endif // MODE_RENDER_MATERIAL
|
||||
#endif // ALPHA_HASH_USED
|
||||
|
||||
// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash
|
||||
#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED)
|
||||
#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED) && !defined(MODE_RENDER_MATERIAL)
|
||||
alpha = 1.0;
|
||||
#endif
|
||||
|
||||
|
|
@ -1042,10 +1058,21 @@ void main() {
|
|||
#endif
|
||||
|
||||
#ifdef ENABLE_CLIP_ALPHA
|
||||
#ifdef MODE_RENDER_MATERIAL
|
||||
if (albedo.a < 0.99) {
|
||||
// Used for doublepass and shadowmapping.
|
||||
albedo.a = 0.0;
|
||||
alpha = 0.0;
|
||||
} else {
|
||||
albedo.a = 1.0;
|
||||
alpha = 1.0;
|
||||
}
|
||||
#else
|
||||
if (albedo.a < 0.99) {
|
||||
//used for doublepass and shadowmapping
|
||||
discard;
|
||||
}
|
||||
#endif // MODE_RENDER_MATERIAL
|
||||
#endif
|
||||
|
||||
/////////////////////// FOG //////////////////////
|
||||
|
|
@ -1739,9 +1766,17 @@ void main() {
|
|||
alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
|
||||
|
||||
#if defined(ALPHA_SCISSOR_USED)
|
||||
#ifdef MODE_RENDER_MATERIAL
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
alpha = 0.0;
|
||||
} else {
|
||||
alpha = 1.0;
|
||||
}
|
||||
#else
|
||||
if (alpha < alpha_scissor_threshold) {
|
||||
discard;
|
||||
}
|
||||
#endif // MODE_RENDER_MATERIAL
|
||||
#endif // !ALPHA_SCISSOR_USED
|
||||
|
||||
#endif // !MODE_RENDER_DEPTH
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
#include "core/config/engine.h"
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
|
||||
#include "servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h"
|
||||
#include "servers/rendering/storage/variant_converters.h"
|
||||
#include "texture_storage.h"
|
||||
|
||||
|
|
@ -2302,6 +2304,24 @@ bool MaterialStorage::material_casts_shadows(RID p_material) {
|
|||
return true; //by default everything casts shadows
|
||||
}
|
||||
|
||||
RS::CullMode RendererRD::MaterialStorage::material_get_cull_mode(RID p_material) const {
|
||||
Material *material = material_owner.get_or_null(p_material);
|
||||
ERR_FAIL_NULL_V(material, RS::CULL_MODE_DISABLED);
|
||||
ERR_FAIL_NULL_V(material->shader, RS::CULL_MODE_DISABLED);
|
||||
if (material->shader->type == ShaderType::SHADER_TYPE_3D && material->shader->data) {
|
||||
RendererSceneRenderImplementation::SceneShaderForwardClustered::ShaderData *sd_clustered = dynamic_cast<RendererSceneRenderImplementation::SceneShaderForwardClustered::ShaderData *>(material->shader->data);
|
||||
if (sd_clustered) {
|
||||
return (RS::CullMode)sd_clustered->cull_mode;
|
||||
}
|
||||
|
||||
RendererSceneRenderImplementation::SceneShaderForwardMobile::ShaderData *sd_mobile = dynamic_cast<RendererSceneRenderImplementation::SceneShaderForwardMobile::ShaderData *>(material->shader->data);
|
||||
if (sd_mobile) {
|
||||
return (RS::CullMode)sd_mobile->cull_mode;
|
||||
}
|
||||
}
|
||||
return RS::CULL_MODE_DISABLED;
|
||||
}
|
||||
|
||||
void MaterialStorage::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) {
|
||||
Material *material = material_owner.get_or_null(p_material);
|
||||
ERR_FAIL_NULL(material);
|
||||
|
|
|
|||
|
|
@ -444,6 +444,7 @@ public:
|
|||
|
||||
virtual bool material_is_animated(RID p_material) override;
|
||||
virtual bool material_casts_shadows(RID p_material) override;
|
||||
virtual RS::CullMode material_get_cull_mode(RID p_material) const override;
|
||||
|
||||
virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ public:
|
|||
|
||||
virtual bool material_is_animated(RID p_material) = 0;
|
||||
virtual bool material_casts_shadows(RID p_material) = 0;
|
||||
virtual RS::CullMode material_get_cull_mode(RID p_material) const = 0;
|
||||
|
||||
struct InstanceShaderParam {
|
||||
PropertyInfo info;
|
||||
|
|
|
|||
|
|
@ -221,6 +221,12 @@ public:
|
|||
SHADER_MAX
|
||||
};
|
||||
|
||||
enum CullMode {
|
||||
CULL_MODE_DISABLED,
|
||||
CULL_MODE_FRONT,
|
||||
CULL_MODE_BACK,
|
||||
};
|
||||
|
||||
virtual RID shader_create() = 0;
|
||||
virtual RID shader_create_from_code(const String &p_code, const String &p_path_hint = String()) = 0;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue