mirror of
https://github.com/godotengine/godot.git
synced 2025-12-08 06:09:55 +00:00
Add stencil support for spatial materials
This commit is contained in:
parent
7574a5dbb3
commit
d674c9e289
29 changed files with 1335 additions and 141 deletions
|
|
@ -378,6 +378,24 @@
|
|||
The method for rendering the specular blob.
|
||||
[b]Note:[/b] [member specular_mode] only applies to the specular blob. It does not affect specular reflections from the sky, screen-space reflections, [VoxelGI], SDFGI or [ReflectionProbe]s. To disable reflections from these sources as well, set [member metallic_specular] to [code]0.0[/code] instead.
|
||||
</member>
|
||||
<member name="stencil_color" type="Color" setter="set_stencil_effect_color" getter="get_stencil_effect_color" default="Color(0, 0, 0, 1)" experimental="May be affected by future rendering pipeline changes.">
|
||||
The primary color of the stencil effect.
|
||||
</member>
|
||||
<member name="stencil_compare" type="int" setter="set_stencil_compare" getter="get_stencil_compare" enum="BaseMaterial3D.StencilCompare" default="0" experimental="May be affected by future rendering pipeline changes.">
|
||||
The comparison operator to use for stencil masking operations. See [enum StencilCompare].
|
||||
</member>
|
||||
<member name="stencil_flags" type="int" setter="set_stencil_flags" getter="get_stencil_flags" default="0" experimental="May be affected by future rendering pipeline changes.">
|
||||
The flags dictating how the stencil operation behaves. See [enum StencilFlags].
|
||||
</member>
|
||||
<member name="stencil_mode" type="int" setter="set_stencil_mode" getter="get_stencil_mode" enum="BaseMaterial3D.StencilMode" default="0" experimental="May be affected by future rendering pipeline changes.">
|
||||
The stencil effect mode. See [enum StencilMode].
|
||||
</member>
|
||||
<member name="stencil_outline_thickness" type="float" setter="set_stencil_effect_outline_thickness" getter="get_stencil_effect_outline_thickness" default="0.01" experimental="May be affected by future rendering pipeline changes.">
|
||||
The outline thickness for [constant STENCIL_MODE_OUTLINE].
|
||||
</member>
|
||||
<member name="stencil_reference" type="int" setter="set_stencil_reference" getter="get_stencil_reference" default="1" experimental="May be affected by future rendering pipeline changes.">
|
||||
The stencil reference value (0-255). Typically a power of 2.
|
||||
</member>
|
||||
<member name="subsurf_scatter_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
|
||||
If [code]true[/code], subsurface scattering is enabled. Emulates light that penetrates an object's surface, is scattered, and then emerges. Subsurface scattering quality is controlled by [member ProjectSettings.rendering/environment/subsurface_scattering/subsurface_scattering_quality].
|
||||
</member>
|
||||
|
|
@ -828,5 +846,49 @@
|
|||
<constant name="DISTANCE_FADE_OBJECT_DITHER" value="3" enum="DistanceFadeMode">
|
||||
Smoothly fades the object out based on the object's distance from the camera using a dithering approach. Dithering discards pixels based on a set pattern to smoothly fade without enabling transparency. On certain hardware, this can be faster than [constant DISTANCE_FADE_PIXEL_ALPHA] and [constant DISTANCE_FADE_PIXEL_DITHER].
|
||||
</constant>
|
||||
<constant name="STENCIL_MODE_DISABLED" value="0" enum="StencilMode">
|
||||
Disables stencil operations.
|
||||
</constant>
|
||||
<constant name="STENCIL_MODE_OUTLINE" value="1" enum="StencilMode">
|
||||
Stencil preset which applies an outline to the object.
|
||||
[b]Note:[/b] Requires a [member Material.next_pass] material which will be automatically applied. Any manual changes made to [member Material.next_pass] will be lost when the stencil properties are modified or the scene is reloaded. To safely apply a [member Material.next_pass] material on a material that uses stencil presets, use [member GeometryInstance3D.material_overlay] instead.
|
||||
</constant>
|
||||
<constant name="STENCIL_MODE_XRAY" value="2" enum="StencilMode">
|
||||
Stencil preset which shows a silhouette of the object behind walls.
|
||||
[b]Note:[/b] Requires a [member Material.next_pass] material which will be automatically applied. Any manual changes made to [member Material.next_pass] will be lost when the stencil properties are modified or the scene is reloaded. To safely apply a [member Material.next_pass] material on a material that uses stencil presets, use [member GeometryInstance3D.material_overlay] instead.
|
||||
</constant>
|
||||
<constant name="STENCIL_MODE_CUSTOM" value="3" enum="StencilMode">
|
||||
Enables stencil operations without a preset.
|
||||
</constant>
|
||||
<constant name="STENCIL_FLAG_READ" value="1" enum="StencilFlags">
|
||||
The material will only be rendered where it passes a stencil comparison with existing stencil buffer values. See [enum StencilCompare].
|
||||
</constant>
|
||||
<constant name="STENCIL_FLAG_WRITE" value="2" enum="StencilFlags">
|
||||
The material will write the reference value to the stencil buffer where it passes the depth test.
|
||||
</constant>
|
||||
<constant name="STENCIL_FLAG_WRITE_DEPTH_FAIL" value="4" enum="StencilFlags">
|
||||
The material will write the reference value to the stencil buffer where it fails the depth test.
|
||||
</constant>
|
||||
<constant name="STENCIL_COMPARE_ALWAYS" value="0" enum="StencilCompare">
|
||||
Always passes the stencil test.
|
||||
</constant>
|
||||
<constant name="STENCIL_COMPARE_LESS" value="1" enum="StencilCompare">
|
||||
Passes the stencil test when the reference value is less than the existing stencil value.
|
||||
</constant>
|
||||
<constant name="STENCIL_COMPARE_EQUAL" value="2" enum="StencilCompare">
|
||||
Passes the stencil test when the reference value is equal to the existing stencil value.
|
||||
</constant>
|
||||
<constant name="STENCIL_COMPARE_LESS_OR_EQUAL" value="3" enum="StencilCompare">
|
||||
Passes the stencil test when the reference value is less than or equal to the existing stencil value.
|
||||
</constant>
|
||||
<constant name="STENCIL_COMPARE_GREATER" value="4" enum="StencilCompare">
|
||||
Passes the stencil test when the reference value is greater than the existing stencil value.
|
||||
</constant>
|
||||
<constant name="STENCIL_COMPARE_NOT_EQUAL" value="5" enum="StencilCompare">
|
||||
Passes the stencil test when the reference value is not equal to the existing stencil value.
|
||||
</constant>
|
||||
<constant name="STENCIL_COMPARE_GREATER_OR_EQUAL" value="6" enum="StencilCompare">
|
||||
Passes the stencil test when the reference value is greater than or equal to the existing stencil value.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
|
|||
|
|
@ -138,6 +138,10 @@ void RasterizerGLES3::clear_depth(float p_depth) {
|
|||
#endif // GLES_API_ENABLED
|
||||
}
|
||||
|
||||
void RasterizerGLES3::clear_stencil(int32_t p_stencil) {
|
||||
glClearStencil(p_stencil);
|
||||
}
|
||||
|
||||
#ifdef CAN_DEBUG
|
||||
static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) {
|
||||
// These are ultimately annoying, so removing for now.
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ public:
|
|||
|
||||
static bool is_gles_over_gl() { return gles_over_gl; }
|
||||
static void clear_depth(float p_depth);
|
||||
static void clear_stencil(int32_t p_stencil);
|
||||
|
||||
static void make_current(bool p_gles_over_gl) {
|
||||
gles_over_gl = p_gles_over_gl;
|
||||
|
|
|
|||
|
|
@ -224,6 +224,10 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry
|
|||
flags |= GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS;
|
||||
}
|
||||
|
||||
if (p_material->shader_data->stencil_enabled) {
|
||||
flags |= GeometryInstanceSurface::FLAG_USES_STENCIL;
|
||||
}
|
||||
|
||||
if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test != GLES3::SceneShaderData::DEPTH_TEST_ENABLED) {
|
||||
//material is only meant for alpha pass
|
||||
flags |= GeometryInstanceSurface::FLAG_PASS_ALPHA;
|
||||
|
|
@ -237,6 +241,17 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry
|
|||
flags |= GeometryInstanceSurface::FLAG_PASS_SHADOW;
|
||||
}
|
||||
|
||||
if (p_material->shader_data->stencil_enabled) {
|
||||
if (p_material->shader_data->stencil_flags & GLES3::SceneShaderData::STENCIL_FLAG_READ) {
|
||||
// Stencil materials which read from the stencil buffer must be in the alpha pass.
|
||||
// This is critical to preserve compatibility once we'll have the compositor.
|
||||
if (!(flags & GeometryInstanceSurface::FLAG_PASS_ALPHA)) {
|
||||
String shader_path = p_material->shader_data->path.is_empty() ? "" : "(" + p_material->shader_data->path + ")";
|
||||
ERR_PRINT_ED(vformat("Attempting to use a shader %s that reads stencil but is not in the alpha queue. Ensure the material uses alpha blending or has depth_draw disabled or depth_test disabled.", shader_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLES3::SceneMaterialData *material_shadow = nullptr;
|
||||
void *surface_shadow = nullptr;
|
||||
if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_world_coordinates && !p_material->shader_data->wireframe) {
|
||||
|
|
@ -1234,6 +1249,7 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
|
|||
scene_state.used_screen_texture = false;
|
||||
scene_state.used_normal_texture = false;
|
||||
scene_state.used_depth_texture = false;
|
||||
scene_state.used_opaque_stencil = false;
|
||||
}
|
||||
|
||||
Plane near_plane;
|
||||
|
|
@ -1427,6 +1443,9 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
|
|||
if (surf->flags & GeometryInstanceSurface::FLAG_USES_DEPTH_TEXTURE) {
|
||||
scene_state.used_depth_texture = true;
|
||||
}
|
||||
if ((surf->flags & GeometryInstanceSurface::FLAG_USES_STENCIL) && !force_alpha && (surf->flags & (GeometryInstanceSurface::FLAG_PASS_DEPTH | GeometryInstanceSurface::FLAG_PASS_OPAQUE))) {
|
||||
scene_state.used_opaque_stencil = true;
|
||||
}
|
||||
|
||||
} else if (p_pass_mode == PASS_MODE_SHADOW) {
|
||||
if (surf->flags & GeometryInstanceSurface::FLAG_PASS_SHADOW) {
|
||||
|
|
@ -2490,6 +2509,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
// Do depth prepass if it's explicitly enabled
|
||||
bool use_depth_prepass = config->use_depth_prepass;
|
||||
|
||||
// Forcibly enable depth prepass if opaque stencil writes are used.
|
||||
use_depth_prepass = use_depth_prepass || scene_state.used_opaque_stencil;
|
||||
|
||||
// Don't do depth prepass we are rendering overdraw
|
||||
use_depth_prepass = use_depth_prepass && get_debug_draw_mode() != RS::VIEWPORT_DEBUG_DRAW_OVERDRAW;
|
||||
|
||||
|
|
@ -2506,10 +2528,13 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
scene_state.enable_gl_blend(false);
|
||||
scene_state.set_gl_depth_func(GL_GEQUAL);
|
||||
scene_state.enable_gl_scissor_test(false);
|
||||
scene_state.enable_gl_stencil_test(false);
|
||||
scene_state.set_gl_stencil_write_mask(255);
|
||||
|
||||
glColorMask(0, 0, 0, 0);
|
||||
RasterizerGLES3::clear_depth(0.0);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
RasterizerGLES3::clear_stencil(0);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
// Some desktop GL implementations fall apart when using Multiview with GL_NONE.
|
||||
GLuint db = p_camera_data->view_count > 1 ? GL_COLOR_ATTACHMENT0 : GL_NONE;
|
||||
glDrawBuffers(1, &db);
|
||||
|
|
@ -2549,9 +2574,12 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
glDrawBuffers(1, &db);
|
||||
}
|
||||
|
||||
scene_state.enable_gl_stencil_test(false);
|
||||
|
||||
if (!fb_cleared) {
|
||||
RasterizerGLES3::clear_depth(0.0);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
RasterizerGLES3::clear_stencil(0);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// Need to clear framebuffer unless:
|
||||
|
|
@ -2631,6 +2659,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
_render_list_template<PASS_MODE_COLOR>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
|
||||
|
||||
scene_state.enable_gl_depth_draw(false);
|
||||
scene_state.enable_gl_stencil_test(false);
|
||||
|
||||
if (draw_sky || draw_sky_fog_only) {
|
||||
RENDER_TIMESTAMP("Render Sky");
|
||||
|
|
@ -2689,7 +2718,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
if (scene_state.used_depth_texture) {
|
||||
glBlitFramebuffer(0, 0, size.x, size.y,
|
||||
0, 0, size.x, size.y,
|
||||
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
|
||||
glBindTexture(GL_TEXTURE_2D, backbuffer_depth);
|
||||
}
|
||||
|
|
@ -2707,6 +2736,8 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
|
||||
_render_list_template<PASS_MODE_COLOR_TRANSPARENT>(&render_list_params_alpha, &render_data, 0, render_list[RENDER_LIST_ALPHA].elements.size(), true);
|
||||
|
||||
scene_state.enable_gl_stencil_test(false);
|
||||
|
||||
if (!flip_y) {
|
||||
// Restore the default winding order.
|
||||
glFrontFace(GL_CCW);
|
||||
|
|
@ -2836,7 +2867,7 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
|
|||
// Copy depth buffer
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_int);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_rt);
|
||||
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_rt);
|
||||
|
|
@ -2865,10 +2896,10 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
|
|||
|
||||
for (uint32_t v = 0; v < view_count; v++) {
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, read_color, 0, v);
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, read_depth, 0, v);
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, read_depth, 0, v);
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, write_depth, 0, v);
|
||||
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, internal_size.x, internal_size.y, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, write_depth, 0, v);
|
||||
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, internal_size.x, internal_size.y, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2910,10 +2941,10 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
|
|||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
|
||||
|
||||
for (uint32_t v = 0; v < view_count; v++) {
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, read_depth, 0, v);
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, write_depth, 0, v);
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, read_depth, 0, v);
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, write_depth, 0, v);
|
||||
|
||||
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
glBlitFramebuffer(0, 0, internal_size.x, internal_size.y, 0, 0, target_size.x, target_size.y, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3052,6 +3083,47 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
|||
}
|
||||
}
|
||||
|
||||
// Stencil.
|
||||
if (shader->stencil_enabled) {
|
||||
static const GLenum stencil_compare_table[GLES3::SceneShaderData::STENCIL_COMPARE_MAX] = {
|
||||
GL_LESS,
|
||||
GL_EQUAL,
|
||||
GL_LEQUAL,
|
||||
GL_GREATER,
|
||||
GL_NOTEQUAL,
|
||||
GL_GEQUAL,
|
||||
GL_ALWAYS,
|
||||
};
|
||||
|
||||
GLenum stencil_compare = stencil_compare_table[shader->stencil_compare];
|
||||
GLuint stencil_compare_mask = 0;
|
||||
GLuint stencil_write_mask = 0;
|
||||
GLenum stencil_op_dpfail = GL_KEEP;
|
||||
GLenum stencil_op_dppass = GL_KEEP;
|
||||
|
||||
if (shader->stencil_flags & GLES3::SceneShaderData::STENCIL_FLAG_READ) {
|
||||
stencil_compare_mask = 255;
|
||||
}
|
||||
|
||||
if (shader->stencil_flags & GLES3::SceneShaderData::STENCIL_FLAG_WRITE) {
|
||||
stencil_op_dppass = GL_REPLACE;
|
||||
stencil_write_mask = 255;
|
||||
}
|
||||
|
||||
if (shader->stencil_flags & GLES3::SceneShaderData::STENCIL_FLAG_WRITE_DEPTH_FAIL) {
|
||||
stencil_op_dpfail = GL_REPLACE;
|
||||
stencil_write_mask = 255;
|
||||
}
|
||||
|
||||
scene_state.enable_gl_stencil_test(true);
|
||||
scene_state.set_gl_stencil_func(stencil_compare, shader->stencil_reference, stencil_compare_mask);
|
||||
scene_state.set_gl_stencil_write_mask(stencil_write_mask);
|
||||
scene_state.set_gl_stencil_op(GL_KEEP, stencil_op_dpfail, stencil_op_dppass);
|
||||
} else {
|
||||
scene_state.enable_gl_stencil_test(false);
|
||||
scene_state.set_gl_stencil_write_mask(255);
|
||||
}
|
||||
|
||||
if constexpr (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
|
||||
if (!uses_additive_lighting && pass == 1) {
|
||||
// Don't render additive passes if not using additive lighting.
|
||||
|
|
|
|||
|
|
@ -247,6 +247,7 @@ private:
|
|||
FLAG_USES_DEPTH_TEXTURE = 4096,
|
||||
FLAG_USES_NORMAL_TEXTURE = 8192,
|
||||
FLAG_USES_DOUBLE_SIDED_SHADOWS = 16384,
|
||||
FLAG_USES_STENCIL = 32768,
|
||||
};
|
||||
|
||||
union {
|
||||
|
|
@ -488,6 +489,15 @@ private:
|
|||
|
||||
glDepthFunc(GL_GEQUAL);
|
||||
current_depth_function = GL_GEQUAL;
|
||||
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
current_stencil_test_enabled = false;
|
||||
glStencilMask(255);
|
||||
current_stencil_write_mask = 255;
|
||||
glStencilFunc(GL_ALWAYS, 0, 255);
|
||||
current_stencil_compare = GL_ALWAYS;
|
||||
current_stencil_reference = 0;
|
||||
current_stencil_compare_mask = 255;
|
||||
}
|
||||
|
||||
void set_gl_cull_mode(RS::CullMode p_mode) {
|
||||
|
|
@ -552,10 +562,56 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void enable_gl_stencil_test(bool p_enabled) {
|
||||
if (current_stencil_test_enabled != p_enabled) {
|
||||
if (p_enabled) {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
} else {
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
current_stencil_test_enabled = p_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
void set_gl_stencil_func(GLenum p_compare, GLint p_reference, GLenum p_compare_mask) {
|
||||
if (current_stencil_compare != p_compare || current_stencil_reference != p_reference || current_stencil_compare_mask != p_compare_mask) {
|
||||
glStencilFunc(p_compare, p_reference, p_compare_mask);
|
||||
current_stencil_compare = p_compare;
|
||||
current_stencil_reference = p_reference;
|
||||
current_stencil_compare_mask = p_compare_mask;
|
||||
}
|
||||
}
|
||||
|
||||
void set_gl_stencil_write_mask(GLuint p_mask) {
|
||||
if (current_stencil_write_mask != p_mask) {
|
||||
glStencilMask(p_mask);
|
||||
current_stencil_write_mask = p_mask;
|
||||
}
|
||||
}
|
||||
|
||||
void set_gl_stencil_op(GLenum p_op_fail, GLenum p_op_dpfail, GLenum p_op_dppass) {
|
||||
if (current_stencil_op_fail != p_op_fail || current_stencil_op_dpfail != p_op_dpfail || current_stencil_op_dppass != p_op_dppass) {
|
||||
glStencilOp(p_op_fail, p_op_dpfail, p_op_dppass);
|
||||
current_stencil_op_fail = p_op_fail;
|
||||
current_stencil_op_dpfail = p_op_dpfail;
|
||||
current_stencil_op_dppass = p_op_dppass;
|
||||
}
|
||||
}
|
||||
|
||||
GLenum current_stencil_compare = GL_ALWAYS;
|
||||
GLuint current_stencil_compare_mask = 255;
|
||||
GLuint current_stencil_write_mask = 255;
|
||||
GLint current_stencil_reference = 0;
|
||||
GLenum current_stencil_op_fail = GL_KEEP;
|
||||
GLenum current_stencil_op_dpfail = GL_KEEP;
|
||||
GLenum current_stencil_op_dppass = GL_KEEP;
|
||||
bool current_stencil_test_enabled = false;
|
||||
|
||||
bool texscreen_copied = false;
|
||||
bool used_screen_texture = false;
|
||||
bool used_normal_texture = false;
|
||||
bool used_depth_texture = false;
|
||||
bool used_opaque_stencil = false;
|
||||
|
||||
LightData *omni_lights = nullptr;
|
||||
LightData *spot_lights = nullptr;
|
||||
|
|
|
|||
|
|
@ -2947,6 +2947,12 @@ void SceneShaderData::set_code(const String &p_code) {
|
|||
int cull_modei = RS::CULL_MODE_BACK;
|
||||
int depth_drawi = DEPTH_DRAW_OPAQUE;
|
||||
|
||||
int stencil_readi = 0;
|
||||
int stencil_writei = 0;
|
||||
int stencil_write_depth_faili = 0;
|
||||
int stencil_comparei = STENCIL_COMPARE_ALWAYS;
|
||||
int stencil_referencei = -1;
|
||||
|
||||
ShaderCompiler::IdentifierActions actions;
|
||||
actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
|
||||
actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT;
|
||||
|
|
@ -3016,6 +3022,20 @@ void SceneShaderData::set_code(const String &p_code) {
|
|||
actions.usage_flag_pointers["BONE_INDICES"] = &uses_bones;
|
||||
actions.usage_flag_pointers["BONE_WEIGHTS"] = &uses_weights;
|
||||
|
||||
actions.stencil_mode_values["read"] = Pair<int *, int>(&stencil_readi, STENCIL_FLAG_READ);
|
||||
actions.stencil_mode_values["write"] = Pair<int *, int>(&stencil_writei, STENCIL_FLAG_WRITE);
|
||||
actions.stencil_mode_values["write_depth_fail"] = Pair<int *, int>(&stencil_write_depth_faili, STENCIL_FLAG_WRITE_DEPTH_FAIL);
|
||||
|
||||
actions.stencil_mode_values["compare_less"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_LESS);
|
||||
actions.stencil_mode_values["compare_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_EQUAL);
|
||||
actions.stencil_mode_values["compare_less_or_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_LESS_OR_EQUAL);
|
||||
actions.stencil_mode_values["compare_greater"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_GREATER);
|
||||
actions.stencil_mode_values["compare_not_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_NOT_EQUAL);
|
||||
actions.stencil_mode_values["compare_greater_or_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_GREATER_OR_EQUAL);
|
||||
actions.stencil_mode_values["compare_always"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_ALWAYS);
|
||||
|
||||
actions.stencil_reference = &stencil_referencei;
|
||||
|
||||
actions.uniforms = &uniforms;
|
||||
|
||||
Error err = MaterialStorage::get_singleton()->shaders.compiler_scene.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
|
||||
|
|
@ -3056,6 +3076,11 @@ void SceneShaderData::set_code(const String &p_code) {
|
|||
uses_vertex_time = gen_code.uses_vertex_time;
|
||||
uses_fragment_time = gen_code.uses_fragment_time;
|
||||
|
||||
stencil_enabled = stencil_referencei != -1;
|
||||
stencil_flags = stencil_readi | stencil_writei | stencil_write_depth_faili;
|
||||
stencil_compare = StencilCompare(stencil_comparei);
|
||||
stencil_reference = stencil_referencei;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (uses_particle_trails) {
|
||||
WARN_PRINT_ONCE_ED("Particle trails are only available when using the Forward+ or Mobile renderers.");
|
||||
|
|
|
|||
|
|
@ -261,6 +261,23 @@ struct SceneShaderData : public ShaderData {
|
|||
DEPTH_TEST_ENABLED_INVERTED,
|
||||
};
|
||||
|
||||
enum StencilCompare {
|
||||
STENCIL_COMPARE_LESS,
|
||||
STENCIL_COMPARE_EQUAL,
|
||||
STENCIL_COMPARE_LESS_OR_EQUAL,
|
||||
STENCIL_COMPARE_GREATER,
|
||||
STENCIL_COMPARE_NOT_EQUAL,
|
||||
STENCIL_COMPARE_GREATER_OR_EQUAL,
|
||||
STENCIL_COMPARE_ALWAYS,
|
||||
STENCIL_COMPARE_MAX // not an actual operator, just the amount of operators
|
||||
};
|
||||
|
||||
enum StencilFlags {
|
||||
STENCIL_FLAG_READ = 1,
|
||||
STENCIL_FLAG_WRITE = 2,
|
||||
STENCIL_FLAG_WRITE_DEPTH_FAIL = 4,
|
||||
};
|
||||
|
||||
enum AlphaAntiAliasing {
|
||||
ALPHA_ANTIALIASING_OFF,
|
||||
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
|
||||
|
|
@ -286,6 +303,11 @@ struct SceneShaderData : public ShaderData {
|
|||
DepthTest depth_test;
|
||||
RS::CullMode cull_mode;
|
||||
|
||||
StencilCompare stencil_compare;
|
||||
uint32_t stencil_flags;
|
||||
int32_t stencil_reference;
|
||||
bool stencil_enabled;
|
||||
|
||||
bool uses_point_size;
|
||||
bool uses_alpha;
|
||||
bool uses_alpha_clip;
|
||||
|
|
|
|||
|
|
@ -63,14 +63,14 @@ void RenderSceneBuffersGLES3::_rt_attach_textures(GLuint p_color, GLuint p_depth
|
|||
if (p_samples > 1) {
|
||||
#if defined(ANDROID_ENABLED) || defined(WEB_ENABLED)
|
||||
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, p_color, 0, p_samples, 0, p_view_count);
|
||||
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, p_depth, 0, p_samples, 0, p_view_count);
|
||||
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, p_depth, 0, p_samples, 0, p_view_count);
|
||||
#else
|
||||
ERR_PRINT_ONCE("Multiview MSAA isn't supported on this platform.");
|
||||
#endif
|
||||
} else {
|
||||
#ifndef IOS_ENABLED
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, p_color, 0, 0, p_view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, p_depth, 0, 0, p_view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, p_depth, 0, 0, p_view_count);
|
||||
#else
|
||||
ERR_PRINT_ONCE("Multiview isn't supported on this platform.");
|
||||
#endif
|
||||
|
|
@ -79,13 +79,13 @@ void RenderSceneBuffersGLES3::_rt_attach_textures(GLuint p_color, GLuint p_depth
|
|||
if (p_samples > 1) {
|
||||
#ifdef ANDROID_ENABLED
|
||||
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_color, 0, p_samples);
|
||||
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, p_depth, 0, p_samples);
|
||||
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, p_depth, 0, p_samples);
|
||||
#else
|
||||
ERR_PRINT_ONCE("MSAA via EXT_multisampled_render_to_texture isn't supported on this platform.");
|
||||
#endif
|
||||
} else {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_color, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, p_depth, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, p_depth, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -196,7 +196,8 @@ void RenderSceneBuffersGLES3::_check_render_buffers() {
|
|||
ERR_FAIL_COND(view_count == 0);
|
||||
|
||||
bool use_internal_buffer = scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF || apply_color_adjustments_in_post;
|
||||
uint32_t depth_format_size = 3;
|
||||
GLenum depth_format = GL_DEPTH24_STENCIL8;
|
||||
uint32_t depth_format_size = 4;
|
||||
bool use_multiview = view_count > 1;
|
||||
|
||||
if ((!use_internal_buffer || internal3d.color != 0) && (msaa3d.mode == RS::VIEWPORT_MSAA_DISABLED || msaa3d.color != 0)) {
|
||||
|
|
@ -230,9 +231,9 @@ void RenderSceneBuffersGLES3::_check_render_buffers() {
|
|||
glBindTexture(texture_target, internal3d.depth);
|
||||
|
||||
if (use_multiview) {
|
||||
glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
glTexImage3D(texture_target, 0, depth_format, internal_size.x, internal_size.y, view_count, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
|
||||
} else {
|
||||
glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
glTexImage2D(texture_target, 0, depth_format, internal_size.x, internal_size.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
|
||||
}
|
||||
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
|
@ -250,13 +251,13 @@ void RenderSceneBuffersGLES3::_check_render_buffers() {
|
|||
#ifndef IOS_ENABLED
|
||||
if (use_multiview) {
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, internal3d.color, 0, 0, view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, internal3d.depth, 0, 0, view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, internal3d.depth, 0, 0, view_count);
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, internal3d.color, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture_target, internal3d.depth, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, texture_target, internal3d.depth, 0);
|
||||
}
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
|
|
@ -299,15 +300,15 @@ void RenderSceneBuffersGLES3::_check_render_buffers() {
|
|||
glGenRenderbuffers(1, &msaa3d.depth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, msaa3d.depth);
|
||||
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa3d.samples, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y);
|
||||
GLES3::Utilities::get_singleton()->render_buffer_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * 3 * msaa3d.samples, "MSAA 3D depth render buffer");
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa3d.samples, depth_format, internal_size.x, internal_size.y);
|
||||
GLES3::Utilities::get_singleton()->render_buffer_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size * msaa3d.samples, "MSAA 3D depth render buffer");
|
||||
|
||||
// Create our MSAA 3D FBO.
|
||||
glGenFramebuffers(1, &msaa3d.fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo);
|
||||
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaa3d.color);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msaa3d.depth);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, msaa3d.depth);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
|
|
@ -341,9 +342,9 @@ void RenderSceneBuffersGLES3::_check_render_buffers() {
|
|||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.depth);
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, GL_TRUE);
|
||||
glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, depth_format, internal_size.x, internal_size.y, view_count, GL_TRUE);
|
||||
#else
|
||||
glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, GL_TRUE);
|
||||
glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, depth_format, internal_size.x, internal_size.y, view_count, GL_TRUE);
|
||||
#endif
|
||||
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size * msaa3d.samples, "MSAA 3D depth texture");
|
||||
|
|
@ -353,7 +354,7 @@ void RenderSceneBuffersGLES3::_check_render_buffers() {
|
|||
glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo);
|
||||
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, msaa3d.color, 0, 0, view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, msaa3d.depth, 0, 0, view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, msaa3d.depth, 0, 0, view_count);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
|
|
@ -474,7 +475,8 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de
|
|||
|
||||
bool use_multiview = view_count > 1 && GLES3::Config::get_singleton()->multiview_supported;
|
||||
GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
|
||||
uint32_t depth_format_size = 3;
|
||||
GLenum depth_format = GL_DEPTH24_STENCIL8;
|
||||
uint32_t depth_format_size = 4;
|
||||
|
||||
if (backbuffer3d.color == 0 && p_need_color) {
|
||||
glGenTextures(1, &backbuffer3d.color);
|
||||
|
|
@ -509,9 +511,9 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de
|
|||
glBindTexture(texture_target, backbuffer3d.depth);
|
||||
|
||||
if (use_multiview) {
|
||||
glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
glTexImage3D(texture_target, 0, depth_format, internal_size.x, internal_size.y, view_count, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT, nullptr);
|
||||
} else {
|
||||
glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, internal_size.x, internal_size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
glTexImage2D(texture_target, 0, depth_format, internal_size.x, internal_size.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT, nullptr);
|
||||
}
|
||||
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
|
@ -523,12 +525,12 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de
|
|||
|
||||
#ifndef IOS_ENABLED
|
||||
if (use_multiview) {
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, backbuffer3d.depth, 0, 0, view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, backbuffer3d.depth, 0, 0, view_count);
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture_target, backbuffer3d.depth, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, texture_target, backbuffer3d.depth, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2183,14 +2183,15 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
|
|||
ERR_FAIL_NULL(texture);
|
||||
|
||||
rt->depth = texture->tex_id;
|
||||
rt->depth_has_stencil = rt->overridden.depth_has_stencil;
|
||||
} else {
|
||||
glGenTextures(1, &rt->depth);
|
||||
glBindTexture(texture_target, rt->depth);
|
||||
|
||||
if (use_multiview) {
|
||||
glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, rt->view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
glTexImage3D(texture_target, 0, GL_DEPTH24_STENCIL8, rt->size.x, rt->size.y, rt->view_count, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
|
||||
} else {
|
||||
glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
glTexImage2D(texture_target, 0, GL_DEPTH24_STENCIL8, rt->size.x, rt->size.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
|
||||
}
|
||||
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
|
@ -2198,16 +2199,19 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
|
|||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->depth, rt->size.x * rt->size.y * rt->view_count * 3, "Render target depth texture");
|
||||
rt->depth_has_stencil = true;
|
||||
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->depth, rt->size.x * rt->size.y * rt->view_count * 4, "Render target depth texture");
|
||||
}
|
||||
|
||||
#ifndef IOS_ENABLED
|
||||
if (use_multiview) {
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, rt->depth_has_stencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count);
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture_target, rt->depth, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, rt->depth_has_stencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT, texture_target, rt->depth, 0);
|
||||
}
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
|
|
@ -2354,12 +2358,33 @@ void GLES3::TextureStorage::check_backbuffer(RenderTarget *rt, const bool uses_s
|
|||
if (rt->backbuffer_depth == 0 && uses_depth_texture) {
|
||||
glGenTextures(1, &rt->backbuffer_depth);
|
||||
glBindTexture(texture_target, rt->backbuffer_depth);
|
||||
if (use_multiview) {
|
||||
glTexImage3D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, rt->view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
|
||||
GLint internal_format;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
GLenum attachment;
|
||||
int element_size;
|
||||
|
||||
if (rt->depth_has_stencil) {
|
||||
internal_format = GL_DEPTH24_STENCIL8;
|
||||
format = GL_DEPTH_STENCIL;
|
||||
type = GL_UNSIGNED_INT_24_8;
|
||||
attachment = GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
element_size = 4;
|
||||
} else {
|
||||
glTexImage2D(texture_target, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
internal_format = GL_DEPTH_COMPONENT24;
|
||||
format = GL_DEPTH_COMPONENT;
|
||||
type = GL_UNSIGNED_INT;
|
||||
attachment = GL_DEPTH_ATTACHMENT;
|
||||
element_size = 3;
|
||||
}
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer_depth, rt->size.x * rt->size.y * rt->view_count * 3, "Render target backbuffer depth texture");
|
||||
|
||||
if (use_multiview) {
|
||||
glTexImage3D(texture_target, 0, internal_format, rt->size.x, rt->size.y, rt->view_count, 0, format, type, nullptr);
|
||||
} else {
|
||||
glTexImage2D(texture_target, 0, internal_format, rt->size.x, rt->size.y, 0, format, type, nullptr);
|
||||
}
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(rt->backbuffer_depth, rt->size.x * rt->size.y * rt->view_count * element_size, "Render target backbuffer depth texture");
|
||||
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
|
@ -2367,12 +2392,12 @@ void GLES3::TextureStorage::check_backbuffer(RenderTarget *rt, const bool uses_s
|
|||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
#ifndef IOS_ENABLED
|
||||
if (use_multiview) {
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->backbuffer_depth, 0, 0, rt->view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment, rt->backbuffer_depth, 0, 0, rt->view_count);
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->backbuffer_depth, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, rt->backbuffer_depth, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2546,6 +2571,7 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
|
|||
|
||||
rt->overridden.color = p_color_texture;
|
||||
rt->overridden.depth = p_depth_texture;
|
||||
rt->overridden.depth_has_stencil = p_depth_texture.is_null();
|
||||
rt->overridden.is_overridden = true;
|
||||
|
||||
uint32_t hash_key = hash_murmur3_one_64(p_color_texture.get_id());
|
||||
|
|
@ -2557,6 +2583,7 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
|
|||
rt->fbo = cache->get().fbo;
|
||||
rt->color = cache->get().color;
|
||||
rt->depth = cache->get().depth;
|
||||
rt->depth_has_stencil = cache->get().depth_has_stencil;
|
||||
rt->size = cache->get().size;
|
||||
rt->texture = p_color_texture;
|
||||
return;
|
||||
|
|
@ -2568,6 +2595,7 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
|
|||
new_entry.fbo = rt->fbo;
|
||||
new_entry.color = rt->color;
|
||||
new_entry.depth = rt->depth;
|
||||
new_entry.depth_has_stencil = rt->depth_has_stencil;
|
||||
new_entry.size = rt->size;
|
||||
// Keep track of any textures we had to allocate because they weren't overridden.
|
||||
if (p_color_texture.is_null()) {
|
||||
|
|
|
|||
|
|
@ -347,6 +347,7 @@ struct RenderTarget {
|
|||
GLuint backbuffer_fbo = 0;
|
||||
GLuint backbuffer = 0;
|
||||
GLuint backbuffer_depth = 0;
|
||||
bool depth_has_stencil = true;
|
||||
|
||||
bool hdr = false; // For Compatibility this effects both 2D and 3D rendering!
|
||||
GLuint color_internal_format = GL_RGBA8;
|
||||
|
|
@ -375,6 +376,7 @@ struct RenderTarget {
|
|||
|
||||
struct RTOverridden {
|
||||
bool is_overridden = false;
|
||||
bool depth_has_stencil = false;
|
||||
RID color;
|
||||
RID depth;
|
||||
RID velocity;
|
||||
|
|
@ -385,6 +387,7 @@ struct RenderTarget {
|
|||
GLuint depth;
|
||||
Size2i size;
|
||||
Vector<GLuint> allocated_textures;
|
||||
bool depth_has_stencil;
|
||||
};
|
||||
RBMap<uint32_t, FBOCacheEntry> fbo_cache;
|
||||
} overridden;
|
||||
|
|
|
|||
|
|
@ -269,20 +269,34 @@ void ShaderTextEditor::_load_theme_settings() {
|
|||
}
|
||||
}
|
||||
|
||||
const Vector<ShaderLanguage::ModeInfo> &modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(i));
|
||||
|
||||
for (int j = 0; j < modes.size(); j++) {
|
||||
const ShaderLanguage::ModeInfo &mode_info = modes[j];
|
||||
{
|
||||
const Vector<ShaderLanguage::ModeInfo> &render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(i));
|
||||
|
||||
for (const ShaderLanguage::ModeInfo &mode_info : render_modes) {
|
||||
if (!mode_info.options.is_empty()) {
|
||||
for (int k = 0; k < mode_info.options.size(); k++) {
|
||||
built_ins.push_back(String(mode_info.name) + "_" + String(mode_info.options[k]));
|
||||
for (const StringName &option : mode_info.options) {
|
||||
built_ins.push_back(String(mode_info.name) + "_" + String(option));
|
||||
}
|
||||
} else {
|
||||
built_ins.push_back(String(mode_info.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const Vector<ShaderLanguage::ModeInfo> &stencil_modes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(i));
|
||||
|
||||
for (const ShaderLanguage::ModeInfo &mode_info : stencil_modes) {
|
||||
if (!mode_info.options.is_empty()) {
|
||||
for (const StringName &option : mode_info.options) {
|
||||
built_ins.push_back(String(mode_info.name) + "_" + String(option));
|
||||
}
|
||||
} else {
|
||||
built_ins.push_back(String(mode_info.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (shader.is_valid()) {
|
||||
for (const KeyValue<StringName, ShaderLanguage::FunctionInfo> &E : ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode()))) {
|
||||
for (const KeyValue<StringName, ShaderLanguage::BuiltInInfo> &F : E.value.built_ins) {
|
||||
|
|
@ -290,14 +304,13 @@ void ShaderTextEditor::_load_theme_settings() {
|
|||
}
|
||||
}
|
||||
|
||||
const Vector<ShaderLanguage::ModeInfo> &modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()));
|
||||
|
||||
for (int i = 0; i < modes.size(); i++) {
|
||||
const ShaderLanguage::ModeInfo &mode_info = modes[i];
|
||||
{
|
||||
const Vector<ShaderLanguage::ModeInfo> &shader_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()));
|
||||
|
||||
for (const ShaderLanguage::ModeInfo &mode_info : shader_modes) {
|
||||
if (!mode_info.options.is_empty()) {
|
||||
for (int j = 0; j < mode_info.options.size(); j++) {
|
||||
built_ins.push_back(String(mode_info.name) + "_" + String(mode_info.options[j]));
|
||||
for (const StringName &option : mode_info.options) {
|
||||
built_ins.push_back(String(mode_info.name) + "_" + String(option));
|
||||
}
|
||||
} else {
|
||||
built_ins.push_back(String(mode_info.name));
|
||||
|
|
@ -305,6 +318,21 @@ void ShaderTextEditor::_load_theme_settings() {
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
const Vector<ShaderLanguage::ModeInfo> &stencil_modes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(shader->get_mode()));
|
||||
|
||||
for (const ShaderLanguage::ModeInfo &mode_info : stencil_modes) {
|
||||
if (!mode_info.options.is_empty()) {
|
||||
for (const StringName &option : mode_info.options) {
|
||||
built_ins.push_back(String(mode_info.name) + "_" + String(option));
|
||||
}
|
||||
} else {
|
||||
built_ins.push_back(String(mode_info.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Color user_type_color = EDITOR_GET("text_editor/theme/highlighting/user_type_color");
|
||||
|
||||
for (const String &E : built_ins) {
|
||||
|
|
@ -437,6 +465,7 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptLa
|
|||
_check_shader_mode();
|
||||
comp_info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode()));
|
||||
comp_info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()));
|
||||
comp_info.stencil_modes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(shader->get_mode()));
|
||||
comp_info.shader_types = ShaderTypes::get_singleton()->get_types();
|
||||
|
||||
sl.complete(code, comp_info, r_options, calltip);
|
||||
|
|
@ -541,6 +570,7 @@ void ShaderTextEditor::_validate_script() {
|
|||
Shader::Mode mode = shader->get_mode();
|
||||
comp_info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(mode));
|
||||
comp_info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(mode));
|
||||
comp_info.stencil_modes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(mode));
|
||||
comp_info.shader_types = ShaderTypes::get_singleton()->get_types();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6297,6 +6297,7 @@ void VisualShaderEditor::_update_preview() {
|
|||
ShaderLanguage::ShaderCompileInfo info;
|
||||
info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode()));
|
||||
info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode()));
|
||||
info.stencil_modes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(visual_shader->get_mode()));
|
||||
info.shader_types = ShaderTypes::get_singleton()->get_types();
|
||||
info.global_shader_uniform_type_func = _visual_shader_editor_get_global_shader_uniform_type;
|
||||
|
||||
|
|
|
|||
|
|
@ -912,6 +912,56 @@ void BaseMaterial3D::_update_shader() {
|
|||
|
||||
code += ";\n";
|
||||
|
||||
if (stencil_mode != STENCIL_MODE_DISABLED && stencil_flags != 0) {
|
||||
code += "stencil_mode ";
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_READ) {
|
||||
code += "read";
|
||||
}
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_WRITE) {
|
||||
if (stencil_flags & STENCIL_FLAG_READ) {
|
||||
code += ", ";
|
||||
}
|
||||
code += "write";
|
||||
}
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_WRITE_DEPTH_FAIL) {
|
||||
if (stencil_flags & (STENCIL_FLAG_READ | STENCIL_FLAG_WRITE)) {
|
||||
code += ", ";
|
||||
}
|
||||
code += "write_depth_fail";
|
||||
}
|
||||
|
||||
switch (stencil_compare) {
|
||||
case STENCIL_COMPARE_ALWAYS:
|
||||
code += ", compare_always";
|
||||
break;
|
||||
case STENCIL_COMPARE_LESS:
|
||||
code += ", compare_less";
|
||||
break;
|
||||
case STENCIL_COMPARE_EQUAL:
|
||||
code += ", compare_equal";
|
||||
break;
|
||||
case STENCIL_COMPARE_LESS_OR_EQUAL:
|
||||
code += ", compare_less_or_equal";
|
||||
break;
|
||||
case STENCIL_COMPARE_GREATER:
|
||||
code += ", compare_greater";
|
||||
break;
|
||||
case STENCIL_COMPARE_NOT_EQUAL:
|
||||
code += ", compare_not_equal";
|
||||
break;
|
||||
case STENCIL_COMPARE_GREATER_OR_EQUAL:
|
||||
code += ", compare_greater_or_equal";
|
||||
break;
|
||||
case STENCIL_COMPARE_MAX:
|
||||
break;
|
||||
}
|
||||
|
||||
code += vformat(", %s;\n", stencil_reference);
|
||||
}
|
||||
|
||||
// Generate list of uniforms.
|
||||
code += vformat(R"(
|
||||
uniform vec4 albedo : source_color;
|
||||
|
|
@ -2591,7 +2641,23 @@ void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const {
|
|||
}
|
||||
|
||||
if (p_property.name == "depth_test" && flags[FLAG_DISABLE_DEPTH_TEST]) {
|
||||
p_property.usage = PROPERTY_USAGE_NONE;
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
if (p_property.name == "stencil_reference" && stencil_mode == STENCIL_MODE_DISABLED) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
if ((p_property.name == "stencil_flags" || p_property.name == "stencil_compare") && stencil_mode != STENCIL_MODE_CUSTOM) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
if (p_property.name == "stencil_color" && stencil_mode != STENCIL_MODE_OUTLINE && stencil_mode != STENCIL_MODE_XRAY) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
if (p_property.name == "stencil_outline_thickness" && stencil_mode != STENCIL_MODE_OUTLINE) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (p_property.name == "subsurf_scatter_transmittance_color" || p_property.name == "subsurf_scatter_transmittance_texture")) {
|
||||
|
|
@ -3066,6 +3132,179 @@ RID BaseMaterial3D::get_rid() const {
|
|||
return _get_material();
|
||||
}
|
||||
|
||||
void BaseMaterial3D::_prepare_stencil_effect() {
|
||||
const Ref<Material> current_next_pass = get_next_pass();
|
||||
|
||||
if (stencil_mode == STENCIL_MODE_DISABLED || stencil_mode == STENCIL_MODE_CUSTOM) {
|
||||
if (current_next_pass.is_valid() && current_next_pass->has_meta("_stencil_owned")) {
|
||||
set_next_pass(current_next_pass->get_next_pass());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<BaseMaterial3D> stencil_next_pass;
|
||||
|
||||
if (current_next_pass.is_null() || !current_next_pass->has_meta("_stencil_owned")) {
|
||||
stencil_next_pass = Ref<BaseMaterial3D>(memnew(StandardMaterial3D));
|
||||
stencil_next_pass->set_meta("_stencil_owned", true);
|
||||
stencil_next_pass->set_next_pass(current_next_pass);
|
||||
set_next_pass(stencil_next_pass);
|
||||
} else {
|
||||
stencil_next_pass = current_next_pass;
|
||||
}
|
||||
|
||||
switch (stencil_mode) {
|
||||
case STENCIL_MODE_DISABLED:
|
||||
break;
|
||||
case STENCIL_MODE_OUTLINE:
|
||||
set_stencil_flags(STENCIL_FLAG_WRITE);
|
||||
set_stencil_compare(STENCIL_COMPARE_ALWAYS);
|
||||
stencil_next_pass->set_render_priority(-1);
|
||||
stencil_next_pass->set_shading_mode(SHADING_MODE_UNSHADED);
|
||||
stencil_next_pass->set_transparency(TRANSPARENCY_ALPHA);
|
||||
stencil_next_pass->set_flag(FLAG_DISABLE_DEPTH_TEST, false);
|
||||
stencil_next_pass->set_grow_enabled(true);
|
||||
stencil_next_pass->set_grow(stencil_effect_outline_thickness);
|
||||
stencil_next_pass->set_albedo(stencil_effect_color);
|
||||
stencil_next_pass->set_stencil_mode(STENCIL_MODE_CUSTOM);
|
||||
stencil_next_pass->set_stencil_flags(STENCIL_FLAG_READ | STENCIL_FLAG_WRITE);
|
||||
stencil_next_pass->set_stencil_compare(STENCIL_COMPARE_NOT_EQUAL);
|
||||
stencil_next_pass->set_stencil_reference(stencil_reference);
|
||||
break;
|
||||
case STENCIL_MODE_XRAY:
|
||||
set_stencil_flags(STENCIL_FLAG_WRITE);
|
||||
set_stencil_compare(STENCIL_COMPARE_ALWAYS);
|
||||
stencil_next_pass->set_render_priority(-1);
|
||||
stencil_next_pass->set_shading_mode(SHADING_MODE_UNSHADED);
|
||||
stencil_next_pass->set_transparency(TRANSPARENCY_ALPHA);
|
||||
stencil_next_pass->set_flag(FLAG_DISABLE_DEPTH_TEST, true);
|
||||
stencil_next_pass->set_grow_enabled(false);
|
||||
stencil_next_pass->set_grow(0);
|
||||
stencil_next_pass->set_albedo(stencil_effect_color);
|
||||
stencil_next_pass->set_stencil_mode(STENCIL_MODE_CUSTOM);
|
||||
stencil_next_pass->set_stencil_flags(STENCIL_FLAG_READ | STENCIL_FLAG_WRITE);
|
||||
stencil_next_pass->set_stencil_compare(STENCIL_COMPARE_NOT_EQUAL);
|
||||
stencil_next_pass->set_stencil_reference(stencil_reference);
|
||||
break;
|
||||
case STENCIL_MODE_CUSTOM:
|
||||
break;
|
||||
case STENCIL_MODE_MAX:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<BaseMaterial3D> BaseMaterial3D::_get_stencil_next_pass() const {
|
||||
const Ref<Material> current_next_pass = get_next_pass();
|
||||
Ref<BaseMaterial3D> stencil_next_pass;
|
||||
|
||||
if (current_next_pass.is_valid() && current_next_pass->has_meta("_stencil_owned")) {
|
||||
stencil_next_pass = current_next_pass;
|
||||
}
|
||||
|
||||
return stencil_next_pass;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_mode(StencilMode p_stencil_mode) {
|
||||
if (stencil_mode == p_stencil_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
stencil_mode = p_stencil_mode;
|
||||
_prepare_stencil_effect();
|
||||
_queue_shader_change();
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
BaseMaterial3D::StencilMode BaseMaterial3D::get_stencil_mode() const {
|
||||
return stencil_mode;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_flags(int p_stencil_flags) {
|
||||
if (stencil_flags == p_stencil_flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((p_stencil_flags & STENCIL_FLAG_READ) && (stencil_flags & (STENCIL_FLAG_WRITE | STENCIL_FLAG_WRITE_DEPTH_FAIL))) {
|
||||
p_stencil_flags = p_stencil_flags & STENCIL_FLAG_READ;
|
||||
}
|
||||
|
||||
if ((p_stencil_flags & (STENCIL_FLAG_WRITE | STENCIL_FLAG_WRITE_DEPTH_FAIL)) && (stencil_flags & STENCIL_FLAG_READ)) {
|
||||
p_stencil_flags = p_stencil_flags & (STENCIL_FLAG_WRITE | STENCIL_FLAG_WRITE_DEPTH_FAIL);
|
||||
}
|
||||
|
||||
stencil_flags = p_stencil_flags;
|
||||
_queue_shader_change();
|
||||
}
|
||||
|
||||
int BaseMaterial3D::get_stencil_flags() const {
|
||||
return stencil_flags;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_compare(BaseMaterial3D::StencilCompare p_op) {
|
||||
if (stencil_compare == p_op) {
|
||||
return;
|
||||
}
|
||||
|
||||
stencil_compare = p_op;
|
||||
_queue_shader_change();
|
||||
}
|
||||
|
||||
BaseMaterial3D::StencilCompare BaseMaterial3D::get_stencil_compare() const {
|
||||
return stencil_compare;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_reference(int p_reference) {
|
||||
if (stencil_reference == p_reference) {
|
||||
return;
|
||||
}
|
||||
|
||||
stencil_reference = p_reference;
|
||||
_queue_shader_change();
|
||||
|
||||
Ref<BaseMaterial3D> stencil_next_pass = _get_stencil_next_pass();
|
||||
if (stencil_next_pass.is_valid()) {
|
||||
stencil_next_pass->set_stencil_reference(p_reference);
|
||||
}
|
||||
}
|
||||
|
||||
int BaseMaterial3D::get_stencil_reference() const {
|
||||
return stencil_reference;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_effect_color(const Color &p_color) {
|
||||
if (stencil_effect_color == p_color) {
|
||||
return;
|
||||
}
|
||||
|
||||
stencil_effect_color = p_color;
|
||||
|
||||
Ref<BaseMaterial3D> stencil_next_pass = _get_stencil_next_pass();
|
||||
if (stencil_next_pass.is_valid()) {
|
||||
stencil_next_pass->set_albedo(p_color);
|
||||
}
|
||||
}
|
||||
|
||||
Color BaseMaterial3D::get_stencil_effect_color() const {
|
||||
return stencil_effect_color;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_effect_outline_thickness(float p_outline_thickness) {
|
||||
if (stencil_effect_outline_thickness == p_outline_thickness) {
|
||||
return;
|
||||
}
|
||||
|
||||
stencil_effect_outline_thickness = p_outline_thickness;
|
||||
|
||||
Ref<BaseMaterial3D> stencil_next_pass = _get_stencil_next_pass();
|
||||
if (stencil_next_pass.is_valid()) {
|
||||
stencil_next_pass->set_grow(p_outline_thickness);
|
||||
}
|
||||
}
|
||||
|
||||
float BaseMaterial3D::get_stencil_effect_outline_thickness() const {
|
||||
return stencil_effect_outline_thickness;
|
||||
}
|
||||
|
||||
RID BaseMaterial3D::get_shader_rid() const {
|
||||
const_cast<BaseMaterial3D *>(this)->_update_shader();
|
||||
return shader_rid;
|
||||
|
|
@ -3291,6 +3530,24 @@ void BaseMaterial3D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_fov_override", "scale"), &BaseMaterial3D::set_fov_override);
|
||||
ClassDB::bind_method(D_METHOD("get_fov_override"), &BaseMaterial3D::get_fov_override);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_mode", "stencil_mode"), &BaseMaterial3D::set_stencil_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_mode"), &BaseMaterial3D::get_stencil_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_flags", "stencil_flags"), &BaseMaterial3D::set_stencil_flags);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_flags"), &BaseMaterial3D::get_stencil_flags);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_compare", "stencil_compare"), &BaseMaterial3D::set_stencil_compare);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_compare"), &BaseMaterial3D::get_stencil_compare);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_reference", "stencil_reference"), &BaseMaterial3D::set_stencil_reference);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_reference"), &BaseMaterial3D::get_stencil_reference);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_effect_color", "stencil_color"), &BaseMaterial3D::set_stencil_effect_color);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_effect_color"), &BaseMaterial3D::get_stencil_effect_color);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_effect_outline_thickness", "stencil_outline_thickness"), &BaseMaterial3D::set_stencil_effect_outline_thickness);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_effect_outline_thickness"), &BaseMaterial3D::get_stencil_effect_outline_thickness);
|
||||
|
||||
ADD_GROUP("Transparency", "");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,Alpha Scissor,Alpha Hash,Depth Pre-Pass"), "set_transparency", "get_transparency");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
|
||||
|
|
@ -3478,6 +3735,15 @@ void BaseMaterial3D::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_distance_fade_min_distance", "get_distance_fade_min_distance");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_distance_fade_max_distance", "get_distance_fade_max_distance");
|
||||
|
||||
ADD_GROUP("Stencil", "stencil_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "stencil_mode", PROPERTY_HINT_ENUM, "Disabled,Outline,X-Ray,Custom"), "set_stencil_mode", "get_stencil_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "stencil_flags", PROPERTY_HINT_FLAGS, "Read,Write,Write Depth Fail"), "set_stencil_flags", "get_stencil_flags");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "stencil_compare", PROPERTY_HINT_ENUM, "Always,Less,Equal,Less Or Equal,Greater,Not Equal,Greater Or Equal"), "set_stencil_compare", "get_stencil_compare");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "stencil_reference", PROPERTY_HINT_RANGE, "0,255,1"), "set_stencil_reference", "get_stencil_reference");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "stencil_color", PROPERTY_HINT_NONE), "set_stencil_effect_color", "get_stencil_effect_color");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stencil_outline_thickness", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,suffix:m"), "set_stencil_effect_outline_thickness", "get_stencil_effect_outline_thickness");
|
||||
|
||||
BIND_ENUM_CONSTANT(TEXTURE_ALBEDO);
|
||||
BIND_ENUM_CONSTANT(TEXTURE_METALLIC);
|
||||
BIND_ENUM_CONSTANT(TEXTURE_ROUGHNESS);
|
||||
|
|
@ -3612,6 +3878,23 @@ void BaseMaterial3D::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(DISTANCE_FADE_PIXEL_ALPHA);
|
||||
BIND_ENUM_CONSTANT(DISTANCE_FADE_PIXEL_DITHER);
|
||||
BIND_ENUM_CONSTANT(DISTANCE_FADE_OBJECT_DITHER);
|
||||
|
||||
BIND_ENUM_CONSTANT(STENCIL_MODE_DISABLED);
|
||||
BIND_ENUM_CONSTANT(STENCIL_MODE_OUTLINE);
|
||||
BIND_ENUM_CONSTANT(STENCIL_MODE_XRAY);
|
||||
BIND_ENUM_CONSTANT(STENCIL_MODE_CUSTOM);
|
||||
|
||||
BIND_ENUM_CONSTANT(STENCIL_FLAG_READ);
|
||||
BIND_ENUM_CONSTANT(STENCIL_FLAG_WRITE);
|
||||
BIND_ENUM_CONSTANT(STENCIL_FLAG_WRITE_DEPTH_FAIL);
|
||||
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_ALWAYS);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_LESS);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_EQUAL);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_LESS_OR_EQUAL);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_GREATER);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_NOT_EQUAL);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_GREATER_OR_EQUAL);
|
||||
}
|
||||
|
||||
BaseMaterial3D::BaseMaterial3D(bool p_orm) :
|
||||
|
|
@ -3680,6 +3963,8 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
|
|||
set_z_clip_scale(1.0);
|
||||
set_fov_override(75.0);
|
||||
|
||||
set_stencil_mode(STENCIL_MODE_DISABLED);
|
||||
|
||||
flags[FLAG_ALBEDO_TEXTURE_MSDF] = false;
|
||||
flags[FLAG_USE_TEXTURE_REPEAT] = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -326,6 +326,33 @@ public:
|
|||
DISTANCE_FADE_MAX
|
||||
};
|
||||
|
||||
enum StencilMode {
|
||||
STENCIL_MODE_DISABLED,
|
||||
STENCIL_MODE_OUTLINE,
|
||||
STENCIL_MODE_XRAY,
|
||||
STENCIL_MODE_CUSTOM,
|
||||
STENCIL_MODE_MAX // Not an actual mode, just the amount of modes.
|
||||
};
|
||||
|
||||
enum StencilFlags {
|
||||
STENCIL_FLAG_READ = 1,
|
||||
STENCIL_FLAG_WRITE = 2,
|
||||
STENCIL_FLAG_WRITE_DEPTH_FAIL = 4,
|
||||
|
||||
STENCIL_FLAG_NUM_BITS = 3 // Not an actual mode, just the amount of bits.
|
||||
};
|
||||
|
||||
enum StencilCompare {
|
||||
STENCIL_COMPARE_ALWAYS,
|
||||
STENCIL_COMPARE_LESS,
|
||||
STENCIL_COMPARE_EQUAL,
|
||||
STENCIL_COMPARE_LESS_OR_EQUAL,
|
||||
STENCIL_COMPARE_GREATER,
|
||||
STENCIL_COMPARE_NOT_EQUAL,
|
||||
STENCIL_COMPARE_GREATER_OR_EQUAL,
|
||||
STENCIL_COMPARE_MAX // Not an actual operator, just the amount of operators.
|
||||
};
|
||||
|
||||
private:
|
||||
struct MaterialKey {
|
||||
// enum values
|
||||
|
|
@ -345,6 +372,13 @@ private:
|
|||
uint64_t roughness_channel : get_num_bits(TEXTURE_CHANNEL_MAX - 1);
|
||||
uint64_t emission_op : get_num_bits(EMISSION_OP_MAX - 1);
|
||||
uint64_t distance_fade : get_num_bits(DISTANCE_FADE_MAX - 1);
|
||||
|
||||
// stencil
|
||||
uint64_t stencil_mode : get_num_bits(STENCIL_MODE_MAX - 1);
|
||||
uint64_t stencil_flags : STENCIL_FLAG_NUM_BITS;
|
||||
uint64_t stencil_compare : get_num_bits(STENCIL_COMPARE_MAX - 1);
|
||||
uint64_t stencil_reference : 8;
|
||||
|
||||
// booleans
|
||||
uint64_t invalid_key : 1;
|
||||
uint64_t deep_parallax : 1;
|
||||
|
|
@ -406,6 +440,11 @@ private:
|
|||
mk.alpha_antialiasing_mode = alpha_antialiasing_mode;
|
||||
mk.orm = orm;
|
||||
|
||||
mk.stencil_mode = stencil_mode;
|
||||
mk.stencil_flags = stencil_flags;
|
||||
mk.stencil_compare = stencil_compare;
|
||||
mk.stencil_reference = stencil_reference;
|
||||
|
||||
for (int i = 0; i < FEATURE_MAX; i++) {
|
||||
if (features[i]) {
|
||||
mk.feature_mask |= ((uint64_t)1 << i);
|
||||
|
|
@ -579,10 +618,21 @@ private:
|
|||
float z_clip_scale = 1.0;
|
||||
float fov_override = 75.0;
|
||||
|
||||
StencilMode stencil_mode = STENCIL_MODE_DISABLED;
|
||||
int stencil_flags = 0;
|
||||
StencilCompare stencil_compare = STENCIL_COMPARE_ALWAYS;
|
||||
int stencil_reference = 1;
|
||||
|
||||
Color stencil_effect_color;
|
||||
float stencil_effect_outline_thickness = 0.01f;
|
||||
|
||||
bool features[FEATURE_MAX] = {};
|
||||
|
||||
Ref<Texture2D> textures[TEXTURE_MAX];
|
||||
|
||||
void _prepare_stencil_effect();
|
||||
Ref<BaseMaterial3D> _get_stencil_next_pass() const;
|
||||
|
||||
static HashMap<uint64_t, Ref<StandardMaterial3D>> materials_for_2d; //used by Sprite3D, Label3D and other stuff
|
||||
|
||||
protected:
|
||||
|
|
@ -790,6 +840,24 @@ public:
|
|||
void set_emission_operator(EmissionOperator p_op);
|
||||
EmissionOperator get_emission_operator() const;
|
||||
|
||||
void set_stencil_mode(StencilMode p_stencil_mode);
|
||||
StencilMode get_stencil_mode() const;
|
||||
|
||||
void set_stencil_flags(int p_stencil_flags);
|
||||
int get_stencil_flags() const;
|
||||
|
||||
void set_stencil_compare(StencilCompare p_op);
|
||||
StencilCompare get_stencil_compare() const;
|
||||
|
||||
void set_stencil_reference(int p_reference);
|
||||
int get_stencil_reference() const;
|
||||
|
||||
void set_stencil_effect_color(const Color &p_color);
|
||||
Color get_stencil_effect_color() const;
|
||||
|
||||
void set_stencil_effect_outline_thickness(float p_outline_thickness);
|
||||
float get_stencil_effect_outline_thickness() const;
|
||||
|
||||
void set_metallic_texture_channel(TextureChannel p_channel);
|
||||
TextureChannel get_metallic_texture_channel() const;
|
||||
void set_roughness_texture_channel(TextureChannel p_channel);
|
||||
|
|
@ -837,6 +905,9 @@ VARIANT_ENUM_CAST(BaseMaterial3D::BillboardMode)
|
|||
VARIANT_ENUM_CAST(BaseMaterial3D::TextureChannel)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::EmissionOperator)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::DistanceFadeMode)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::StencilMode)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::StencilFlags)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::StencilCompare)
|
||||
|
||||
class StandardMaterial3D : public BaseMaterial3D {
|
||||
GDCLASS(StandardMaterial3D, BaseMaterial3D)
|
||||
|
|
|
|||
|
|
@ -1715,6 +1715,41 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
|
|||
}
|
||||
_queue_update();
|
||||
return true;
|
||||
} else if (prop_name == "stencil/enabled") {
|
||||
stencil_enabled = bool(p_value);
|
||||
_queue_update();
|
||||
notify_property_list_changed();
|
||||
return true;
|
||||
} else if (prop_name == "stencil/reference") {
|
||||
stencil_reference = int(p_value);
|
||||
_queue_update();
|
||||
return true;
|
||||
} else if (prop_name.begins_with("stencil_flags/")) {
|
||||
StringName flag = prop_name.get_slicec('/', 1);
|
||||
bool enable = p_value;
|
||||
if (enable) {
|
||||
stencil_flags.insert(flag);
|
||||
if (flag == "read") {
|
||||
stencil_flags.erase("write");
|
||||
stencil_flags.erase("write_depth_fail");
|
||||
} else if (flag == "write" || flag == "write_depth_fail") {
|
||||
stencil_flags.erase("read");
|
||||
}
|
||||
} else {
|
||||
stencil_flags.erase(flag);
|
||||
}
|
||||
_queue_update();
|
||||
return true;
|
||||
} else if (prop_name.begins_with("stencil_modes/")) {
|
||||
String mode_name = prop_name.get_slicec('/', 1);
|
||||
int value = p_value;
|
||||
if (value == 0) {
|
||||
stencil_modes.erase(mode_name); // It's default anyway, so don't store it.
|
||||
} else {
|
||||
stencil_modes[mode_name] = value;
|
||||
}
|
||||
_queue_update();
|
||||
return true;
|
||||
} else if (prop_name.begins_with("varyings/")) {
|
||||
String var_name = prop_name.get_slicec('/', 1);
|
||||
Varying value = Varying();
|
||||
|
|
@ -1798,6 +1833,24 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
|
|||
r_ret = 0;
|
||||
}
|
||||
return true;
|
||||
} else if (prop_name == "stencil/enabled") {
|
||||
r_ret = stencil_enabled;
|
||||
return true;
|
||||
} else if (prop_name == "stencil/reference") {
|
||||
r_ret = stencil_reference;
|
||||
return true;
|
||||
} else if (prop_name.begins_with("stencil_flags/")) {
|
||||
StringName flag = prop_name.get_slicec('/', 1);
|
||||
r_ret = stencil_flags.has(flag);
|
||||
return true;
|
||||
} else if (prop_name.begins_with("stencil_modes/")) {
|
||||
String mode_name = prop_name.get_slicec('/', 1);
|
||||
if (stencil_modes.has(mode_name)) {
|
||||
r_ret = stencil_modes[mode_name];
|
||||
} else {
|
||||
r_ret = 0;
|
||||
}
|
||||
return true;
|
||||
} else if (prop_name.begins_with("varyings/")) {
|
||||
String var_name = prop_name.get_slicec('/', 1);
|
||||
if (varyings.has(var_name)) {
|
||||
|
|
@ -1934,6 +1987,45 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
|
|||
p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("flags"), E)));
|
||||
}
|
||||
|
||||
const Vector<ShaderLanguage::ModeInfo> &smodes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(shader_mode));
|
||||
|
||||
if (smodes.size() > 0) {
|
||||
p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("stencil"), PNAME("enabled"))));
|
||||
|
||||
uint32_t stencil_prop_usage = stencil_enabled ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_STORAGE;
|
||||
|
||||
p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%s", PNAME("stencil"), PNAME("reference")), PROPERTY_HINT_RANGE, "0,255,1", stencil_prop_usage));
|
||||
|
||||
HashMap<String, String> stencil_enums;
|
||||
HashSet<String> stencil_toggles;
|
||||
|
||||
for (const ShaderLanguage::ModeInfo &info : smodes) {
|
||||
if (!info.options.is_empty()) {
|
||||
const String begin = String(info.name);
|
||||
|
||||
for (int j = 0; j < info.options.size(); j++) {
|
||||
const String option = String(info.options[j]).capitalize();
|
||||
|
||||
if (!stencil_enums.has(begin)) {
|
||||
stencil_enums[begin] = option;
|
||||
} else {
|
||||
stencil_enums[begin] += "," + option;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stencil_toggles.insert(String(info.name));
|
||||
}
|
||||
}
|
||||
|
||||
for (const KeyValue<String, String> &E : stencil_enums) {
|
||||
p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%s", PNAME("stencil_modes"), E.key), PROPERTY_HINT_ENUM, E.value, stencil_prop_usage));
|
||||
}
|
||||
|
||||
for (const String &E : stencil_toggles) {
|
||||
p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("stencil_flags"), E), PROPERTY_HINT_NONE, "", stencil_prop_usage));
|
||||
}
|
||||
}
|
||||
|
||||
for (const KeyValue<String, Varying> &E : varyings) {
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, vformat("%s/%s", "varyings", E.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
}
|
||||
|
|
@ -2621,6 +2713,46 @@ void VisualShader::_update_shader() const {
|
|||
global_code += "render_mode " + render_mode + ";\n\n";
|
||||
}
|
||||
|
||||
const Vector<ShaderLanguage::ModeInfo> &smodes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(shader_mode));
|
||||
|
||||
if (stencil_enabled && smodes.size() > 0 && (stencil_flags.has("read") || stencil_flags.has("write") || stencil_flags.has("write_depth_fail"))) {
|
||||
String stencil_mode;
|
||||
|
||||
Vector<String> flag_names;
|
||||
|
||||
// Add enum modes first.
|
||||
for (const ShaderLanguage::ModeInfo &info : smodes) {
|
||||
const String temp = String(info.name);
|
||||
|
||||
if (!info.options.is_empty()) {
|
||||
if (stencil_modes.has(temp) && stencil_modes[temp] < info.options.size()) {
|
||||
if (!stencil_mode.is_empty()) {
|
||||
stencil_mode += ", ";
|
||||
}
|
||||
stencil_mode += temp + "_" + info.options[stencil_modes[temp]];
|
||||
}
|
||||
} else if (stencil_flags.has(temp)) {
|
||||
flag_names.push_back(temp);
|
||||
}
|
||||
}
|
||||
|
||||
// Add flags afterward.
|
||||
for (const String &flag_name : flag_names) {
|
||||
if (!stencil_mode.is_empty()) {
|
||||
stencil_mode += ", ";
|
||||
}
|
||||
stencil_mode += flag_name;
|
||||
}
|
||||
|
||||
// Add reference value.
|
||||
if (!stencil_mode.is_empty()) {
|
||||
stencil_mode += ", ";
|
||||
}
|
||||
stencil_mode += itos(stencil_reference);
|
||||
|
||||
global_code += "stencil_mode " + stencil_mode + ";\n\n";
|
||||
}
|
||||
|
||||
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" };
|
||||
|
||||
String global_expressions;
|
||||
|
|
|
|||
|
|
@ -138,6 +138,11 @@ private:
|
|||
HashMap<String, int> modes;
|
||||
HashSet<StringName> flags;
|
||||
|
||||
bool stencil_enabled = false;
|
||||
HashMap<String, int> stencil_modes;
|
||||
HashSet<StringName> stencil_flags;
|
||||
int stencil_reference = 1;
|
||||
|
||||
HashMap<String, Varying> varyings;
|
||||
#ifdef TOOLS_ENABLED
|
||||
HashMap<String, Variant> preview_params;
|
||||
|
|
|
|||
|
|
@ -881,6 +881,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
|
|||
scene_state.used_normal_texture = false;
|
||||
scene_state.used_depth_texture = false;
|
||||
scene_state.used_lightmap = false;
|
||||
scene_state.used_opaque_stencil = false;
|
||||
}
|
||||
uint32_t lightmap_captures_used = 0;
|
||||
|
||||
|
|
@ -1126,6 +1127,9 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
|
|||
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) {
|
||||
scene_state.used_depth_texture = true;
|
||||
}
|
||||
if ((surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_STENCIL) && !force_alpha && (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE))) {
|
||||
scene_state.used_opaque_stencil = true;
|
||||
}
|
||||
} else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) {
|
||||
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) {
|
||||
rl->add_element(surf);
|
||||
|
|
@ -2041,7 +2045,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
|
|||
|
||||
bool debug_voxelgis = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION;
|
||||
bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES;
|
||||
bool depth_pre_pass = bool(GLOBAL_GET_CACHED(bool, "rendering/driver/depth_prepass/enable")) && depth_framebuffer.is_valid();
|
||||
bool force_depth_pre_pass = scene_state.used_opaque_stencil;
|
||||
bool depth_pre_pass = (force_depth_pre_pass || bool(GLOBAL_GET_CACHED(bool, "rendering/driver/depth_prepass/enable"))) && depth_framebuffer.is_valid();
|
||||
|
||||
SceneShaderForwardClustered::ShaderSpecialization base_specialization = scene_shader.default_specialization;
|
||||
base_specialization.use_depth_fog = p_render_data->environment.is_valid() && environment_get_fog_mode(p_render_data->environment) == RS::EnvironmentFogMode::ENV_FOG_MODE_DEPTH;
|
||||
|
|
@ -3984,6 +3989,10 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
|
|||
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS;
|
||||
}
|
||||
|
||||
if (p_material->shader_data->stencil_enabled) {
|
||||
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_STENCIL;
|
||||
}
|
||||
|
||||
if (p_material->shader_data->uses_alpha_pass()) {
|
||||
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA;
|
||||
if (p_material->shader_data->uses_depth_in_alpha_pass()) {
|
||||
|
|
@ -4004,6 +4013,17 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
|
|||
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_MOTION_VECTOR;
|
||||
}
|
||||
|
||||
if (p_material->shader_data->stencil_enabled) {
|
||||
if (p_material->shader_data->stencil_flags & SceneShaderForwardClustered::ShaderData::STENCIL_FLAG_READ) {
|
||||
// Stencil materials which read from the stencil buffer must be in the alpha pass.
|
||||
// This is critical to preserve compatibility once we'll have the compositor.
|
||||
if (!(flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) {
|
||||
String shader_path = p_material->shader_data->path.is_empty() ? "" : "(" + p_material->shader_data->path + ")";
|
||||
ERR_PRINT_ED(vformat("Attempting to use a shader %s that reads stencil but is not in the alpha queue. Ensure the material uses alpha blending or has depth_draw disabled or depth_test disabled.", shader_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SceneShaderForwardClustered::MaterialData *material_shadow = nullptr;
|
||||
void *surface_shadow = nullptr;
|
||||
if (p_material->shader_data->uses_shared_shadow_material()) {
|
||||
|
|
|
|||
|
|
@ -408,6 +408,7 @@ private:
|
|||
bool used_depth_texture = false;
|
||||
bool used_sss = false;
|
||||
bool used_lightmap = false;
|
||||
bool used_opaque_stencil = false;
|
||||
|
||||
struct ShadowPass {
|
||||
uint32_t element_from;
|
||||
|
|
@ -485,6 +486,7 @@ private:
|
|||
FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768,
|
||||
FLAG_USES_PARTICLE_TRAILS = 65536,
|
||||
FLAG_USES_MOTION_VECTOR = 131072,
|
||||
FLAG_USES_STENCIL = 262144,
|
||||
};
|
||||
|
||||
union {
|
||||
|
|
|
|||
|
|
@ -84,6 +84,12 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
|
|||
|
||||
int depth_drawi = DEPTH_DRAW_OPAQUE;
|
||||
|
||||
int stencil_readi = 0;
|
||||
int stencil_writei = 0;
|
||||
int stencil_write_depth_faili = 0;
|
||||
int stencil_comparei = STENCIL_COMPARE_ALWAYS;
|
||||
int stencil_referencei = -1;
|
||||
|
||||
ShaderCompiler::IdentifierActions actions;
|
||||
actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
|
||||
actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT;
|
||||
|
|
@ -145,6 +151,20 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
|
|||
actions.write_flag_pointers["POSITION"] = &uses_position;
|
||||
actions.write_flag_pointers["Z_CLIP_SCALE"] = &uses_z_clip_scale;
|
||||
|
||||
actions.stencil_mode_values["read"] = Pair<int *, int>(&stencil_readi, STENCIL_FLAG_READ);
|
||||
actions.stencil_mode_values["write"] = Pair<int *, int>(&stencil_writei, STENCIL_FLAG_WRITE);
|
||||
actions.stencil_mode_values["write_depth_fail"] = Pair<int *, int>(&stencil_write_depth_faili, STENCIL_FLAG_WRITE_DEPTH_FAIL);
|
||||
|
||||
actions.stencil_mode_values["compare_less"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_LESS);
|
||||
actions.stencil_mode_values["compare_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_EQUAL);
|
||||
actions.stencil_mode_values["compare_less_or_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_LESS_OR_EQUAL);
|
||||
actions.stencil_mode_values["compare_greater"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_GREATER);
|
||||
actions.stencil_mode_values["compare_not_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_NOT_EQUAL);
|
||||
actions.stencil_mode_values["compare_greater_or_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_GREATER_OR_EQUAL);
|
||||
actions.stencil_mode_values["compare_always"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_ALWAYS);
|
||||
|
||||
actions.stencil_reference = &stencil_referencei;
|
||||
|
||||
actions.uniforms = &uniforms;
|
||||
|
||||
Error err = OK;
|
||||
|
|
@ -185,6 +205,11 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
|
|||
uses_tangent |= uses_normal_map;
|
||||
uses_tangent |= uses_bent_normal_map;
|
||||
|
||||
stencil_enabled = stencil_referencei != -1;
|
||||
stencil_flags = stencil_readi | stencil_writei | stencil_write_depth_faili;
|
||||
stencil_compare = StencilCompare(stencil_comparei);
|
||||
stencil_reference = stencil_referencei;
|
||||
|
||||
#if 0
|
||||
print_line("**compiling shader:");
|
||||
print_line("**defines:\n");
|
||||
|
|
@ -333,6 +358,48 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip
|
|||
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS;
|
||||
}
|
||||
}
|
||||
|
||||
depth_stencil_state.enable_stencil = stencil_enabled;
|
||||
if (stencil_enabled) {
|
||||
static const RD::CompareOperator stencil_compare_rd_table[STENCIL_COMPARE_MAX] = {
|
||||
RD::COMPARE_OP_LESS,
|
||||
RD::COMPARE_OP_EQUAL,
|
||||
RD::COMPARE_OP_LESS_OR_EQUAL,
|
||||
RD::COMPARE_OP_GREATER,
|
||||
RD::COMPARE_OP_NOT_EQUAL,
|
||||
RD::COMPARE_OP_GREATER_OR_EQUAL,
|
||||
RD::COMPARE_OP_ALWAYS,
|
||||
};
|
||||
|
||||
uint32_t stencil_mask = 255;
|
||||
|
||||
RD::PipelineDepthStencilState::StencilOperationState op;
|
||||
op.fail = RD::STENCIL_OP_KEEP;
|
||||
op.pass = RD::STENCIL_OP_KEEP;
|
||||
op.depth_fail = RD::STENCIL_OP_KEEP;
|
||||
op.compare = stencil_compare_rd_table[stencil_compare];
|
||||
op.compare_mask = 0;
|
||||
op.write_mask = 0;
|
||||
op.reference = stencil_reference;
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_READ) {
|
||||
op.compare_mask = stencil_mask;
|
||||
}
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_WRITE) {
|
||||
op.pass = RD::STENCIL_OP_REPLACE;
|
||||
op.write_mask = stencil_mask;
|
||||
}
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_WRITE_DEPTH_FAIL) {
|
||||
op.depth_fail = RD::STENCIL_OP_REPLACE;
|
||||
op.write_mask = stencil_mask;
|
||||
}
|
||||
|
||||
depth_stencil_state.front_op = op;
|
||||
depth_stencil_state.back_op = op;
|
||||
}
|
||||
|
||||
bool depth_pre_pass_enabled = bool(GLOBAL_GET_CACHED(bool, "rendering/driver/depth_prepass/enable"));
|
||||
|
||||
RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
|
||||
|
|
|
|||
|
|
@ -168,6 +168,23 @@ public:
|
|||
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
|
||||
};
|
||||
|
||||
enum StencilFlags {
|
||||
STENCIL_FLAG_READ = 1,
|
||||
STENCIL_FLAG_WRITE = 2,
|
||||
STENCIL_FLAG_WRITE_DEPTH_FAIL = 4,
|
||||
};
|
||||
|
||||
enum StencilCompare {
|
||||
STENCIL_COMPARE_LESS,
|
||||
STENCIL_COMPARE_EQUAL,
|
||||
STENCIL_COMPARE_LESS_OR_EQUAL,
|
||||
STENCIL_COMPARE_GREATER,
|
||||
STENCIL_COMPARE_NOT_EQUAL,
|
||||
STENCIL_COMPARE_GREATER_OR_EQUAL,
|
||||
STENCIL_COMPARE_ALWAYS,
|
||||
STENCIL_COMPARE_MAX // Not an actual operator, just the amount of operators.
|
||||
};
|
||||
|
||||
struct PipelineKey {
|
||||
RD::VertexFormatID vertex_format_id;
|
||||
RD::FramebufferFormatID framebuffer_format_id;
|
||||
|
|
@ -250,6 +267,11 @@ public:
|
|||
bool uses_z_clip_scale = false;
|
||||
RS::CullMode cull_mode = RS::CULL_MODE_DISABLED;
|
||||
|
||||
bool stencil_enabled = false;
|
||||
uint32_t stencil_flags = 0;
|
||||
StencilCompare stencil_compare = STENCIL_COMPARE_LESS;
|
||||
uint32_t stencil_reference = 0;
|
||||
|
||||
uint64_t last_pass = 0;
|
||||
uint32_t index = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -2675,6 +2675,17 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
|
|||
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS;
|
||||
}
|
||||
|
||||
if (p_material->shader_data->stencil_enabled) {
|
||||
if (p_material->shader_data->stencil_flags & SceneShaderForwardMobile::ShaderData::STENCIL_FLAG_READ) {
|
||||
// Stencil materials which read from the stencil buffer must be in the alpha pass.
|
||||
// This is critical to preserve compatibility once we'll have the compositor.
|
||||
if (!(flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) {
|
||||
String shader_path = p_material->shader_data->path.is_empty() ? "" : "(" + p_material->shader_data->path + ")";
|
||||
ERR_PRINT_ED(vformat("Attempting to use a shader %s that reads stencil but is not in the alpha queue. Ensure the material uses alpha blending or has depth_draw disabled or depth_test disabled.", shader_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SceneShaderForwardMobile::MaterialData *material_shadow = nullptr;
|
||||
void *surface_shadow = nullptr;
|
||||
if (p_material->shader_data->uses_shared_shadow_material()) {
|
||||
|
|
|
|||
|
|
@ -84,6 +84,12 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
|
|||
|
||||
int depth_drawi = DEPTH_DRAW_OPAQUE;
|
||||
|
||||
int stencil_readi = 0;
|
||||
int stencil_writei = 0;
|
||||
int stencil_write_depth_faili = 0;
|
||||
int stencil_comparei = STENCIL_COMPARE_ALWAYS;
|
||||
int stencil_referencei = -1;
|
||||
|
||||
ShaderCompiler::IdentifierActions actions;
|
||||
actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
|
||||
actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT;
|
||||
|
|
@ -143,6 +149,20 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
|
|||
actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
|
||||
actions.write_flag_pointers["VERTEX"] = &uses_vertex;
|
||||
|
||||
actions.stencil_mode_values["read"] = Pair<int *, int>(&stencil_readi, STENCIL_FLAG_READ);
|
||||
actions.stencil_mode_values["write"] = Pair<int *, int>(&stencil_writei, STENCIL_FLAG_WRITE);
|
||||
actions.stencil_mode_values["write_depth_fail"] = Pair<int *, int>(&stencil_write_depth_faili, STENCIL_FLAG_WRITE_DEPTH_FAIL);
|
||||
|
||||
actions.stencil_mode_values["compare_less"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_LESS);
|
||||
actions.stencil_mode_values["compare_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_EQUAL);
|
||||
actions.stencil_mode_values["compare_less_or_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_LESS_OR_EQUAL);
|
||||
actions.stencil_mode_values["compare_greater"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_GREATER);
|
||||
actions.stencil_mode_values["compare_not_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_NOT_EQUAL);
|
||||
actions.stencil_mode_values["compare_greater_or_equal"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_GREATER_OR_EQUAL);
|
||||
actions.stencil_mode_values["compare_always"] = Pair<int *, int>(&stencil_comparei, STENCIL_COMPARE_ALWAYS);
|
||||
|
||||
actions.stencil_reference = &stencil_referencei;
|
||||
|
||||
actions.uniforms = &uniforms;
|
||||
|
||||
MutexLock lock(SceneShaderForwardMobile::singleton_mutex);
|
||||
|
|
@ -179,6 +199,11 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
|
|||
uses_tangent |= uses_normal_map;
|
||||
uses_tangent |= uses_bent_normal_map;
|
||||
|
||||
stencil_enabled = stencil_referencei != -1;
|
||||
stencil_flags = stencil_readi | stencil_writei | stencil_write_depth_faili;
|
||||
stencil_compare = StencilCompare(stencil_comparei);
|
||||
stencil_reference = stencil_referencei;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (uses_sss) {
|
||||
WARN_PRINT_ONCE_ED("Subsurface scattering is only available when using the Forward+ renderer.");
|
||||
|
|
@ -300,6 +325,47 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli
|
|||
RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
|
||||
};
|
||||
|
||||
depth_stencil_state.enable_stencil = stencil_enabled;
|
||||
if (stencil_enabled) {
|
||||
static const RD::CompareOperator stencil_compare_rd_table[STENCIL_COMPARE_MAX] = {
|
||||
RD::COMPARE_OP_LESS,
|
||||
RD::COMPARE_OP_EQUAL,
|
||||
RD::COMPARE_OP_LESS_OR_EQUAL,
|
||||
RD::COMPARE_OP_GREATER,
|
||||
RD::COMPARE_OP_NOT_EQUAL,
|
||||
RD::COMPARE_OP_GREATER_OR_EQUAL,
|
||||
RD::COMPARE_OP_ALWAYS,
|
||||
};
|
||||
|
||||
uint32_t stencil_mask = 255;
|
||||
|
||||
RD::PipelineDepthStencilState::StencilOperationState op;
|
||||
op.fail = RD::STENCIL_OP_KEEP;
|
||||
op.pass = RD::STENCIL_OP_KEEP;
|
||||
op.depth_fail = RD::STENCIL_OP_KEEP;
|
||||
op.compare = stencil_compare_rd_table[stencil_compare];
|
||||
op.compare_mask = 0;
|
||||
op.write_mask = 0;
|
||||
op.reference = stencil_reference;
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_READ) {
|
||||
op.compare_mask = stencil_mask;
|
||||
}
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_WRITE) {
|
||||
op.pass = RD::STENCIL_OP_REPLACE;
|
||||
op.write_mask = stencil_mask;
|
||||
}
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_WRITE_DEPTH_FAIL) {
|
||||
op.depth_fail = RD::STENCIL_OP_REPLACE;
|
||||
op.write_mask = stencil_mask;
|
||||
}
|
||||
|
||||
depth_stencil_state.front_op = op;
|
||||
depth_stencil_state.back_op = op;
|
||||
}
|
||||
|
||||
RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[p_pipeline_key.primitive_type];
|
||||
|
||||
RD::PipelineRasterizationState raster_state;
|
||||
|
|
|
|||
|
|
@ -166,6 +166,23 @@ public:
|
|||
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
|
||||
};
|
||||
|
||||
enum StencilFlags {
|
||||
STENCIL_FLAG_READ = 1,
|
||||
STENCIL_FLAG_WRITE = 2,
|
||||
STENCIL_FLAG_WRITE_DEPTH_FAIL = 4,
|
||||
};
|
||||
|
||||
enum StencilCompare {
|
||||
STENCIL_COMPARE_LESS,
|
||||
STENCIL_COMPARE_EQUAL,
|
||||
STENCIL_COMPARE_LESS_OR_EQUAL,
|
||||
STENCIL_COMPARE_GREATER,
|
||||
STENCIL_COMPARE_NOT_EQUAL,
|
||||
STENCIL_COMPARE_GREATER_OR_EQUAL,
|
||||
STENCIL_COMPARE_ALWAYS,
|
||||
STENCIL_COMPARE_MAX // Not an actual operator, just the amount of operators.
|
||||
};
|
||||
|
||||
struct PipelineKey {
|
||||
RD::VertexFormatID vertex_format_id;
|
||||
RD::FramebufferFormatID framebuffer_format_id;
|
||||
|
|
@ -246,6 +263,11 @@ public:
|
|||
bool writes_modelview_or_projection = false;
|
||||
bool uses_world_coordinates = false;
|
||||
|
||||
bool stencil_enabled = false;
|
||||
uint32_t stencil_flags = 0;
|
||||
StencilCompare stencil_compare = STENCIL_COMPARE_LESS;
|
||||
uint32_t stencil_reference = 0;
|
||||
|
||||
uint64_t last_pass = 0;
|
||||
uint32_t index = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -453,6 +453,8 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
|
|||
case SL::Node::NODE_TYPE_SHADER: {
|
||||
SL::ShaderNode *pnode = (SL::ShaderNode *)p_node;
|
||||
|
||||
// Render modes.
|
||||
|
||||
for (int i = 0; i < pnode->render_modes.size(); i++) {
|
||||
if (p_default_actions.render_mode_defines.has(pnode->render_modes[i]) && !used_rmode_defines.has(pnode->render_modes[i])) {
|
||||
r_gen_code.defines.push_back(p_default_actions.render_mode_defines[pnode->render_modes[i]]);
|
||||
|
|
@ -469,6 +471,21 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
|
|||
}
|
||||
}
|
||||
|
||||
// Stencil modes.
|
||||
|
||||
for (int i = 0; i < pnode->stencil_modes.size(); i++) {
|
||||
if (p_actions.stencil_mode_values.has(pnode->stencil_modes[i])) {
|
||||
Pair<int *, int> &p = p_actions.stencil_mode_values[pnode->stencil_modes[i]];
|
||||
*p.first = p.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Stencil reference value.
|
||||
|
||||
if (p_actions.stencil_reference && pnode->stencil_reference != -1) {
|
||||
*p_actions.stencil_reference = pnode->stencil_reference;
|
||||
}
|
||||
|
||||
// structs
|
||||
|
||||
for (int i = 0; i < pnode->vstructs.size(); i++) {
|
||||
|
|
@ -1463,6 +1480,7 @@ Error ShaderCompiler::compile(RS::ShaderMode p_mode, const String &p_code, Ident
|
|||
SL::ShaderCompileInfo info;
|
||||
info.functions = ShaderTypes::get_singleton()->get_functions(p_mode);
|
||||
info.render_modes = ShaderTypes::get_singleton()->get_modes(p_mode);
|
||||
info.stencil_modes = ShaderTypes::get_singleton()->get_stencil_modes(p_mode);
|
||||
info.shader_types = ShaderTypes::get_singleton()->get_types();
|
||||
info.global_shader_uniform_type_func = _get_global_shader_uniform_type;
|
||||
info.base_varying_index = actions.base_varying_index;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ public:
|
|||
HashMap<StringName, bool *> render_mode_flags;
|
||||
HashMap<StringName, bool *> usage_flag_pointers;
|
||||
HashMap<StringName, bool *> write_flag_pointers;
|
||||
HashMap<StringName, Pair<int *, int>> stencil_mode_values;
|
||||
int *stencil_reference = nullptr;
|
||||
|
||||
HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> *uniforms = nullptr;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -339,6 +339,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
|
|||
{ TK_STRUCT, "struct", CF_GLOBAL_SPACE, {}, {} },
|
||||
{ TK_SHADER_TYPE, "shader_type", CF_SHADER_TYPE, {}, {} },
|
||||
{ TK_RENDER_MODE, "render_mode", CF_GLOBAL_SPACE, {}, {} },
|
||||
{ TK_STENCIL_MODE, "stencil_mode", CF_GLOBAL_SPACE, {}, {} },
|
||||
|
||||
// uniform qualifiers
|
||||
|
||||
|
|
@ -4128,7 +4129,7 @@ bool ShaderLanguage::is_token_operator_assign(TokenType p_type) {
|
|||
}
|
||||
|
||||
bool ShaderLanguage::is_token_hint(TokenType p_type) {
|
||||
return int(p_type) > int(TK_RENDER_MODE) && int(p_type) < int(TK_SHADER_TYPE);
|
||||
return int(p_type) > int(TK_STENCIL_MODE) && int(p_type) < int(TK_SHADER_TYPE);
|
||||
}
|
||||
|
||||
bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, Scalar *p_value) {
|
||||
|
|
@ -9110,7 +9111,7 @@ bool ShaderLanguage::_parse_numeric_constant_expression(const FunctionInfo &p_fu
|
|||
return true;
|
||||
}
|
||||
|
||||
Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_functions, const Vector<ModeInfo> &p_render_modes, const HashSet<String> &p_shader_types) {
|
||||
Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_functions, const Vector<ModeInfo> &p_render_modes, const Vector<ModeInfo> &p_stencil_modes, const HashSet<String> &p_shader_types) {
|
||||
Token tk;
|
||||
TkPos prev_pos;
|
||||
Token next;
|
||||
|
|
@ -9173,7 +9174,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
|
|||
|
||||
const FunctionInfo &constants = p_functions.has("constants") ? p_functions["constants"] : FunctionInfo();
|
||||
|
||||
HashMap<String, String> defined_modes;
|
||||
HashMap<String, String> defined_render_modes;
|
||||
HashMap<String, String> defined_stencil_modes;
|
||||
|
||||
while (tk.type != TK_EOF) {
|
||||
switch (tk.type) {
|
||||
|
|
@ -9182,83 +9184,64 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
|
|||
keyword_completion_context = CF_UNSPECIFIED;
|
||||
#endif // DEBUG_ENABLED
|
||||
while (true) {
|
||||
StringName mode;
|
||||
_get_completable_identifier(nullptr, COMPLETION_RENDER_MODE, mode);
|
||||
|
||||
if (mode == StringName()) {
|
||||
_set_error(RTR("Expected an identifier for render mode."));
|
||||
return ERR_PARSE_ERROR;
|
||||
Error error = _parse_shader_mode(false, p_render_modes, defined_render_modes);
|
||||
if (error != OK) {
|
||||
return error;
|
||||
}
|
||||
|
||||
const String smode = String(mode);
|
||||
|
||||
if (shader->render_modes.has(mode)) {
|
||||
_set_error(vformat(RTR("Duplicated render mode: '%s'."), smode));
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
if (is_shader_inc) {
|
||||
for (int i = 0; i < RenderingServer::SHADER_MAX; i++) {
|
||||
const Vector<ModeInfo> modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(i));
|
||||
|
||||
for (int j = 0; j < modes.size(); j++) {
|
||||
const ModeInfo &info = modes[j];
|
||||
const String name = String(info.name);
|
||||
|
||||
if (smode.begins_with(name)) {
|
||||
if (!info.options.is_empty()) {
|
||||
if (info.options.has(smode.substr(name.length() + 1))) {
|
||||
found = true;
|
||||
|
||||
if (defined_modes.has(name)) {
|
||||
_set_error(vformat(RTR("Redefinition of render mode: '%s'. The '%s' mode has already been set to '%s'."), smode, name, defined_modes[name]));
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
defined_modes.insert(name, smode);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < p_render_modes.size(); i++) {
|
||||
const ModeInfo &info = p_render_modes[i];
|
||||
const String name = String(info.name);
|
||||
|
||||
if (smode.begins_with(name)) {
|
||||
if (!info.options.is_empty()) {
|
||||
if (info.options.has(smode.substr(name.length() + 1))) {
|
||||
found = true;
|
||||
|
||||
if (defined_modes.has(name)) {
|
||||
_set_error(vformat(RTR("Redefinition of render mode: '%s'. The '%s' mode has already been set to '%s'."), smode, name, defined_modes[name]));
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
defined_modes.insert(name, smode);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
_set_error(vformat(RTR("Invalid render mode: '%s'."), smode));
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
shader->render_modes.push_back(mode);
|
||||
|
||||
tk = _get_token();
|
||||
|
||||
if (tk.type == TK_COMMA) {
|
||||
// All good, do nothing.
|
||||
} else if (tk.type == TK_SEMICOLON) {
|
||||
break; // Done.
|
||||
} else {
|
||||
_set_error(vformat(RTR("Unexpected token: '%s'."), get_token_text(tk)));
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_ENABLED
|
||||
keyword_completion_context = CF_GLOBAL_SPACE;
|
||||
#endif // DEBUG_ENABLED
|
||||
} break;
|
||||
case TK_STENCIL_MODE: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
keyword_completion_context = CF_UNSPECIFIED;
|
||||
#endif // DEBUG_ENABLED
|
||||
while (true) {
|
||||
TkPos pos = _get_tkpos();
|
||||
tk = _get_token();
|
||||
|
||||
if (tk.is_integer_constant()) {
|
||||
const int reference_value = tk.constant;
|
||||
|
||||
if (shader->stencil_reference != -1) {
|
||||
_set_error(vformat(RTR("Duplicated stencil mode reference value: '%s'."), reference_value));
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
if (reference_value < 0) {
|
||||
_set_error(vformat(RTR("Stencil mode reference value cannot be negative: '%s'."), reference_value));
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
if (reference_value > 255) {
|
||||
_set_error(vformat(RTR("Stencil mode reference value cannot be greater than 255: '%s'."), reference_value));
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
shader->stencil_reference = reference_value;
|
||||
} else {
|
||||
_set_tkpos(pos);
|
||||
|
||||
Error error = _parse_shader_mode(true, p_stencil_modes, defined_stencil_modes);
|
||||
if (error != OK) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
tk = _get_token();
|
||||
|
||||
if (tk.type == TK_COMMA) {
|
||||
//all good, do nothing
|
||||
} else if (tk.type == TK_SEMICOLON) {
|
||||
|
|
@ -11076,6 +11059,110 @@ Error ShaderLanguage::_find_last_flow_op_in_block(BlockNode *p_block, FlowOperat
|
|||
return FAILED;
|
||||
}
|
||||
|
||||
Error ShaderLanguage::_parse_shader_mode(bool p_is_stencil, const Vector<ModeInfo> &p_modes, HashMap<String, String> &r_defined_modes) {
|
||||
StringName mode;
|
||||
_get_completable_identifier(nullptr, p_is_stencil ? COMPLETION_STENCIL_MODE : COMPLETION_RENDER_MODE, mode);
|
||||
|
||||
if (mode == StringName()) {
|
||||
if (p_is_stencil) {
|
||||
_set_error(RTR("Expected an identifier for stencil mode."));
|
||||
} else {
|
||||
_set_error(RTR("Expected an identifier for render mode."));
|
||||
}
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
const String smode = String(mode);
|
||||
|
||||
Vector<StringName> ¤t_modes = p_is_stencil ? shader->stencil_modes : shader->render_modes;
|
||||
|
||||
if (current_modes.has(mode)) {
|
||||
if (p_is_stencil) {
|
||||
_set_error(vformat(RTR("Duplicated stencil mode: '%s'."), smode));
|
||||
} else {
|
||||
_set_error(vformat(RTR("Duplicated render mode: '%s'."), smode));
|
||||
}
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
if (is_shader_inc) {
|
||||
for (int i = 0; i < RenderingServer::SHADER_MAX; i++) {
|
||||
const Vector<ModeInfo> modes = p_is_stencil ? ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(i)) : ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(i));
|
||||
|
||||
for (const ModeInfo &info : modes) {
|
||||
const String name = String(info.name);
|
||||
|
||||
if (smode.begins_with(name)) {
|
||||
if (!info.options.is_empty()) {
|
||||
if (info.options.has(smode.substr(name.length() + 1))) {
|
||||
found = true;
|
||||
|
||||
if (r_defined_modes.has(name)) {
|
||||
if (p_is_stencil) {
|
||||
_set_error(vformat(RTR("Redefinition of stencil mode: '%s'. The '%s' mode has already been set to '%s'."), smode, name, r_defined_modes[name]));
|
||||
} else {
|
||||
_set_error(vformat(RTR("Redefinition of render mode: '%s'. The '%s' mode has already been set to '%s'."), smode, name, r_defined_modes[name]));
|
||||
}
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
r_defined_modes.insert(name, smode);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const ModeInfo &info : p_modes) {
|
||||
const String name = String(info.name);
|
||||
|
||||
if (smode.begins_with(name)) {
|
||||
if (!info.options.is_empty()) {
|
||||
if (info.options.has(smode.substr(name.length() + 1))) {
|
||||
found = true;
|
||||
|
||||
if (r_defined_modes.has(name)) {
|
||||
if (p_is_stencil) {
|
||||
_set_error(vformat(RTR("Redefinition of stencil mode: '%s'. The '%s' mode has already been set to '%s'."), smode, name, r_defined_modes[name]));
|
||||
} else {
|
||||
_set_error(vformat(RTR("Redefinition of render mode: '%s'. The '%s' mode has already been set to '%s'."), smode, name, r_defined_modes[name]));
|
||||
}
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
r_defined_modes.insert(name, smode);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (p_is_stencil) {
|
||||
_set_error(vformat(RTR("Invalid stencil mode: '%s'."), smode));
|
||||
} else {
|
||||
_set_error(vformat(RTR("Invalid render mode: '%s'."), smode));
|
||||
}
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
if (p_is_stencil) {
|
||||
shader->stencil_modes.push_back(mode);
|
||||
} else {
|
||||
shader->render_modes.push_back(mode);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
// skips over whitespace and /* */ and // comments
|
||||
static int _get_first_ident_pos(const String &p_code) {
|
||||
int idx = 0;
|
||||
|
|
@ -11226,7 +11313,7 @@ Error ShaderLanguage::compile(const String &p_code, const ShaderCompileInfo &p_i
|
|||
nodes = nullptr;
|
||||
|
||||
shader = alloc_node<ShaderNode>();
|
||||
Error err = _parse_shader(p_info.functions, p_info.render_modes, p_info.shader_types);
|
||||
Error err = _parse_shader(p_info.functions, p_info.render_modes, p_info.stencil_modes, p_info.shader_types);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings) {
|
||||
|
|
@ -11251,7 +11338,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
|
|||
global_shader_uniform_get_type_func = p_info.global_shader_uniform_type_func;
|
||||
|
||||
shader = alloc_node<ShaderNode>();
|
||||
_parse_shader(p_info.functions, p_info.render_modes, p_info.shader_types);
|
||||
_parse_shader(p_info.functions, p_info.render_modes, p_info.stencil_modes, p_info.shader_types);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// Adds context keywords.
|
||||
|
|
@ -11349,6 +11436,67 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
|
|||
|
||||
return OK;
|
||||
} break;
|
||||
case COMPLETION_STENCIL_MODE: {
|
||||
if (is_shader_inc) {
|
||||
for (int i = 0; i < RenderingServer::SHADER_MAX; i++) {
|
||||
const Vector<ModeInfo> modes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(i));
|
||||
|
||||
for (const ModeInfo &info : modes) {
|
||||
if (!info.options.is_empty()) {
|
||||
bool found = false;
|
||||
|
||||
for (const StringName &option : info.options) {
|
||||
if (shader->stencil_modes.has(String(info.name) + "_" + String(option))) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
for (const StringName &option : info.options) {
|
||||
ScriptLanguage::CodeCompletionOption completion_option(String(info.name) + "_" + String(option), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
|
||||
r_options->push_back(completion_option);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const String name = String(info.name);
|
||||
|
||||
if (!shader->stencil_modes.has(name)) {
|
||||
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
|
||||
r_options->push_back(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const ModeInfo &info : p_info.stencil_modes) {
|
||||
if (!info.options.is_empty()) {
|
||||
bool found = false;
|
||||
|
||||
for (const StringName &option : info.options) {
|
||||
if (shader->stencil_modes.has(String(info.name) + "_" + String(option))) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
for (const StringName &option : info.options) {
|
||||
ScriptLanguage::CodeCompletionOption completion_option(String(info.name) + "_" + String(option), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
|
||||
r_options->push_back(completion_option);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const String name = String(info.name);
|
||||
|
||||
if (!shader->stencil_modes.has(name)) {
|
||||
ScriptLanguage::CodeCompletionOption option(name, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
|
||||
r_options->push_back(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
} break;
|
||||
case COMPLETION_STRUCT: {
|
||||
if (shader->structs.has(completion_struct)) {
|
||||
StructNode *node = shader->structs[completion_struct].shader_struct;
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ public:
|
|||
TK_ARG_OUT,
|
||||
TK_ARG_INOUT,
|
||||
TK_RENDER_MODE,
|
||||
TK_STENCIL_MODE,
|
||||
TK_HINT_DEFAULT_WHITE_TEXTURE,
|
||||
TK_HINT_DEFAULT_BLACK_TEXTURE,
|
||||
TK_HINT_DEFAULT_TRANSPARENT_TEXTURE,
|
||||
|
|
@ -723,6 +724,8 @@ public:
|
|||
HashMap<StringName, Struct> structs;
|
||||
HashMap<StringName, Function> functions;
|
||||
Vector<StringName> render_modes;
|
||||
Vector<StringName> stencil_modes;
|
||||
int stencil_reference = -1;
|
||||
|
||||
Vector<Function> vfunctions;
|
||||
Vector<Constant> vconstants;
|
||||
|
|
@ -799,6 +802,7 @@ public:
|
|||
COMPLETION_NONE,
|
||||
COMPLETION_SHADER_TYPE,
|
||||
COMPLETION_RENDER_MODE,
|
||||
COMPLETION_STENCIL_MODE,
|
||||
COMPLETION_MAIN_FUNCTION,
|
||||
COMPLETION_IDENTIFIER,
|
||||
COMPLETION_FUNCTION_CALL,
|
||||
|
|
@ -1222,11 +1226,13 @@ private:
|
|||
String _get_qualifier_str(ArgumentQualifier p_qualifier) const;
|
||||
|
||||
bool _parse_numeric_constant_expression(const FunctionInfo &p_function_info, float &r_constant);
|
||||
Error _parse_shader(const HashMap<StringName, FunctionInfo> &p_functions, const Vector<ModeInfo> &p_render_modes, const HashSet<String> &p_shader_types);
|
||||
Error _parse_shader(const HashMap<StringName, FunctionInfo> &p_functions, const Vector<ModeInfo> &p_render_modes, const Vector<ModeInfo> &p_stencil_modes, const HashSet<String> &p_shader_types);
|
||||
|
||||
Error _find_last_flow_op_in_block(BlockNode *p_block, FlowOperation p_op);
|
||||
Error _find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op);
|
||||
|
||||
Error _parse_shader_mode(bool p_is_stencil, const Vector<ModeInfo> &p_modes, HashMap<String, String> &r_defined_modes);
|
||||
|
||||
public:
|
||||
#ifdef DEBUG_ENABLED
|
||||
List<ShaderWarning>::Element *get_warnings_ptr();
|
||||
|
|
@ -1248,6 +1254,7 @@ public:
|
|||
struct ShaderCompileInfo {
|
||||
HashMap<StringName, FunctionInfo> functions;
|
||||
Vector<ModeInfo> render_modes;
|
||||
Vector<ModeInfo> stencil_modes;
|
||||
VaryingFunctionNames varying_function_names;
|
||||
HashSet<String> shader_types;
|
||||
GlobalShaderUniformGetTypeFunc global_shader_uniform_type_func = nullptr;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ const Vector<ShaderLanguage::ModeInfo> &ShaderTypes::get_modes(RS::ShaderMode p_
|
|||
return shader_modes[p_mode].modes;
|
||||
}
|
||||
|
||||
const Vector<ShaderLanguage::ModeInfo> &ShaderTypes::get_stencil_modes(RS::ShaderMode p_mode) const {
|
||||
return shader_modes[p_mode].stencil_modes;
|
||||
}
|
||||
|
||||
const HashSet<String> &ShaderTypes::get_types() const {
|
||||
return shader_types;
|
||||
}
|
||||
|
|
@ -246,6 +250,10 @@ ShaderTypes::ShaderTypes() {
|
|||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("debug_shadow_splits") });
|
||||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("fog_disabled") });
|
||||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("specular_occlusion_disabled") });
|
||||
shader_modes[RS::SHADER_SPATIAL].stencil_modes.push_back({ PNAME("read") });
|
||||
shader_modes[RS::SHADER_SPATIAL].stencil_modes.push_back({ PNAME("write") });
|
||||
shader_modes[RS::SHADER_SPATIAL].stencil_modes.push_back({ PNAME("write_depth_fail") });
|
||||
shader_modes[RS::SHADER_SPATIAL].stencil_modes.push_back({ PNAME("compare"), { "always", "less", "equal", "less_or_equal", "greater", "not_equal", "greater_or_equal" } });
|
||||
}
|
||||
|
||||
/************ CANVAS ITEM **************************/
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class ShaderTypes {
|
|||
struct Type {
|
||||
HashMap<StringName, ShaderLanguage::FunctionInfo> functions;
|
||||
Vector<ShaderLanguage::ModeInfo> modes;
|
||||
Vector<ShaderLanguage::ModeInfo> stencil_modes;
|
||||
};
|
||||
|
||||
HashMap<RS::ShaderMode, Type> shader_modes;
|
||||
|
|
@ -51,6 +52,7 @@ public:
|
|||
|
||||
const HashMap<StringName, ShaderLanguage::FunctionInfo> &get_functions(RS::ShaderMode p_mode) const;
|
||||
const Vector<ShaderLanguage::ModeInfo> &get_modes(RS::ShaderMode p_mode) const;
|
||||
const Vector<ShaderLanguage::ModeInfo> &get_stencil_modes(RS::ShaderMode p_mode) const;
|
||||
const HashSet<String> &get_types() const;
|
||||
const List<String> &get_types_list() const;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue