Last active
October 9, 2020 11:43
-
-
Save PranavSK/191dd40331561277a512f87df3d70bea to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tool | |
extends ShaderMaterial | |
class_name StylizedMaterial | |
""" | |
""" | |
enum BlendMode {MIX, ADD, SUB, MUL} | |
enum DepthDrawMode {OPAQUE_ONLY, ALWAYS, DISABLED, ALPHA_OPAQUE_PREPASS} | |
enum CullMode {BACK, FRONT, DISABLED} | |
enum CelPrimaryMode {NONE, SINGLE, MULTI} | |
export(BlendMode) var blend_mode: int = BlendMode.MIX setget set_blend_mode, get_blend_mode | |
export(DepthDrawMode) var depth_draw_mode: int = DepthDrawMode.OPAQUE_ONLY setget set_depth_draw_mode, get_depth_draw_mode | |
export(CullMode) var cull_mode: int = CullMode.BACK setget set_cull_mode, get_cull_mode | |
export var recieve_shadows: = true setget enable_recieve_shadows, is_recieve_shadows_enabled | |
export var ambient_light: = false setget enable_ambient_light, is_ambient_light_enabled | |
export(CelPrimaryMode) var cel_shading_mode: int = CelPrimaryMode.NONE setget set_cel_shading_mode, get_cel_shading_mode | |
export var extra_cel: = false setget enable_extra_cel, is_extra_cel_enabled | |
export var specular: = false setget enable_specular, is_specular_enabled | |
export var rim: = false setget enable_rim, is_rim_enabled | |
export var height_gradient: = false setget enable_height_gradient, is_height_gradient_enabled | |
# Additional params | |
export var vertex_color: = false setget enable_vertex_color, is_vertex_color_enabled | |
var _is_shader_updating: = false | |
func set_blend_mode(value): | |
blend_mode = value; | |
_queue_shader_update() | |
func get_blend_mode(): | |
return blend_mode | |
func set_depth_draw_mode(value): | |
depth_draw_mode = value | |
_queue_shader_update() | |
func get_depth_draw_mode(): | |
return depth_draw_mode | |
func set_cull_mode(value): | |
cull_mode = value | |
_queue_shader_update() | |
func get_cull_mode(): | |
return cull_mode | |
func enable_recieve_shadows(value): | |
recieve_shadows = value | |
_queue_shader_update() | |
func is_recieve_shadows_enabled(): | |
return recieve_shadows | |
func enable_ambient_light(value): | |
ambient_light = value | |
_queue_shader_update() | |
func is_ambient_light_enabled(): | |
return ambient_light | |
func set_cel_shading_mode(value): | |
cel_shading_mode = value | |
_queue_shader_update() | |
func get_cel_shading_mode(): | |
return cel_shading_mode | |
func enable_extra_cel(value): | |
extra_cel = value | |
_queue_shader_update() | |
func is_extra_cel_enabled(): | |
return extra_cel | |
func enable_specular(value): | |
specular = value | |
_queue_shader_update() | |
func is_specular_enabled(): | |
return specular | |
func enable_rim(value): | |
rim = value | |
_queue_shader_update() | |
func is_rim_enabled(): | |
return rim | |
func enable_height_gradient(value): | |
height_gradient = value | |
_queue_shader_update() | |
func is_height_gradient_enabled(): | |
return height_gradient | |
func enable_vertex_color(value): | |
vertex_color = value | |
_queue_shader_update() | |
func is_vertex_color_enabled(): | |
return vertex_color | |
func _queue_shader_update(): | |
if not _is_shader_updating: | |
call_deferred("_generate_shader_code") | |
# _generate_shader_code() | |
_is_shader_updating = true | |
func _generate_shader_code(): | |
print_debug("Updating Shader") | |
if not shader: | |
shader = Shader.new() | |
shader.code = "" | |
shader.code += "shader_type spatial;" | |
shader.code += "\nrender_mode " | |
match blend_mode: | |
BlendMode.MIX: shader.code += "blend_mix" | |
BlendMode.ADD: shader.code += "blend_add" | |
BlendMode.SUB: shader.code += "blend_sub" | |
BlendMode.MUL: shader.code += "blend_mul" | |
match depth_draw_mode: | |
DepthDrawMode.OPAQUE_ONLY: shader.code += ",depth_draw_opaque" | |
DepthDrawMode.ALWAYS: shader.code += ",depth_draw_always" | |
DepthDrawMode.DISABLED: shader.code += ",depth_draw_never" | |
DepthDrawMode.ALPHA_OPAQUE_PREPASS: shader.code += ",depth_draw_alpha_prepass" | |
match cull_mode: | |
CullMode.BACK: shader.code += ",cull_back" | |
CullMode.FRONT: shader.code += ",cull_front" | |
CullMode.DISABLED: shader.code += ",cull_disabled" | |
if cel_shading_mode == CelPrimaryMode.NONE: | |
shader.code += ",unshaded" | |
if not recieve_shadows: | |
shader.code += ",shadows_disabled"; | |
if not ambient_light: | |
shader.code += ",ambient_light_disabled" | |
shader.code += ";\n" | |
shader.code += "uniform vec4 color_primary: hint_color = vec4(1.0, 1.0, 1.0, 1.0);\n" | |
shader.code += "uniform sampler2D texture_primary: hint_albedo;\n" | |
if not cel_shading_mode == CelPrimaryMode.NONE: | |
if cel_shading_mode == CelPrimaryMode.SINGLE: | |
shader.code += "uniform vec4 color_shaded: hint_color = vec4(0.86, 0.86, 0.86, 1.0);\n" | |
shader.code += "uniform float self_shading_size: hint_range(0.0, 1.0) = 0.5;\n" | |
shader.code += "uniform float shadow_edge_size: hint_range(0.0, 0.5) = 0.05;\n" | |
shader.code += "uniform float flatness: hint_range(0.0, 1.0) = 1.0;\n" | |
elif cel_shading_mode == CelPrimaryMode.MULTI: | |
shader.code += "uniform vec4 color_shaded: hint_color = vec4(0.86, 0.86, 0.86, 1.0);\n" | |
shader.code += "uniform sampler2D cel_step_texture: hint_white;\n" | |
if extra_cel: | |
shader.code += "uniform vec4 extra_color_shaded: hint_color = vec4(0.86, 0.86, 0.86, 1.0);\n" | |
shader.code += "uniform float extra_self_shading_size: hint_range(0.0, 1.0) = 0.6;\n" | |
shader.code += "uniform float extra_shadow_edge_size: hint_range(0.0, 0.5) = 0.05;\n" | |
shader.code += "uniform float extra_flatness: hint_range(0.0, 1.0) = 1.0;\n" | |
if specular: | |
shader.code += "uniform vec4 specular_color: hint_color = vec4(0.86, 0.86, 0.86, 1.0);\n" | |
shader.code += "uniform float specular_size: hint_range(0.0, 1.0) = 0.1;\n" | |
shader.code += "uniform float specular_edge_smoothness: hint_range(0.0, 1.0) = 0.0;\n" | |
if rim: | |
shader.code += "uniform vec4 rim_color: hint_color = vec4(0.86, 0.86, 0.86, 1.0);\n" | |
shader.code += "uniform float rim_light_align: hint_range(0.0, 1.0) = 0;\n" | |
shader.code += "uniform float rim_size: hint_range(0.0, 1.0) = 0.5;\n" | |
shader.code += "uniform float rim_edge_smoothness: hint_range(0.0, 1.0) = 0.5;\n" | |
if height_gradient: | |
shader.code += "uniform vec4 height_gradient_color: hint_color = vec4(0.86, 0.86, 0.86, 1.0);\n" | |
shader.code += "uniform vec2 height_gradient_center = vec2(0.0, 0.0);\n" | |
shader.code += "uniform float height_gradient_size = 10.0;\n" | |
shader.code += "uniform float height_gradient_angle: hint_range(0.0, 360.0) = 0.0;\n" | |
shader.code += "float cel_transition(float ndotl, float p_self_shading_size, float p_shadow_edge_size, float p_flatness) {\n" | |
shader.code += "\tfloat angle_diff = clamp((ndotl * 0.5 + 0.5) - p_self_shading_size, 0.0, 1.0);\n" | |
shader.code += "\tfloat angle_diff_transition = smoothstep(0.0, p_shadow_edge_size, angle_diff);\n" | |
shader.code += "\treturn mix(angle_diff, angle_diff_transition, p_flatness);\n" | |
shader.code += "}\n" | |
if cel_shading_mode == CelPrimaryMode.SINGLE: | |
shader.code += "float cel_transition_primary(float ndotl) {\n" | |
shader.code += "\treturn cel_transition(ndotl, self_shading_size, shadow_edge_size, flatness);\n" | |
shader.code += "}\n" | |
elif cel_shading_mode == CelPrimaryMode.MULTI: | |
shader.code += "float cel_transition_texture(float ndotl, sampler2D step_texture) {\n" | |
shader.code += "\tfloat angle_diff = clamp((ndotl * 0.5 + 0.5), 0.0, 1.0);\n" | |
shader.code += "\treturn texture(step_texture, vec2(angle_diff, 0.5)).r;\n" | |
shader.code += "}\n" | |
if extra_cel: | |
shader.code += "float cel_transition_extra(float ndotl){\n" | |
shader.code += "\treturn cel_transition(ndotl, extra_self_shading_size, extra_shadow_edge_size, extra_flatness);\n" | |
shader.code += "}\n" | |
if height_gradient: | |
shader.code += "varying vec3 world_pos;\n" | |
shader.code += "\n" | |
shader.code += "void vertex() {\n" | |
shader.code += "\tvec4 world = WORLD_MATRIX * vec4(VERTEX, 1.0);\n" | |
shader.code += "\tworld_pos = world.xyz / world.w;\n" | |
shader.code += "}\n" | |
shader.code += "void fragment(){\n" | |
shader.code += "\tvec4 primary = texture(texture_primary, UV) * color_primary;\n" | |
if vertex_color: | |
shader.code += "\tprimary *= COLOR;\n" | |
shader.code += "\tALBEDO = primary.rgb;\n//\tALPHA = primary.a;\n" | |
shader.code += "}\n" | |
if not cel_shading_mode == CelPrimaryMode.NONE: | |
shader.code += "void light(){\n" | |
shader.code += "\tvec4 color = color_primary;\n" | |
shader.code += "\tfloat ndotl = dot(NORMAL, LIGHT);\n" | |
if cel_shading_mode == CelPrimaryMode.SINGLE: | |
shader.code += "\tfloat cel_transition = cel_transition_primary(ndotl);\n" | |
elif cel_shading_mode == CelPrimaryMode.MULTI: | |
shader.code += "\tfloat cel_transition = cel_transition_texture(ndotl, cel_step_texture);\n" | |
shader.code += "\tcolor = mix(color_shaded, color, cel_transition);\n" | |
if extra_cel: | |
shader.code += "\tfloat extra_cel_transition = cel_transition_extra(ndotl);\n" | |
shader.code += "\tcolor = mix(extra_color_shaded, color, extra_cel_transition);\n" | |
if height_gradient: | |
shader.code += "\tfloat angle_radians = radians(height_gradient_angle / 180.0);\n" | |
shader.code += "\tfloat pos_grad_rotated = (world_pos.x - height_gradient_center.x) * sin(angle_radians) + (world_pos.y - height_gradient_center.y) * cos(angle_radians);\n" | |
shader.code += "\tfloat gradient_top = height_gradient_center.y + height_gradient_size * 0.5;\n" | |
shader.code += "\tfloat gradient_factor = clamp((gradient_top - pos_grad_rotated) / height_gradient_size, 0.0, 1.0);\n" | |
shader.code += "\tcolor = mix(height_gradient_color, color, gradient_factor);\n" | |
if rim: | |
shader.code += "\tfloat rim = 1.0 - dot(VIEW, NORMAL);\n" | |
shader.code += "\tfloat rim_spread = 1.0 - rim_size - ndotl * rim_light_align;\n" | |
shader.code += "\tfloat rim_transition = smoothstep(rim_spread - rim_edge_smoothness * 0.5, rim_spread + rim_edge_smoothness * 0.5, rim);\n" | |
shader.code += "\tcolor = mix(color, rim_color, rim_transition);\n" | |
if specular: | |
shader.code += "\tvec3 half_vector = normalize(VIEW + LIGHT);\n" | |
shader.code += "\tfloat ndoth = dot(NORMAL, half_vector) * 0.5 + 0.5;\n" | |
shader.code += "\tfloat specular = clamp(pow(ndoth, 100.0 * (1.0 - specular_size) * (1.0 - specular_size)), 0.0, 1.0);\n" | |
shader.code += "\tfloat specular_transition = smoothstep(0.5 - specular_edge_smoothness * 0.1, 0.5 + specular_edge_smoothness * 0.1, specular);\n" | |
shader.code += "\tSPECULAR_LIGHT = mix(vec4(0.0,0.0,0.0,1.0), specular_color, specular_transition).rgb * ALBEDO;\n" | |
shader.code += "\tDIFFUSE_LIGHT += color.rgb * ALBEDO;\n" | |
shader.code += "//\tALPHA = color.a;\n" | |
shader.code +="}\n" | |
_is_shader_updating = false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment