Add derivative functions with precision to shaders

This commit is contained in:
Yuri Rubinsky 2023-01-26 14:31:37 +03:00
parent 44c0bfc94d
commit 8c8c333bf2
4 changed files with 128 additions and 4 deletions

View File

@ -15,6 +15,9 @@
<member name="op_type" type="int" setter="set_op_type" getter="get_op_type" enum="VisualShaderNodeDerivativeFunc.OpType" default="0"> <member name="op_type" type="int" setter="set_op_type" getter="get_op_type" enum="VisualShaderNodeDerivativeFunc.OpType" default="0">
A type of operands and returned value. See [enum OpType] for options. A type of operands and returned value. See [enum OpType] for options.
</member> </member>
<member name="precision" type="int" setter="set_precision" getter="get_precision" enum="VisualShaderNodeDerivativeFunc.Precision" default="0">
Sets the level of precision to use for the derivative function. See [enum Precision] for options. When using the GL_Compatibility renderer, this setting has no effect.
</member>
</members> </members>
<constants> <constants>
<constant name="OP_TYPE_SCALAR" value="0" enum="OpType"> <constant name="OP_TYPE_SCALAR" value="0" enum="OpType">
@ -44,5 +47,17 @@
<constant name="FUNC_MAX" value="3" enum="Function"> <constant name="FUNC_MAX" value="3" enum="Function">
Represents the size of the [enum Function] enum. Represents the size of the [enum Function] enum.
</constant> </constant>
<constant name="PRECISION_NONE" value="0" enum="Precision">
No precision is specified, the GPU driver is allowed to use whatever level of precision it chooses. This is the default option and is equivalent to using [code]dFdx()[/code] or [code]dFdy()[/code] in text shaders.
</constant>
<constant name="PRECISION_COARSE" value="1" enum="Precision">
The derivative will be calculated using the current fragment's neighbors (which may not include the current fragment). This tends to be faster than using [constant PRECISION_FINE], but may not be suitable when more precision is needed. This is equivalent to using [code]dFdxCoarse()[/code] or [code]dFdyCoarse()[/code] in text shaders.
</constant>
<constant name="PRECISION_FINE" value="2" enum="Precision">
The derivative will be calculated using the current fragment and its immediate neighbors. This tends to be slower than using [constant PRECISION_COARSE], but may be necessary when more precision is needed. This is equivalent to using [code]dFdxFine()[/code] or [code]dFdyFine()[/code] in text shaders.
</constant>
<constant name="PRECISION_MAX" value="3" enum="Precision">
Represents the size of the [enum Precision] enum.
</constant>
</constants> </constants>
</class> </class>

View File

@ -3690,16 +3690,47 @@ String VisualShaderNodeDerivativeFunc::get_output_port_name(int p_port) const {
String VisualShaderNodeDerivativeFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String VisualShaderNodeDerivativeFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
static const char *functions[FUNC_MAX] = { static const char *functions[FUNC_MAX] = {
"fwidth($)", "fwidth$($)",
"dFdx($)", "dFdx$($)",
"dFdy($)" "dFdy$($)"
};
static const char *precisions[PRECISION_MAX] = {
"",
"Coarse",
"Fine"
}; };
String code; String code;
code += " " + p_output_vars[0] + " = " + String(functions[func]).replace("$", p_input_vars[0]) + ";\n"; if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
code += " " + p_output_vars[0] + " = " + String(functions[func]).replace_first("$", "").replace_first("$", p_input_vars[0]) + ";\n";
return code;
}
code += " " + p_output_vars[0] + " = " + String(functions[func]).replace_first("$", String(precisions[precision])).replace_first("$", p_input_vars[0]) + ";\n";
return code; return code;
} }
String VisualShaderNodeDerivativeFunc::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
if (precision != PRECISION_NONE && OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
String precision_str;
switch (precision) {
case PRECISION_COARSE: {
precision_str = "Coarse";
} break;
case PRECISION_FINE: {
precision_str = "Fine";
} break;
default: {
} break;
}
return vformat(RTR("`%s` precision mode is not available for `gl_compatibility` profile.\nReverted to `None` precision."), precision_str);
}
return String();
}
void VisualShaderNodeDerivativeFunc::set_op_type(OpType p_op_type) { void VisualShaderNodeDerivativeFunc::set_op_type(OpType p_op_type) {
ERR_FAIL_INDEX((int)p_op_type, int(OP_TYPE_MAX)); ERR_FAIL_INDEX((int)p_op_type, int(OP_TYPE_MAX));
if (op_type == p_op_type) { if (op_type == p_op_type) {
@ -3742,10 +3773,24 @@ VisualShaderNodeDerivativeFunc::Function VisualShaderNodeDerivativeFunc::get_fun
return func; return func;
} }
void VisualShaderNodeDerivativeFunc::set_precision(Precision p_precision) {
ERR_FAIL_INDEX(int(p_precision), int(PRECISION_MAX));
if (precision == p_precision) {
return;
}
precision = p_precision;
emit_changed();
}
VisualShaderNodeDerivativeFunc::Precision VisualShaderNodeDerivativeFunc::get_precision() const {
return precision;
}
Vector<StringName> VisualShaderNodeDerivativeFunc::get_editable_properties() const { Vector<StringName> VisualShaderNodeDerivativeFunc::get_editable_properties() const {
Vector<StringName> props; Vector<StringName> props;
props.push_back("op_type"); props.push_back("op_type");
props.push_back("function"); props.push_back("function");
props.push_back("precision");
return props; return props;
} }
@ -3756,8 +3801,12 @@ void VisualShaderNodeDerivativeFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeDerivativeFunc::set_function); ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeDerivativeFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeDerivativeFunc::get_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeDerivativeFunc::get_function);
ClassDB::bind_method(D_METHOD("set_precision", "precision"), &VisualShaderNodeDerivativeFunc::set_precision);
ClassDB::bind_method(D_METHOD("get_precision"), &VisualShaderNodeDerivativeFunc::get_precision);
ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector3,Vector4"), "set_op_type", "get_op_type"); ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector3,Vector4"), "set_op_type", "get_op_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sum,X,Y"), "set_function", "get_function"); ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sum,X,Y"), "set_function", "get_function");
ADD_PROPERTY(PropertyInfo(Variant::INT, "precision", PROPERTY_HINT_ENUM, "None,Coarse,Fine"), "set_precision", "get_precision");
BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); BIND_ENUM_CONSTANT(OP_TYPE_SCALAR);
BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D);
@ -3769,6 +3818,11 @@ void VisualShaderNodeDerivativeFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_X); BIND_ENUM_CONSTANT(FUNC_X);
BIND_ENUM_CONSTANT(FUNC_Y); BIND_ENUM_CONSTANT(FUNC_Y);
BIND_ENUM_CONSTANT(FUNC_MAX); BIND_ENUM_CONSTANT(FUNC_MAX);
BIND_ENUM_CONSTANT(PRECISION_NONE);
BIND_ENUM_CONSTANT(PRECISION_COARSE);
BIND_ENUM_CONSTANT(PRECISION_FINE);
BIND_ENUM_CONSTANT(PRECISION_MAX);
} }
VisualShaderNodeDerivativeFunc::VisualShaderNodeDerivativeFunc() { VisualShaderNodeDerivativeFunc::VisualShaderNodeDerivativeFunc() {

View File

@ -1536,9 +1536,17 @@ public:
FUNC_MAX, FUNC_MAX,
}; };
enum Precision {
PRECISION_NONE,
PRECISION_COARSE,
PRECISION_FINE,
PRECISION_MAX,
};
protected: protected:
OpType op_type = OP_TYPE_SCALAR; OpType op_type = OP_TYPE_SCALAR;
Function func = FUNC_SUM; Function func = FUNC_SUM;
Precision precision = PRECISION_NONE;
protected: protected:
static void _bind_methods(); static void _bind_methods();
@ -1555,6 +1563,7 @@ public:
virtual String get_output_port_name(int p_port) const override; virtual String get_output_port_name(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override;
void set_op_type(OpType p_op_type); void set_op_type(OpType p_op_type);
OpType get_op_type() const; OpType get_op_type() const;
@ -1562,6 +1571,9 @@ public:
void set_function(Function p_func); void set_function(Function p_func);
Function get_function() const; Function get_function() const;
void set_precision(Precision p_precision);
Precision get_precision() const;
virtual Vector<StringName> get_editable_properties() const override; virtual Vector<StringName> get_editable_properties() const override;
VisualShaderNodeDerivativeFunc(); VisualShaderNodeDerivativeFunc();
@ -1569,6 +1581,7 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeDerivativeFunc::OpType) VARIANT_ENUM_CAST(VisualShaderNodeDerivativeFunc::OpType)
VARIANT_ENUM_CAST(VisualShaderNodeDerivativeFunc::Function) VARIANT_ENUM_CAST(VisualShaderNodeDerivativeFunc::Function)
VARIANT_ENUM_CAST(VisualShaderNodeDerivativeFunc::Precision)
/////////////////////////////////////// ///////////////////////////////////////
/// FACEFORWARD /// FACEFORWARD

View File

@ -2837,6 +2837,20 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "dFdx", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, false }, { "dFdx", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, false },
{ "dFdx", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, false }, { "dFdx", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, false },
// dFdxCoarse
{ "dFdxCoarse", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdxCoarse", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdxCoarse", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdxCoarse", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
// dFdxFine
{ "dFdxFine", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdxFine", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdxFine", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdxFine", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
// dFdy // dFdy
{ "dFdy", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, false }, { "dFdy", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, false },
@ -2844,6 +2858,20 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "dFdy", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, false }, { "dFdy", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, false },
{ "dFdy", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, false }, { "dFdy", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, false },
// dFdyCoarse
{ "dFdyCoarse", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdyCoarse", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdyCoarse", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdyCoarse", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
// dFdyFine
{ "dFdyFine", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdyFine", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdyFine", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "dFdyFine", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
// fwidth // fwidth
{ "fwidth", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, false }, { "fwidth", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, false },
@ -2851,6 +2879,20 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "fwidth", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, false }, { "fwidth", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, false },
{ "fwidth", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, false }, { "fwidth", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, false },
// fwidthCoarse
{ "fwidthCoarse", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "fwidthCoarse", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "fwidthCoarse", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "fwidthCoarse", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
// fwidthFine
{ "fwidthFine", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "fwidthFine", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "fwidthFine", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
{ "fwidthFine", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true },
// Sub-functions. // Sub-functions.
// array // array