mirror of
https://github.com/godotengine/godot.git
synced 2025-12-08 06:09:55 +00:00
Merge pull request #80710 from apples/7174-apples-stencil
Add stencil support to spatial materials
This commit is contained in:
commit
0497ae9947
29 changed files with 1531 additions and 174 deletions
|
|
@ -159,6 +159,10 @@
|
|||
<member name="depth_draw_mode" type="int" setter="set_depth_draw_mode" getter="get_depth_draw_mode" enum="BaseMaterial3D.DepthDrawMode" default="0">
|
||||
Determines when depth rendering takes place. See also [member transparency].
|
||||
</member>
|
||||
<member name="depth_test" type="int" setter="set_depth_test" getter="get_depth_test" enum="BaseMaterial3D.DepthTest" default="0" experimental="May be affected by future rendering pipeline changes.">
|
||||
Determines which comparison operator is used when testing depth. See [enum DepthTest].
|
||||
[b]Note:[/b] Changing [member depth_test] to a non-default value only has a visible effect when used on a transparent material, or a material that has [member depth_draw_mode] set to [constant DEPTH_DRAW_DISABLED].
|
||||
</member>
|
||||
<member name="detail_albedo" type="Texture2D" setter="set_texture" getter="get_texture">
|
||||
Texture that specifies the color of the detail overlay. [member detail_albedo]'s alpha channel is used as a mask, even when the material is opaque. To use a dedicated texture as a mask, see [member detail_mask].
|
||||
[b]Note:[/b] [member detail_albedo] is [i]not[/i] modulated by [member albedo_color].
|
||||
|
|
@ -374,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>
|
||||
|
|
@ -661,6 +683,12 @@
|
|||
<constant name="DEPTH_DRAW_DISABLED" value="2" enum="DepthDrawMode">
|
||||
Objects will not write their depth to the depth buffer, even during the depth prepass (if enabled).
|
||||
</constant>
|
||||
<constant name="DEPTH_TEST_DEFAULT" value="0" enum="DepthTest">
|
||||
Depth test will discard the pixel if it is behind other pixels.
|
||||
</constant>
|
||||
<constant name="DEPTH_TEST_INVERTED" value="1" enum="DepthTest">
|
||||
Depth test will discard the pixel if it is in front of other pixels. Useful for stencil effects.
|
||||
</constant>
|
||||
<constant name="CULL_BACK" value="0" enum="CullMode">
|
||||
Default cull mode. The back of the object is culled when not visible. Back face triangles will be culled when facing the camera. This results in only the front side of triangles being drawn. For closed-surface meshes, this means that only the exterior of the mesh will be visible.
|
||||
</constant>
|
||||
|
|
@ -818,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;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "drivers/gles3/effects/copy_effects.h"
|
||||
#include "drivers/gles3/effects/feed_effects.h"
|
||||
#include "drivers/gles3/storage/material_storage.h"
|
||||
#include "rasterizer_gles3.h"
|
||||
#include "storage/config.h"
|
||||
#include "storage/mesh_storage.h"
|
||||
|
|
@ -223,10 +224,14 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry
|
|||
flags |= GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS;
|
||||
}
|
||||
|
||||
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_DISABLED) {
|
||||
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;
|
||||
if (p_material->shader_data->uses_depth_prepass_alpha && !(p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED)) {
|
||||
if (p_material->shader_data->uses_depth_prepass_alpha && !(p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test != GLES3::SceneShaderData::DEPTH_TEST_ENABLED)) {
|
||||
flags |= GeometryInstanceSurface::FLAG_PASS_DEPTH;
|
||||
flags |= GeometryInstanceSurface::FLAG_PASS_SHADOW;
|
||||
}
|
||||
|
|
@ -236,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) {
|
||||
|
|
@ -1233,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;
|
||||
|
|
@ -1426,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) {
|
||||
|
|
@ -2184,7 +2204,7 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
|
|||
scene_state.reset_gl_state();
|
||||
scene_state.enable_gl_depth_test(true);
|
||||
scene_state.enable_gl_depth_draw(true);
|
||||
glDepthFunc(GL_GREATER);
|
||||
scene_state.set_gl_depth_func(GL_GREATER);
|
||||
|
||||
glColorMask(0, 0, 0, 0);
|
||||
glDrawBuffers(0, nullptr);
|
||||
|
|
@ -2489,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;
|
||||
|
||||
|
|
@ -2503,12 +2526,15 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
scene_state.enable_gl_depth_test(true);
|
||||
scene_state.enable_gl_depth_draw(true);
|
||||
scene_state.enable_gl_blend(false);
|
||||
glDepthFunc(GL_GEQUAL);
|
||||
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);
|
||||
|
|
@ -2541,16 +2567,19 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
|||
scene_state.enable_gl_scissor_test(false);
|
||||
scene_state.enable_gl_depth_test(true);
|
||||
scene_state.enable_gl_depth_draw(true);
|
||||
glDepthFunc(GL_GEQUAL);
|
||||
scene_state.set_gl_depth_func(GL_GEQUAL);
|
||||
|
||||
{
|
||||
GLuint db = GL_COLOR_ATTACHMENT0;
|
||||
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:
|
||||
|
|
@ -2630,11 +2659,13 @@ 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");
|
||||
|
||||
scene_state.enable_gl_depth_test(true);
|
||||
scene_state.set_gl_depth_func(GL_GEQUAL);
|
||||
scene_state.enable_gl_blend(false);
|
||||
scene_state.set_gl_cull_mode(RS::CULL_MODE_BACK);
|
||||
|
||||
|
|
@ -2687,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);
|
||||
}
|
||||
|
|
@ -2705,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);
|
||||
|
|
@ -2834,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);
|
||||
|
|
@ -2863,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2908,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3016,7 +3049,13 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
|
|||
}
|
||||
|
||||
if constexpr (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
|
||||
scene_state.enable_gl_depth_test(shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_ENABLED);
|
||||
scene_state.enable_gl_depth_test(shader->depth_test != GLES3::SceneShaderData::DEPTH_TEST_DISABLED);
|
||||
}
|
||||
|
||||
if (shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_ENABLED_INVERTED) {
|
||||
scene_state.set_gl_depth_func(GL_LESS);
|
||||
} else {
|
||||
scene_state.set_gl_depth_func(GL_GEQUAL);
|
||||
}
|
||||
|
||||
if constexpr (p_pass_mode != PASS_MODE_SHADOW) {
|
||||
|
|
@ -3044,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.
|
||||
|
|
@ -3713,7 +3793,7 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider,
|
|||
scene_state.reset_gl_state();
|
||||
scene_state.enable_gl_depth_test(true);
|
||||
scene_state.enable_gl_depth_draw(true);
|
||||
glDepthFunc(GL_GREATER);
|
||||
scene_state.set_gl_depth_func(GL_GREATER);
|
||||
|
||||
glDrawBuffers(0, nullptr);
|
||||
|
||||
|
|
@ -3759,7 +3839,7 @@ void RasterizerSceneGLES3::_render_uv2(const PagedArray<RenderGeometryInstance *
|
|||
scene_state.reset_gl_state();
|
||||
scene_state.enable_gl_depth_test(true);
|
||||
scene_state.enable_gl_depth_draw(true);
|
||||
glDepthFunc(GL_GREATER);
|
||||
scene_state.set_gl_depth_func(GL_GREATER);
|
||||
|
||||
TightLocalVector<GLenum> draw_buffers;
|
||||
draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
|
||||
|
|
@ -3852,7 +3932,7 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES
|
|||
glViewport(0, 0, shadow_atlas_size, shadow_atlas_size);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
scene_state.enable_gl_depth_draw(true);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
scene_state.set_gl_depth_func(GL_ALWAYS);
|
||||
scene_state.set_gl_cull_mode(RS::CULL_MODE_DISABLED);
|
||||
|
||||
// Loop through quadrants and copy shadows over.
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "platform_gl.h"
|
||||
#ifdef GLES3_ENABLED
|
||||
|
||||
#include "core/math/projection.h"
|
||||
|
|
@ -246,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 {
|
||||
|
|
@ -462,6 +464,7 @@ private:
|
|||
|
||||
GLES3::SceneShaderData::BlendMode current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
|
||||
RS::CullMode cull_mode = RS::CULL_MODE_BACK;
|
||||
GLenum current_depth_function = GL_GEQUAL;
|
||||
|
||||
bool current_blend_enabled = false;
|
||||
bool current_depth_draw_enabled = false;
|
||||
|
|
@ -483,6 +486,18 @@ private:
|
|||
current_depth_draw_enabled = false;
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
current_depth_test_enabled = false;
|
||||
|
||||
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) {
|
||||
|
|
@ -540,10 +555,63 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void set_gl_depth_func(GLenum p_depth_func) {
|
||||
if (current_depth_function != p_depth_func) {
|
||||
glDepthFunc(p_depth_func);
|
||||
current_depth_function = p_depth_func;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -2945,11 +2945,18 @@ void SceneShaderData::set_code(const String &p_code) {
|
|||
|
||||
// Actual enums set further down after compilation.
|
||||
int blend_modei = BLEND_MODE_MIX;
|
||||
int depth_testi = DEPTH_TEST_ENABLED;
|
||||
int depth_test_disabledi = 0;
|
||||
int depth_test_invertedi = 0;
|
||||
int alpha_antialiasing_modei = ALPHA_ANTIALIASING_OFF;
|
||||
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;
|
||||
|
|
@ -2968,7 +2975,8 @@ void SceneShaderData::set_code(const String &p_code) {
|
|||
actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
|
||||
actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
|
||||
|
||||
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
|
||||
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_test_disabledi, 1);
|
||||
actions.render_mode_values["depth_test_inverted"] = Pair<int *, int>(&depth_test_invertedi, 1);
|
||||
|
||||
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_DISABLED);
|
||||
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_FRONT);
|
||||
|
|
@ -3018,6 +3026,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);
|
||||
|
|
@ -3030,7 +3052,13 @@ void SceneShaderData::set_code(const String &p_code) {
|
|||
blend_mode = BlendMode(blend_modei);
|
||||
alpha_antialiasing_mode = AlphaAntiAliasing(alpha_antialiasing_modei);
|
||||
depth_draw = DepthDraw(depth_drawi);
|
||||
depth_test = DepthTest(depth_testi);
|
||||
if (depth_test_disabledi) {
|
||||
depth_test = DEPTH_TEST_DISABLED;
|
||||
} else if (depth_test_invertedi) {
|
||||
depth_test = DEPTH_TEST_ENABLED_INVERTED;
|
||||
} else {
|
||||
depth_test = DEPTH_TEST_ENABLED;
|
||||
}
|
||||
cull_mode = RS::CullMode(cull_modei);
|
||||
|
||||
vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL; // We can always read vertices and normals.
|
||||
|
|
@ -3052,6 +3080,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.");
|
||||
|
|
@ -3118,7 +3151,7 @@ bool SceneShaderData::casts_shadows() const {
|
|||
bool has_base_alpha = (uses_alpha && !uses_alpha_clip) || has_read_screen_alpha;
|
||||
bool has_alpha = has_base_alpha || uses_blend_alpha;
|
||||
|
||||
return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
|
||||
return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test != DEPTH_TEST_ENABLED));
|
||||
}
|
||||
|
||||
RS::ShaderNativeSourceCode SceneShaderData::get_native_source_code() const {
|
||||
|
|
|
|||
|
|
@ -257,7 +257,25 @@ struct SceneShaderData : public ShaderData {
|
|||
|
||||
enum DepthTest {
|
||||
DEPTH_TEST_DISABLED,
|
||||
DEPTH_TEST_ENABLED
|
||||
DEPTH_TEST_ENABLED,
|
||||
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 {
|
||||
|
|
@ -285,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;
|
||||
|
||||
|
|
|
|||
|
|
@ -861,6 +861,17 @@ void BaseMaterial3D::_update_shader() {
|
|||
}
|
||||
if (flags[FLAG_DISABLE_DEPTH_TEST]) {
|
||||
code += ", depth_test_disabled";
|
||||
} else {
|
||||
switch (depth_test) {
|
||||
case DEPTH_TEST_DEFAULT:
|
||||
// depth_test_default is the default behavior, no need to emit it here.
|
||||
break;
|
||||
case DEPTH_TEST_INVERTED:
|
||||
code += ", depth_test_inverted";
|
||||
break;
|
||||
case DEPTH_TEST_MAX:
|
||||
break; // Internal value, skip.
|
||||
}
|
||||
}
|
||||
if (flags[FLAG_PARTICLE_TRAILS_MODE]) {
|
||||
code += ", particle_trails";
|
||||
|
|
@ -901,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;
|
||||
|
|
@ -2354,6 +2415,19 @@ BaseMaterial3D::DepthDrawMode BaseMaterial3D::get_depth_draw_mode() const {
|
|||
return depth_draw_mode;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_depth_test(DepthTest p_func) {
|
||||
if (depth_test == p_func) {
|
||||
return;
|
||||
}
|
||||
|
||||
depth_test = p_func;
|
||||
_queue_shader_change();
|
||||
}
|
||||
|
||||
BaseMaterial3D::DepthTest BaseMaterial3D::get_depth_test() const {
|
||||
return depth_test;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_cull_mode(CullMode p_mode) {
|
||||
if (cull_mode == p_mode) {
|
||||
return;
|
||||
|
|
@ -2410,7 +2484,8 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) {
|
|||
p_flag == FLAG_UV1_USE_TRIPLANAR ||
|
||||
p_flag == FLAG_UV2_USE_TRIPLANAR ||
|
||||
p_flag == FLAG_USE_Z_CLIP_SCALE ||
|
||||
p_flag == FLAG_USE_FOV_OVERRIDE) {
|
||||
p_flag == FLAG_USE_FOV_OVERRIDE ||
|
||||
p_flag == FLAG_DISABLE_DEPTH_TEST) {
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
|
|
@ -2565,6 +2640,26 @@ void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const {
|
|||
p_property.usage = PROPERTY_USAGE_NONE;
|
||||
}
|
||||
|
||||
if (p_property.name == "depth_test" && flags[FLAG_DISABLE_DEPTH_TEST]) {
|
||||
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")) {
|
||||
p_property.usage = PROPERTY_USAGE_NONE;
|
||||
}
|
||||
|
|
@ -3037,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;
|
||||
|
|
@ -3133,6 +3401,9 @@ void BaseMaterial3D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_depth_draw_mode", "depth_draw_mode"), &BaseMaterial3D::set_depth_draw_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_depth_draw_mode"), &BaseMaterial3D::get_depth_draw_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_depth_test", "depth_test"), &BaseMaterial3D::set_depth_test);
|
||||
ClassDB::bind_method(D_METHOD("get_depth_test"), &BaseMaterial3D::get_depth_test);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_cull_mode", "cull_mode"), &BaseMaterial3D::set_cull_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_cull_mode"), &BaseMaterial3D::get_cull_mode);
|
||||
|
||||
|
|
@ -3259,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");
|
||||
|
|
@ -3269,6 +3558,7 @@ void BaseMaterial3D::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mode", PROPERTY_HINT_ENUM, "Back,Front,Disabled"), "set_cull_mode", "get_cull_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_draw_mode", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never"), "set_depth_draw_mode", "get_depth_draw_mode");
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_flag", "get_flag", FLAG_DISABLE_DEPTH_TEST);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_test", PROPERTY_HINT_ENUM, "Default,Inverted"), "set_depth_test", "get_depth_test");
|
||||
|
||||
ADD_GROUP("Shading", "");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "shading_mode", PROPERTY_HINT_ENUM, "Unshaded,Per-Pixel,Per-Vertex"), "set_shading_mode", "get_shading_mode");
|
||||
|
|
@ -3445,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);
|
||||
|
|
@ -3518,6 +3817,9 @@ void BaseMaterial3D::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(DEPTH_DRAW_ALWAYS);
|
||||
BIND_ENUM_CONSTANT(DEPTH_DRAW_DISABLED);
|
||||
|
||||
BIND_ENUM_CONSTANT(DEPTH_TEST_DEFAULT);
|
||||
BIND_ENUM_CONSTANT(DEPTH_TEST_INVERTED);
|
||||
|
||||
BIND_ENUM_CONSTANT(CULL_BACK);
|
||||
BIND_ENUM_CONSTANT(CULL_FRONT);
|
||||
BIND_ENUM_CONSTANT(CULL_DISABLED);
|
||||
|
|
@ -3576,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) :
|
||||
|
|
@ -3644,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;
|
||||
|
||||
|
|
|
|||
|
|
@ -238,6 +238,12 @@ public:
|
|||
DEPTH_DRAW_MAX
|
||||
};
|
||||
|
||||
enum DepthTest {
|
||||
DEPTH_TEST_DEFAULT,
|
||||
DEPTH_TEST_INVERTED,
|
||||
DEPTH_TEST_MAX
|
||||
};
|
||||
|
||||
enum CullMode {
|
||||
CULL_BACK,
|
||||
CULL_FRONT,
|
||||
|
|
@ -320,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
|
||||
|
|
@ -330,6 +363,7 @@ private:
|
|||
uint64_t shading_mode : get_num_bits(SHADING_MODE_MAX - 1);
|
||||
uint64_t blend_mode : get_num_bits(BLEND_MODE_MAX - 1);
|
||||
uint64_t depth_draw_mode : get_num_bits(DEPTH_DRAW_MAX - 1);
|
||||
uint64_t depth_test : get_num_bits(DEPTH_TEST_MAX - 1);
|
||||
uint64_t cull_mode : get_num_bits(CULL_MAX - 1);
|
||||
uint64_t diffuse_mode : get_num_bits(DIFFUSE_MAX - 1);
|
||||
uint64_t specular_mode : get_num_bits(SPECULAR_MAX - 1);
|
||||
|
|
@ -338,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;
|
||||
|
|
@ -381,6 +422,7 @@ private:
|
|||
mk.detail_uv = detail_uv;
|
||||
mk.blend_mode = blend_mode;
|
||||
mk.depth_draw_mode = depth_draw_mode;
|
||||
mk.depth_test = depth_test;
|
||||
mk.cull_mode = cull_mode;
|
||||
mk.texture_filter = texture_filter;
|
||||
mk.transparency = transparency;
|
||||
|
|
@ -398,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);
|
||||
|
|
@ -553,6 +600,7 @@ private:
|
|||
BlendMode blend_mode = BLEND_MODE_MIX;
|
||||
BlendMode detail_blend_mode = BLEND_MODE_MIX;
|
||||
DepthDrawMode depth_draw_mode = DEPTH_DRAW_OPAQUE_ONLY;
|
||||
DepthTest depth_test = DEPTH_TEST_DEFAULT;
|
||||
CullMode cull_mode = CULL_BACK;
|
||||
bool flags[FLAG_MAX] = {};
|
||||
SpecularMode specular_mode = SPECULAR_SCHLICK_GGX;
|
||||
|
|
@ -570,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:
|
||||
|
|
@ -688,6 +747,9 @@ public:
|
|||
void set_depth_draw_mode(DepthDrawMode p_mode);
|
||||
DepthDrawMode get_depth_draw_mode() const;
|
||||
|
||||
void set_depth_test(DepthTest p_func);
|
||||
DepthTest get_depth_test() const;
|
||||
|
||||
void set_cull_mode(CullMode p_mode);
|
||||
CullMode get_cull_mode() const;
|
||||
|
||||
|
|
@ -778,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);
|
||||
|
|
@ -816,6 +896,7 @@ VARIANT_ENUM_CAST(BaseMaterial3D::DetailUV)
|
|||
VARIANT_ENUM_CAST(BaseMaterial3D::Feature)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::BlendMode)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::DepthDrawMode)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::DepthTest)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::CullMode)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::Flags)
|
||||
VARIANT_ENUM_CAST(BaseMaterial3D::DiffuseMode)
|
||||
|
|
@ -824,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)) {
|
||||
|
|
@ -1886,6 +1939,29 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
|
|||
for (int i = 0; i < rmodes.size(); i++) {
|
||||
const ShaderLanguage::ModeInfo &info = rmodes[i];
|
||||
|
||||
// Special handling for depth_test.
|
||||
if (info.name == "depth_test") {
|
||||
toggles.insert("depth_test_disabled");
|
||||
|
||||
const String begin = String(info.name);
|
||||
|
||||
for (int j = 0; j < info.options.size(); j++) {
|
||||
if (info.options[j] == "disabled") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const String option = String(info.options[j]).capitalize();
|
||||
|
||||
if (!blend_mode_enums.has(begin)) {
|
||||
blend_mode_enums[begin] = vformat("%s:%s", option, j);
|
||||
} else {
|
||||
blend_mode_enums[begin] += "," + vformat("%s:%s", option, j);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!info.options.is_empty()) {
|
||||
const String begin = String(info.name);
|
||||
|
||||
|
|
@ -1911,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));
|
||||
}
|
||||
|
|
@ -2550,6 +2665,23 @@ void VisualShader::_update_shader() const {
|
|||
const ShaderLanguage::ModeInfo &info = rmodes[i];
|
||||
const String temp = String(info.name);
|
||||
|
||||
// Special handling for depth_test.
|
||||
if (temp == "depth_test") {
|
||||
if (flags.has("depth_test_disabled")) {
|
||||
flag_names.push_back("depth_test_disabled");
|
||||
} else {
|
||||
if (!render_mode.is_empty()) {
|
||||
render_mode += ", ";
|
||||
}
|
||||
if (modes.has(temp) && modes[temp] < info.options.size()) {
|
||||
render_mode += temp + "_" + info.options[modes[temp]];
|
||||
} else {
|
||||
render_mode += temp + "_" + info.options[0];
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!info.options.is_empty()) {
|
||||
if (!render_mode.is_empty()) {
|
||||
render_mode += ", ";
|
||||
|
|
@ -2581,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 {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
|
|||
ShaderCompiler::GeneratedCode gen_code;
|
||||
|
||||
blend_mode = BLEND_MODE_MIX;
|
||||
depth_testi = DEPTH_TEST_ENABLED;
|
||||
depth_test_disabledi = 0;
|
||||
depth_test_invertedi = 0;
|
||||
alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
|
||||
int cull_modei = RS::CULL_MODE_BACK;
|
||||
|
||||
|
|
@ -83,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;
|
||||
|
|
@ -101,7 +108,8 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
|
|||
actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
|
||||
actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
|
||||
|
||||
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
|
||||
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_test_disabledi, 1);
|
||||
actions.render_mode_values["depth_test_inverted"] = Pair<int *, int>(&depth_test_invertedi, 1);
|
||||
|
||||
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_DISABLED);
|
||||
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_FRONT);
|
||||
|
|
@ -143,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;
|
||||
|
|
@ -164,7 +186,13 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
|
|||
}
|
||||
|
||||
depth_draw = DepthDraw(depth_drawi);
|
||||
depth_test = DepthTest(depth_testi);
|
||||
if (depth_test_disabledi) {
|
||||
depth_test = DEPTH_TEST_DISABLED;
|
||||
} else if (depth_test_invertedi) {
|
||||
depth_test = DEPTH_TEST_ENABLED_INVERTED;
|
||||
} else {
|
||||
depth_test = DEPTH_TEST_ENABLED;
|
||||
}
|
||||
cull_mode = RS::CullMode(cull_modei);
|
||||
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
|
||||
uses_screen_texture = gen_code.uses_screen_texture;
|
||||
|
|
@ -177,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");
|
||||
|
|
@ -219,7 +252,7 @@ bool SceneShaderForwardClustered::ShaderData::casts_shadows() const {
|
|||
bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
|
||||
bool has_alpha = has_base_alpha || uses_blend_alpha;
|
||||
|
||||
return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
|
||||
return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test != DEPTH_TEST_ENABLED));
|
||||
}
|
||||
|
||||
RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const {
|
||||
|
|
@ -318,9 +351,55 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip
|
|||
|
||||
if (depth_test != DEPTH_TEST_DISABLED) {
|
||||
depth_stencil_state.enable_depth_test = true;
|
||||
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
|
||||
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
|
||||
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
|
||||
|
||||
if (depth_test == DEPTH_TEST_ENABLED_INVERTED) {
|
||||
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] = {
|
||||
|
|
|
|||
|
|
@ -150,7 +150,8 @@ public:
|
|||
|
||||
enum DepthTest {
|
||||
DEPTH_TEST_DISABLED,
|
||||
DEPTH_TEST_ENABLED
|
||||
DEPTH_TEST_ENABLED,
|
||||
DEPTH_TEST_ENABLED_INVERTED,
|
||||
};
|
||||
|
||||
enum CullVariant {
|
||||
|
|
@ -167,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;
|
||||
|
|
@ -213,7 +231,8 @@ public:
|
|||
DepthTest depth_test = DEPTH_TEST_ENABLED;
|
||||
|
||||
int blend_mode = BLEND_MODE_MIX;
|
||||
int depth_testi = DEPTH_TEST_ENABLED;
|
||||
int depth_test_disabledi = 0;
|
||||
int depth_test_invertedi = 0;
|
||||
int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
|
||||
|
||||
bool uses_point_size = false;
|
||||
|
|
@ -248,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;
|
||||
|
||||
|
|
@ -257,13 +281,13 @@ public:
|
|||
bool has_blend_alpha = uses_blend_alpha;
|
||||
bool has_alpha = has_base_alpha || has_blend_alpha;
|
||||
bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
|
||||
bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
|
||||
bool no_depth_test = depth_test != DEPTH_TEST_ENABLED;
|
||||
return has_alpha || has_read_screen_alpha || no_depth_draw || no_depth_test;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool uses_depth_in_alpha_pass() const {
|
||||
bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
|
||||
bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
|
||||
bool no_depth_test = depth_test != DEPTH_TEST_ENABLED;
|
||||
return (uses_depth_prepass_alpha || uses_alpha_antialiasing) && !(no_depth_draw || no_depth_test);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2683,6 +2683,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()) {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
|
|||
ShaderCompiler::GeneratedCode gen_code;
|
||||
|
||||
blend_mode = BLEND_MODE_MIX;
|
||||
depth_testi = DEPTH_TEST_ENABLED;
|
||||
depth_test_disabledi = 0;
|
||||
depth_test_invertedi = 0;
|
||||
alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
|
||||
cull_mode = RS::CULL_MODE_BACK;
|
||||
|
||||
|
|
@ -83,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;
|
||||
|
|
@ -101,7 +108,8 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
|
|||
actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
|
||||
actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
|
||||
|
||||
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
|
||||
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_test_disabledi, 1);
|
||||
actions.render_mode_values["depth_test_inverted"] = Pair<int *, int>(&depth_test_invertedi, 1);
|
||||
|
||||
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_mode, RS::CULL_MODE_DISABLED);
|
||||
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_mode, RS::CULL_MODE_FRONT);
|
||||
|
|
@ -141,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);
|
||||
|
|
@ -159,7 +181,13 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
|
|||
}
|
||||
|
||||
depth_draw = DepthDraw(depth_drawi);
|
||||
depth_test = DepthTest(depth_testi);
|
||||
if (depth_test_disabledi) {
|
||||
depth_test = DEPTH_TEST_DISABLED;
|
||||
} else if (depth_test_invertedi) {
|
||||
depth_test = DEPTH_TEST_ENABLED_INVERTED;
|
||||
} else {
|
||||
depth_test = DEPTH_TEST_ENABLED;
|
||||
}
|
||||
uses_vertex_time = gen_code.uses_vertex_time;
|
||||
uses_fragment_time = gen_code.uses_fragment_time;
|
||||
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
|
||||
|
|
@ -171,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.");
|
||||
|
|
@ -224,7 +257,7 @@ bool SceneShaderForwardMobile::ShaderData::casts_shadows() const {
|
|||
bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
|
||||
bool has_alpha = has_base_alpha || uses_blend_alpha;
|
||||
|
||||
return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
|
||||
return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test != DEPTH_TEST_ENABLED));
|
||||
}
|
||||
|
||||
RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const {
|
||||
|
|
@ -276,8 +309,12 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli
|
|||
|
||||
if (depth_test != DEPTH_TEST_DISABLED) {
|
||||
depth_stencil_state.enable_depth_test = true;
|
||||
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
|
||||
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
|
||||
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
|
||||
|
||||
if (depth_test == DEPTH_TEST_ENABLED_INVERTED) {
|
||||
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS;
|
||||
}
|
||||
}
|
||||
|
||||
RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
|
||||
|
|
@ -288,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;
|
||||
|
|
|
|||
|
|
@ -150,7 +150,8 @@ public:
|
|||
|
||||
enum DepthTest {
|
||||
DEPTH_TEST_DISABLED,
|
||||
DEPTH_TEST_ENABLED
|
||||
DEPTH_TEST_ENABLED,
|
||||
DEPTH_TEST_ENABLED_INVERTED,
|
||||
};
|
||||
|
||||
enum CullVariant {
|
||||
|
|
@ -167,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;
|
||||
|
|
@ -213,7 +231,8 @@ public:
|
|||
DepthTest depth_test;
|
||||
|
||||
int blend_mode = BLEND_MODE_MIX;
|
||||
int depth_testi = DEPTH_TEST_ENABLED;
|
||||
int depth_test_disabledi = 0;
|
||||
int depth_test_invertedi = 0;
|
||||
int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
|
||||
int cull_mode = RS::CULL_MODE_BACK;
|
||||
|
||||
|
|
@ -246,6 +265,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;
|
||||
|
||||
|
|
@ -255,13 +279,13 @@ public:
|
|||
bool has_blend_alpha = uses_blend_alpha;
|
||||
bool has_alpha = has_base_alpha || has_blend_alpha;
|
||||
bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
|
||||
bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
|
||||
bool no_depth_test = depth_test != DEPTH_TEST_ENABLED;
|
||||
return has_alpha || has_read_screen_alpha || no_depth_draw || no_depth_test;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool uses_depth_in_alpha_pass() const {
|
||||
bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
|
||||
bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
|
||||
bool no_depth_test = depth_test != DEPTH_TEST_ENABLED;
|
||||
return (uses_depth_prepass_alpha || uses_alpha_antialiasing) && !(no_depth_draw || no_depth_test);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -937,6 +941,13 @@ public:
|
|||
options.push_back(p_arg5);
|
||||
options.push_back(p_arg6);
|
||||
}
|
||||
|
||||
ModeInfo(const StringName &p_name, std::initializer_list<StringName> p_args) :
|
||||
name(p_name) {
|
||||
for (const StringName &arg : p_args) {
|
||||
options.push_back(arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionInfo {
|
||||
|
|
@ -1215,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();
|
||||
|
|
@ -1241,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;
|
||||
}
|
||||
|
|
@ -226,7 +230,7 @@ ShaderTypes::ShaderTypes() {
|
|||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("blend"), "mix", "add", "sub", "mul", "premul_alpha" });
|
||||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("depth_draw"), "opaque", "always", "never" });
|
||||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("depth_prepass_alpha") });
|
||||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("depth_test_disabled") });
|
||||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("depth_test"), { "default", "disabled", "inverted" } });
|
||||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("sss_mode_skin") });
|
||||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("cull"), "back", "front", "disabled" });
|
||||
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("unshaded") });
|
||||
|
|
@ -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