mirror of
https://github.com/godotengine/godot.git
synced 2025-12-08 06:09:55 +00:00
Add stencil support for spatial materials
This commit is contained in:
parent
7574a5dbb3
commit
d674c9e289
29 changed files with 1335 additions and 141 deletions
|
|
@ -912,6 +912,56 @@ void BaseMaterial3D::_update_shader() {
|
|||
|
||||
code += ";\n";
|
||||
|
||||
if (stencil_mode != STENCIL_MODE_DISABLED && stencil_flags != 0) {
|
||||
code += "stencil_mode ";
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_READ) {
|
||||
code += "read";
|
||||
}
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_WRITE) {
|
||||
if (stencil_flags & STENCIL_FLAG_READ) {
|
||||
code += ", ";
|
||||
}
|
||||
code += "write";
|
||||
}
|
||||
|
||||
if (stencil_flags & STENCIL_FLAG_WRITE_DEPTH_FAIL) {
|
||||
if (stencil_flags & (STENCIL_FLAG_READ | STENCIL_FLAG_WRITE)) {
|
||||
code += ", ";
|
||||
}
|
||||
code += "write_depth_fail";
|
||||
}
|
||||
|
||||
switch (stencil_compare) {
|
||||
case STENCIL_COMPARE_ALWAYS:
|
||||
code += ", compare_always";
|
||||
break;
|
||||
case STENCIL_COMPARE_LESS:
|
||||
code += ", compare_less";
|
||||
break;
|
||||
case STENCIL_COMPARE_EQUAL:
|
||||
code += ", compare_equal";
|
||||
break;
|
||||
case STENCIL_COMPARE_LESS_OR_EQUAL:
|
||||
code += ", compare_less_or_equal";
|
||||
break;
|
||||
case STENCIL_COMPARE_GREATER:
|
||||
code += ", compare_greater";
|
||||
break;
|
||||
case STENCIL_COMPARE_NOT_EQUAL:
|
||||
code += ", compare_not_equal";
|
||||
break;
|
||||
case STENCIL_COMPARE_GREATER_OR_EQUAL:
|
||||
code += ", compare_greater_or_equal";
|
||||
break;
|
||||
case STENCIL_COMPARE_MAX:
|
||||
break;
|
||||
}
|
||||
|
||||
code += vformat(", %s;\n", stencil_reference);
|
||||
}
|
||||
|
||||
// Generate list of uniforms.
|
||||
code += vformat(R"(
|
||||
uniform vec4 albedo : source_color;
|
||||
|
|
@ -2591,7 +2641,23 @@ void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const {
|
|||
}
|
||||
|
||||
if (p_property.name == "depth_test" && flags[FLAG_DISABLE_DEPTH_TEST]) {
|
||||
p_property.usage = PROPERTY_USAGE_NONE;
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
if (p_property.name == "stencil_reference" && stencil_mode == STENCIL_MODE_DISABLED) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
if ((p_property.name == "stencil_flags" || p_property.name == "stencil_compare") && stencil_mode != STENCIL_MODE_CUSTOM) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
if (p_property.name == "stencil_color" && stencil_mode != STENCIL_MODE_OUTLINE && stencil_mode != STENCIL_MODE_XRAY) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
if (p_property.name == "stencil_outline_thickness" && stencil_mode != STENCIL_MODE_OUTLINE) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (p_property.name == "subsurf_scatter_transmittance_color" || p_property.name == "subsurf_scatter_transmittance_texture")) {
|
||||
|
|
@ -3066,6 +3132,179 @@ RID BaseMaterial3D::get_rid() const {
|
|||
return _get_material();
|
||||
}
|
||||
|
||||
void BaseMaterial3D::_prepare_stencil_effect() {
|
||||
const Ref<Material> current_next_pass = get_next_pass();
|
||||
|
||||
if (stencil_mode == STENCIL_MODE_DISABLED || stencil_mode == STENCIL_MODE_CUSTOM) {
|
||||
if (current_next_pass.is_valid() && current_next_pass->has_meta("_stencil_owned")) {
|
||||
set_next_pass(current_next_pass->get_next_pass());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<BaseMaterial3D> stencil_next_pass;
|
||||
|
||||
if (current_next_pass.is_null() || !current_next_pass->has_meta("_stencil_owned")) {
|
||||
stencil_next_pass = Ref<BaseMaterial3D>(memnew(StandardMaterial3D));
|
||||
stencil_next_pass->set_meta("_stencil_owned", true);
|
||||
stencil_next_pass->set_next_pass(current_next_pass);
|
||||
set_next_pass(stencil_next_pass);
|
||||
} else {
|
||||
stencil_next_pass = current_next_pass;
|
||||
}
|
||||
|
||||
switch (stencil_mode) {
|
||||
case STENCIL_MODE_DISABLED:
|
||||
break;
|
||||
case STENCIL_MODE_OUTLINE:
|
||||
set_stencil_flags(STENCIL_FLAG_WRITE);
|
||||
set_stencil_compare(STENCIL_COMPARE_ALWAYS);
|
||||
stencil_next_pass->set_render_priority(-1);
|
||||
stencil_next_pass->set_shading_mode(SHADING_MODE_UNSHADED);
|
||||
stencil_next_pass->set_transparency(TRANSPARENCY_ALPHA);
|
||||
stencil_next_pass->set_flag(FLAG_DISABLE_DEPTH_TEST, false);
|
||||
stencil_next_pass->set_grow_enabled(true);
|
||||
stencil_next_pass->set_grow(stencil_effect_outline_thickness);
|
||||
stencil_next_pass->set_albedo(stencil_effect_color);
|
||||
stencil_next_pass->set_stencil_mode(STENCIL_MODE_CUSTOM);
|
||||
stencil_next_pass->set_stencil_flags(STENCIL_FLAG_READ | STENCIL_FLAG_WRITE);
|
||||
stencil_next_pass->set_stencil_compare(STENCIL_COMPARE_NOT_EQUAL);
|
||||
stencil_next_pass->set_stencil_reference(stencil_reference);
|
||||
break;
|
||||
case STENCIL_MODE_XRAY:
|
||||
set_stencil_flags(STENCIL_FLAG_WRITE);
|
||||
set_stencil_compare(STENCIL_COMPARE_ALWAYS);
|
||||
stencil_next_pass->set_render_priority(-1);
|
||||
stencil_next_pass->set_shading_mode(SHADING_MODE_UNSHADED);
|
||||
stencil_next_pass->set_transparency(TRANSPARENCY_ALPHA);
|
||||
stencil_next_pass->set_flag(FLAG_DISABLE_DEPTH_TEST, true);
|
||||
stencil_next_pass->set_grow_enabled(false);
|
||||
stencil_next_pass->set_grow(0);
|
||||
stencil_next_pass->set_albedo(stencil_effect_color);
|
||||
stencil_next_pass->set_stencil_mode(STENCIL_MODE_CUSTOM);
|
||||
stencil_next_pass->set_stencil_flags(STENCIL_FLAG_READ | STENCIL_FLAG_WRITE);
|
||||
stencil_next_pass->set_stencil_compare(STENCIL_COMPARE_NOT_EQUAL);
|
||||
stencil_next_pass->set_stencil_reference(stencil_reference);
|
||||
break;
|
||||
case STENCIL_MODE_CUSTOM:
|
||||
break;
|
||||
case STENCIL_MODE_MAX:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<BaseMaterial3D> BaseMaterial3D::_get_stencil_next_pass() const {
|
||||
const Ref<Material> current_next_pass = get_next_pass();
|
||||
Ref<BaseMaterial3D> stencil_next_pass;
|
||||
|
||||
if (current_next_pass.is_valid() && current_next_pass->has_meta("_stencil_owned")) {
|
||||
stencil_next_pass = current_next_pass;
|
||||
}
|
||||
|
||||
return stencil_next_pass;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_mode(StencilMode p_stencil_mode) {
|
||||
if (stencil_mode == p_stencil_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
stencil_mode = p_stencil_mode;
|
||||
_prepare_stencil_effect();
|
||||
_queue_shader_change();
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
BaseMaterial3D::StencilMode BaseMaterial3D::get_stencil_mode() const {
|
||||
return stencil_mode;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_flags(int p_stencil_flags) {
|
||||
if (stencil_flags == p_stencil_flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((p_stencil_flags & STENCIL_FLAG_READ) && (stencil_flags & (STENCIL_FLAG_WRITE | STENCIL_FLAG_WRITE_DEPTH_FAIL))) {
|
||||
p_stencil_flags = p_stencil_flags & STENCIL_FLAG_READ;
|
||||
}
|
||||
|
||||
if ((p_stencil_flags & (STENCIL_FLAG_WRITE | STENCIL_FLAG_WRITE_DEPTH_FAIL)) && (stencil_flags & STENCIL_FLAG_READ)) {
|
||||
p_stencil_flags = p_stencil_flags & (STENCIL_FLAG_WRITE | STENCIL_FLAG_WRITE_DEPTH_FAIL);
|
||||
}
|
||||
|
||||
stencil_flags = p_stencil_flags;
|
||||
_queue_shader_change();
|
||||
}
|
||||
|
||||
int BaseMaterial3D::get_stencil_flags() const {
|
||||
return stencil_flags;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_compare(BaseMaterial3D::StencilCompare p_op) {
|
||||
if (stencil_compare == p_op) {
|
||||
return;
|
||||
}
|
||||
|
||||
stencil_compare = p_op;
|
||||
_queue_shader_change();
|
||||
}
|
||||
|
||||
BaseMaterial3D::StencilCompare BaseMaterial3D::get_stencil_compare() const {
|
||||
return stencil_compare;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_reference(int p_reference) {
|
||||
if (stencil_reference == p_reference) {
|
||||
return;
|
||||
}
|
||||
|
||||
stencil_reference = p_reference;
|
||||
_queue_shader_change();
|
||||
|
||||
Ref<BaseMaterial3D> stencil_next_pass = _get_stencil_next_pass();
|
||||
if (stencil_next_pass.is_valid()) {
|
||||
stencil_next_pass->set_stencil_reference(p_reference);
|
||||
}
|
||||
}
|
||||
|
||||
int BaseMaterial3D::get_stencil_reference() const {
|
||||
return stencil_reference;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_effect_color(const Color &p_color) {
|
||||
if (stencil_effect_color == p_color) {
|
||||
return;
|
||||
}
|
||||
|
||||
stencil_effect_color = p_color;
|
||||
|
||||
Ref<BaseMaterial3D> stencil_next_pass = _get_stencil_next_pass();
|
||||
if (stencil_next_pass.is_valid()) {
|
||||
stencil_next_pass->set_albedo(p_color);
|
||||
}
|
||||
}
|
||||
|
||||
Color BaseMaterial3D::get_stencil_effect_color() const {
|
||||
return stencil_effect_color;
|
||||
}
|
||||
|
||||
void BaseMaterial3D::set_stencil_effect_outline_thickness(float p_outline_thickness) {
|
||||
if (stencil_effect_outline_thickness == p_outline_thickness) {
|
||||
return;
|
||||
}
|
||||
|
||||
stencil_effect_outline_thickness = p_outline_thickness;
|
||||
|
||||
Ref<BaseMaterial3D> stencil_next_pass = _get_stencil_next_pass();
|
||||
if (stencil_next_pass.is_valid()) {
|
||||
stencil_next_pass->set_grow(p_outline_thickness);
|
||||
}
|
||||
}
|
||||
|
||||
float BaseMaterial3D::get_stencil_effect_outline_thickness() const {
|
||||
return stencil_effect_outline_thickness;
|
||||
}
|
||||
|
||||
RID BaseMaterial3D::get_shader_rid() const {
|
||||
const_cast<BaseMaterial3D *>(this)->_update_shader();
|
||||
return shader_rid;
|
||||
|
|
@ -3291,6 +3530,24 @@ void BaseMaterial3D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_fov_override", "scale"), &BaseMaterial3D::set_fov_override);
|
||||
ClassDB::bind_method(D_METHOD("get_fov_override"), &BaseMaterial3D::get_fov_override);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_mode", "stencil_mode"), &BaseMaterial3D::set_stencil_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_mode"), &BaseMaterial3D::get_stencil_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_flags", "stencil_flags"), &BaseMaterial3D::set_stencil_flags);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_flags"), &BaseMaterial3D::get_stencil_flags);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_compare", "stencil_compare"), &BaseMaterial3D::set_stencil_compare);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_compare"), &BaseMaterial3D::get_stencil_compare);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_reference", "stencil_reference"), &BaseMaterial3D::set_stencil_reference);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_reference"), &BaseMaterial3D::get_stencil_reference);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_effect_color", "stencil_color"), &BaseMaterial3D::set_stencil_effect_color);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_effect_color"), &BaseMaterial3D::get_stencil_effect_color);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_stencil_effect_outline_thickness", "stencil_outline_thickness"), &BaseMaterial3D::set_stencil_effect_outline_thickness);
|
||||
ClassDB::bind_method(D_METHOD("get_stencil_effect_outline_thickness"), &BaseMaterial3D::get_stencil_effect_outline_thickness);
|
||||
|
||||
ADD_GROUP("Transparency", "");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,Alpha Scissor,Alpha Hash,Depth Pre-Pass"), "set_transparency", "get_transparency");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
|
||||
|
|
@ -3478,6 +3735,15 @@ void BaseMaterial3D::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_distance_fade_min_distance", "get_distance_fade_min_distance");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_distance_fade_max_distance", "get_distance_fade_max_distance");
|
||||
|
||||
ADD_GROUP("Stencil", "stencil_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "stencil_mode", PROPERTY_HINT_ENUM, "Disabled,Outline,X-Ray,Custom"), "set_stencil_mode", "get_stencil_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "stencil_flags", PROPERTY_HINT_FLAGS, "Read,Write,Write Depth Fail"), "set_stencil_flags", "get_stencil_flags");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "stencil_compare", PROPERTY_HINT_ENUM, "Always,Less,Equal,Less Or Equal,Greater,Not Equal,Greater Or Equal"), "set_stencil_compare", "get_stencil_compare");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "stencil_reference", PROPERTY_HINT_RANGE, "0,255,1"), "set_stencil_reference", "get_stencil_reference");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "stencil_color", PROPERTY_HINT_NONE), "set_stencil_effect_color", "get_stencil_effect_color");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stencil_outline_thickness", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,suffix:m"), "set_stencil_effect_outline_thickness", "get_stencil_effect_outline_thickness");
|
||||
|
||||
BIND_ENUM_CONSTANT(TEXTURE_ALBEDO);
|
||||
BIND_ENUM_CONSTANT(TEXTURE_METALLIC);
|
||||
BIND_ENUM_CONSTANT(TEXTURE_ROUGHNESS);
|
||||
|
|
@ -3612,6 +3878,23 @@ void BaseMaterial3D::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(DISTANCE_FADE_PIXEL_ALPHA);
|
||||
BIND_ENUM_CONSTANT(DISTANCE_FADE_PIXEL_DITHER);
|
||||
BIND_ENUM_CONSTANT(DISTANCE_FADE_OBJECT_DITHER);
|
||||
|
||||
BIND_ENUM_CONSTANT(STENCIL_MODE_DISABLED);
|
||||
BIND_ENUM_CONSTANT(STENCIL_MODE_OUTLINE);
|
||||
BIND_ENUM_CONSTANT(STENCIL_MODE_XRAY);
|
||||
BIND_ENUM_CONSTANT(STENCIL_MODE_CUSTOM);
|
||||
|
||||
BIND_ENUM_CONSTANT(STENCIL_FLAG_READ);
|
||||
BIND_ENUM_CONSTANT(STENCIL_FLAG_WRITE);
|
||||
BIND_ENUM_CONSTANT(STENCIL_FLAG_WRITE_DEPTH_FAIL);
|
||||
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_ALWAYS);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_LESS);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_EQUAL);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_LESS_OR_EQUAL);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_GREATER);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_NOT_EQUAL);
|
||||
BIND_ENUM_CONSTANT(STENCIL_COMPARE_GREATER_OR_EQUAL);
|
||||
}
|
||||
|
||||
BaseMaterial3D::BaseMaterial3D(bool p_orm) :
|
||||
|
|
@ -3680,6 +3963,8 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
|
|||
set_z_clip_scale(1.0);
|
||||
set_fov_override(75.0);
|
||||
|
||||
set_stencil_mode(STENCIL_MODE_DISABLED);
|
||||
|
||||
flags[FLAG_ALBEDO_TEXTURE_MSDF] = false;
|
||||
flags[FLAG_USE_TEXTURE_REPEAT] = true;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue