Material compiler fixes

This commit is contained in:
luboslenco 2018-05-21 17:55:26 +02:00
parent 083cebe60f
commit 0c4cc2fc70
11 changed files with 352 additions and 258 deletions

View file

@ -80,6 +80,7 @@ void main() {
vec2 metrough = unpackFloat(g0.b);
vec4 g1 = texture(gbuffer1, texCoord); // Basecolor.rgb, spec/occ
float spec = floor(g1.a) / 100.0;
vec3 albedo = surfaceAlbedo(g1.rgb, metrough.x); // g1.rgb - basecolor
#ifdef _IndPos
@ -109,11 +110,14 @@ void main() {
#else
vec4 indirectDiffuse = traceDiffuse(voxpos, n, voxels);
#endif
vec3 indirectSpecular = traceSpecular(voxels, voxpos, n, v, metrough.y);
indirectSpecular *= f0 * envBRDF.x + envBRDF.y;
fragColor.rgb = indirectDiffuse.rgb * voxelgiDiff * g1.rgb + indirectSpecular * voxelgiSpec;
fragColor.rgb = indirectDiffuse.rgb * voxelgiDiff * g1.rgb;
if (spec > 0.0) {
vec3 indirectSpecular = traceSpecular(voxels, voxpos, n, v, metrough.y);
indirectSpecular *= f0 * envBRDF.x + envBRDF.y;
fragColor.rgb += indirectSpecular * voxelgiSpec * spec;
}
// if (!isInsideCube(voxpos)) fragColor = vec4(1.0); // Show bounds
@ -147,7 +151,7 @@ void main() {
envl.rgb *= albedo;
#ifdef _Rad // Indirect specular
envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;
envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5 * spec;
#else
#ifdef _EnvCol
envl.rgb += backgroundCol * surfaceF0(g1.rgb, metrough.x); // f0

View file

@ -204,7 +204,7 @@ void main() {
const float shinyPerpendicular = 0.1;
const vec3 v = vec3(0.99146, 0.11664, 0.05832);
vec3 T = abs(dot(n, v)) > 0.99999 ? cross(n, vec3(0.0, 1.0, 0.0)) : cross(n, v);
fragColor.rgb = orenNayarDiffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH) + wardSpecular(n, h, dotNL, dotNV, dotNH, T, shinyParallel, shinyPerpendicular);
fragColor.rgb = orenNayarDiffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH) + wardSpecular(n, h, dotNL, dotNV, dotNH, T, shinyParallel, shinyPerpendicular) * spec;
}
else fragColor.rgb = lambertDiffuseBRDF(albedo, dotNL) + specularBRDF(f0, metrough.y, dotNL, dotNH, dotNV, dotVH) * spec;
#else

View file

@ -75,6 +75,7 @@ out vec4 fragColor;
void main() {
vec4 g0 = texture(gbuffer0, texCoord); // Normal.xy, metallic/roughness, depth
vec4 g1 = texture(gbuffer1, texCoord); // Basecolor.rgb, spec/occ
float spec = floor(g1.a) / 100.0;
// float depth = texture(gbufferD, texCoord).r * 2.0 - 1.0; // 0 - 1 => -1 - 1
// TODO: store_depth
// TODO: Firefox throws feedback loop detected error, read depth from gbuffer0
@ -136,14 +137,14 @@ void main() {
const float shinyPerpendicular = 0.1;
const vec3 v = vec3(0.99146, 0.11664, 0.05832);
vec3 T = abs(dot(n, v)) > 0.99999 ? cross(n, vec3(0.0, 1.0, 0.0)) : cross(n, v);
fragColor.rgb = orenNayarDiffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH) + wardSpecular(n, h, dotNL, dotNV, dotNH, T, shinyParallel, shinyPerpendicular);
fragColor.rgb = orenNayarDiffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH) + wardSpecular(n, h, dotNL, dotNV, dotNH, T, shinyParallel, shinyPerpendicular) * spec;
}
else fragColor.rgb = lambertDiffuseBRDF(albedo, dotNL) + specularBRDF(f0, metrough.y, dotNL, dotNH, dotNV, dotVH);
else fragColor.rgb = lambertDiffuseBRDF(albedo, dotNL) + specularBRDF(f0, metrough.y, dotNL, dotNH, dotNV, dotVH) * spec;
#else
#ifdef _OrenNayar
fragColor.rgb = orenNayarDiffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH) + specularBRDF(f0, metrough.y, dotNL, dotNH, dotNV, dotVH);
fragColor.rgb = orenNayarDiffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH) + specularBRDF(f0, metrough.y, dotNL, dotNH, dotNV, dotVH) * spec;
#else
fragColor.rgb = lambertDiffuseBRDF(albedo, dotNL) + specularBRDF(f0, metrough.y, dotNL, dotNH, dotNV, dotVH);
fragColor.rgb = lambertDiffuseBRDF(albedo, dotNL) + specularBRDF(f0, metrough.y, dotNL, dotNH, dotNV, dotVH) * spec;
#endif
#endif

View file

@ -7,6 +7,7 @@
uniform sampler2D tex;
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0; // Normal, roughness
uniform sampler2D gbuffer1; // basecol, spec
uniform mat4 P;
uniform mat4 tiV;
uniform vec2 cameraProj;
@ -129,6 +130,12 @@ void main() {
fragColor.rgb = vec3(0.0);
return;
}
float spec = floor(texture(gbuffer1, texCoord).a) / 100.0;
if (spec == 0.0) {
fragColor.rgb = vec3(0.0);
return;
}
float d = texture(gbufferD, texCoord).r * 2.0 - 1.0;
if (d == 1.0) {

View file

@ -715,6 +715,7 @@ class RenderPathDeferred {
path.bindTarget("tex", "tex");
path.bindTarget("_main", "gbufferD");
path.bindTarget("gbuffer0", "gbuffer0");
path.bindTarget("gbuffer1", "gbuffer1");
path.drawShader("shader_datas/ssr_pass/ssr_pass");
path.setTarget(targetb);

View file

@ -143,10 +143,8 @@ def parse_input(inp):
def parse_shader_input(inp):
if inp.is_linked:
l = inp.links[0]
if l.from_node.type == 'REROUTE':
return parse_shader_input(l.from_node.inputs[0])
return parse_shader(l.from_node, l.from_socket)
else:
out_basecol = 'vec3(0.8)'
@ -157,16 +155,6 @@ def parse_shader_input(inp):
out_opacity = '1.0'
return out_basecol, out_roughness, out_metallic, out_occlusion, out_specular, out_opacity
def write_normal(inp):
if inp.is_linked:
normal_res = parse_vector_input(inp)
if normal_res != None:
curshader.write('n = {0};'.format(normal_res))
def parsing_basecolor(b):
global parsing_basecol
parsing_basecol = b
def parse_shader(node, socket):
global emission_found
out_basecol = 'vec3(0.8)'
@ -177,8 +165,7 @@ def parse_shader(node, socket):
out_opacity = '1.0'
if node.type == 'GROUP':
if node.node_tree.name.startswith('Armory PBR'):
if node.node_tree.name.startswith('Armory PBR'):
if parse_surface:
# Base color
parsing_basecolor(True)
@ -199,10 +186,8 @@ def parse_shader(node, socket):
out_emission = parse_value_input(node.inputs[6])
emission_found = True
out_basecol = '({0} + vec3({1} * 100.0))'.format(out_basecol, out_emission)
if parse_opacity:
out_opacity = parse_value_input(node.inputs[1])
else:
return parse_group(node, socket)
@ -254,7 +239,7 @@ def parse_shader(node, socket):
# subsurface = parse_vector_input(node.inputs[1])
# subsurface_radius = parse_vector_input(node.inputs[2])
# subsurface_color = parse_vector_input(node.inputs[3])
# specular = parse_vector_input(node.inputs[5])
out_specular = parse_value_input(node.inputs[5])
# specular_tint = parse_vector_input(node.inputs[6])
# aniso = parse_vector_input(node.inputs[8])
# aniso_rot = parse_vector_input(node.inputs[9])
@ -368,71 +353,20 @@ def parse_shader(node, socket):
def parse_displacement_input(inp):
if inp.is_linked:
l = inp.links[0]
if l.from_node.type == 'REROUTE':
return parse_displacement_input(l.from_node.inputs[0])
return parse_value_input(inp)
else:
return None
def res_var_name(node, socket):
return node_name(node.name) + '_' + safesrc(socket.name) + '_res'
def write_result(l):
res_var = res_var_name(l.from_node, l.from_socket)
st = l.from_socket.type
if res_var not in parsed:
parsed[res_var] = 0
if st == 'RGB' or st == 'RGBA':
res = parse_rgb(l.from_node, l.from_socket)
if res == None:
return None
curshader.write('vec3 {0} = {1};'.format(res_var, res))
elif st == 'VECTOR':
res = parse_vector(l.from_node, l.from_socket)
if res == None:
return None
size = 3
if isinstance(res, tuple):
size = res[1]
parsed[res_var] = size
res = res[0]
curshader.write('vec{2} {0} = {1};'.format(res_var, res, size))
elif st == 'VALUE':
res = parse_value(l.from_node, l.from_socket)
if res == None:
return None
curshader.write('float {0} = {1};'.format(res_var, res))
# Normal map already parsed, return
elif l.from_node.type == 'NORMAL_MAP':
return None
return res_var
def glsl_type(t):
if t == 'RGB' or t == 'RGBA' or t == 'VECTOR':
return 'vec3'
else:
return 'float'
def to_uniform(inp):
uname = safesrc(inp.node.name) + safesrc(inp.name)
curshader.add_uniform(glsl_type(inp.type) + ' ' + uname)
return uname
def parse_vector_input(inp, vec_size=None):
def parse_vector_input(inp):
if inp.is_linked:
l = inp.links[0]
if l.from_node.type == 'REROUTE':
return parse_vector_input(l.from_node.inputs[0], vec_size=vec_size)
return parse_vector_input(l.from_node.inputs[0])
res_var = write_result(l)
st = l.from_socket.type
if st == 'RGB' or st == 'RGBA' or st == 'VECTOR':
# Convert
if vec_size == 3 and parsed[res_var] == 2:
res_var = 'vec3({0}.xy, 0.0)'.format(res_var)
return res_var
else: # VALUE
return 'vec3({0})'.format(res_var)
@ -463,15 +397,23 @@ def parse_rgb(node, socket):
return to_vec3(socket.default_value)
elif node.type == 'TEX_BRICK':
# Pass through
return to_vec3([0.0, 0.0, 0.0])
curshader.add_function(c_functions.str_tex_brick)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
col1 = parse_vector_input(node.inputs[1])
col2 = parse_vector_input(node.inputs[2])
col3 = parse_vector_input(node.inputs[3])
scale = parse_value_input(node.inputs[4])
return 'tex_brick({0} * {4}, {1}, {2}, {3})'.format(co, col1, col2, col3, scale)
elif node.type == 'TEX_CHECKER':
curshader.add_function(c_functions.str_tex_checker)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'mposition'
co = 'bposition'
col1 = parse_vector_input(node.inputs[1])
col2 = parse_vector_input(node.inputs[2])
scale = parse_value_input(node.inputs[3])
@ -485,7 +427,7 @@ def parse_rgb(node, socket):
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'mposition'
co = 'bposition'
grad = node.gradient_type
if grad == 'LINEAR':
f = '{0}.x'.format(co)
@ -526,27 +468,35 @@ def parse_rgb(node, socket):
return '{0}.rgb'.format(tex_store)
elif node.type == 'TEX_MAGIC':
# Pass through
return to_vec3([0.0, 0.0, 0.0])
elif node.type == 'TEX_MUSGRAVE':
# Fall back to noise
curshader.add_function(c_functions.str_tex_noise)
curshader.add_function(c_functions.str_tex_magic)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'mposition'
co = 'bposition'
scale = parse_value_input(node.inputs[1])
return 'vec3(tex_magic({0} * {1} * 4.0))'.format(co, scale)
elif node.type == 'TEX_MUSGRAVE':
curshader.add_function(c_functions.str_tex_musgrave)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
scale = parse_value_input(node.inputs[1])
# detail = parse_value_input(node.inputs[2])
# distortion = parse_value_input(node.inputs[3])
return 'vec3(tex_noise_f({0} * {1}))'.format(co, scale)
return 'vec3(tex_musgrave_f({0} * {1} * 0.5))'.format(co, scale)
elif node.type == 'TEX_NOISE':
curshader.add_function(c_functions.str_tex_noise)
assets_add(get_sdk_path() + '/armory/Assets/' + 'noise256.png')
assets_add_embedded_data('noise256.png')
curshader.add_uniform('sampler2D snoise256', link='_noise256')
curshader.add_function(c_functions.str_tex_noise)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'mposition'
co = 'bposition'
scale = parse_value_input(node.inputs[1])
# detail = parse_value_input(node.inputs[2])
# distortion = parse_value_input(node.inputs[3])
@ -563,34 +513,33 @@ def parse_rgb(node, socket):
elif node.type == 'TEX_VORONOI':
curshader.add_function(c_functions.str_tex_voronoi)
assets_add(get_sdk_path() + '/armory/Assets/' + 'noise64.png')
assets_add_embedded_data('noise64.png')
curshader.add_uniform('sampler2D snoise', link='_noise64')
assets_add(get_sdk_path() + '/armory/Assets/' + 'noise256.png')
assets_add_embedded_data('noise256.png')
curshader.add_uniform('sampler2D snoise256', link='_noise256')
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'mposition'
co = 'bposition'
scale = parse_value_input(node.inputs[1])
if node.coloring == 'INTENSITY':
return 'vec3(tex_voronoi({0} / (1.0 / {1})).a)'.format(co, scale)
return 'vec3(tex_voronoi({0} * {1}).a)'.format(co, scale)
else: # CELLS
return 'tex_voronoi({0} / (1.0 / {1})).rgb'.format(co, scale)
return 'tex_voronoi({0} * {1}).rgb'.format(co, scale)
elif node.type == 'TEX_WAVE':
# Pass through
return to_vec3([0.0, 0.0, 0.0])
curshader.add_function(c_functions.str_tex_wave)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
scale = parse_value_input(node.inputs[1])
return 'vec3(tex_wave_f({0} * {1}))'.format(co, scale)
elif node.type == 'BRIGHTCONTRAST':
out_col = parse_vector_input(node.inputs[0])
bright = parse_value_input(node.inputs[1])
contr = parse_value_input(node.inputs[2])
curshader.add_function(\
"""vec3 brightcontrast(const vec3 col, const float bright, const float contr) {
float a = 1.0 + contr;
float b = bright - contr * 0.5;
return max(a * col + b, 0.0);
}
""")
curshader.add_function(c_functions.str_brightcontrast)
return 'brightcontrast({0}, {1}, {2})'.format(out_col, bright, contr)
elif node.type == 'GAMMA':
@ -616,8 +565,8 @@ def parse_rgb(node, socket):
fac = parse_value_input(node.inputs[0])
fac_var = node_name(node.name) + '_fac'
curshader.write('float {0} = {1};'.format(fac_var, fac))
col1 = parse_vector_input(node.inputs[1], vec_size=3)
col2 = parse_vector_input(node.inputs[2], vec_size=3)
col1 = parse_vector_input(node.inputs[1])
col2 = parse_vector_input(node.inputs[2])
blend = node.blend_type
if blend == 'MIX':
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var)
@ -693,20 +642,6 @@ def parse_rgb(node, socket):
return 'mix({0}, {1}, clamp(({2} - {3}) * (1.0 / (1.0 - {3})), 0.0, 1.0))'.format(to_vec3(elems[0].color), to_vec3(elems[1].color), fac, elems[0].position)
elif node.type == 'COMBHSV':
# vec3 hsv2rgb(vec3 c) {
# vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
# vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
# return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
# }
# vec3 rgb2hsv(vec3 c) {
# vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
# vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
# vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
# float d = q.x - min(q.w, q.y);
# float e = 1.0e-10;
# return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
# }
# Pass constant
return to_vec3([0.0, 0.0, 0.0])
@ -722,39 +657,6 @@ def parse_rgb(node, socket):
# Roughly map to cycles - 450 to 600 nanometers
return 'wavelength_to_rgb(({0} - 450.0) / 150.0)'.format(wl)
def store_var_name(node):
return node_name(node.name) + '_store'
def texture_store(node, tex, tex_name, to_linear=False):
global parsing_basecol
global basecol_texname
global sample_bump
global sample_bump_res
mat_bind_texture(tex)
con.add_elem('tex', 2)
curshader.add_uniform('sampler2D {0}'.format(tex_name))
if node.inputs[0].is_linked:
uv_name = parse_vector_input(node.inputs[0])
else:
uv_name = 'texCoord'
tex_store = store_var_name(node)
if mat_texture_grad():
curshader.write('vec4 {0} = textureGrad({1}, {2}.xy, g2.xy, g2.zw);'.format(tex_store, tex_name, uv_name))
else:
curshader.write('vec4 {0} = texture({1}, {2}.xy);'.format(tex_store, tex_name, uv_name))
if sample_bump:
sample_bump_res = tex_store
curshader.write('float {0}_1 = textureOffset({1}, {2}, ivec2(-2, 0)).r;'.format(tex_store, tex_name, uv_name))
curshader.write('float {0}_2 = textureOffset({1}, {2}, ivec2(2, 0)).r;'.format(tex_store, tex_name, uv_name))
curshader.write('float {0}_3 = textureOffset({1}, {2}, ivec2(0, -2)).r;'.format(tex_store, tex_name, uv_name))
curshader.write('float {0}_4 = textureOffset({1}, {2}, ivec2(0, 2)).r;'.format(tex_store, tex_name, uv_name))
sample_bump = False
if to_linear:
curshader.write('{0}.rgb = pow({0}.rgb, vec3(2.2));'.format(tex_store))
if parsing_basecol:
basecol_texname = tex_store
return tex_store
def parse_vector(node, socket):
global particle_info
global sample_bump
@ -778,8 +680,8 @@ def parse_vector(node, socket):
# Second uvmap referenced
if len(lays) > 1 and node.attribute_name == lays[1].name:
con.add_elem('tex1', 2)
return 'texCoord1', 2
return 'texCoord', 2
return 'vec3(texCoord1.xy, 0.0)'
return 'vec3(texCoord.xy, 0.0)'
elif node.type == 'CAMERA':
# View Vector
@ -822,26 +724,26 @@ def parse_vector(node, socket):
elif node.type == 'TEX_COORD':
#obj = node.object
#dupli = node.from_dupli
if socket == node.outputs[0]: # Generated
return 'vec2(0.0)', 2
if socket == node.outputs[0]: # Generated - bounds
return 'bposition'
elif socket == node.outputs[1]: # Normal
return 'vec2(0.0)', 2
return 'n'
elif socket == node.outputs[2]: # UV
con.add_elem('tex', 2)
return 'texCoord', 2
return 'vec3(texCoord.x, 1.0 - texCoord.y, 0.0)'
elif socket == node.outputs[3]: # Object
return 'vec2(0.0)', 2
return 'mposition'
elif socket == node.outputs[4]: # Camera
return 'vec2(0.0)', 2
return 'vec3(0.0)' # 'vposition'
elif socket == node.outputs[5]: # Window
return 'vec2(0.0)', 2
return 'vec3(0.0)' # 'wvpposition'
elif socket == node.outputs[6]: # Reflection
return 'vec2(0.0)', 2
return 'vec3(0.0)'
elif node.type == 'UVMAP':
#map = node.uv_map
#dupli = node.from_dupli
return 'vec2(0.0)', 2
return 'vec3(0.0)'
elif node.type == 'BUMP':
# Interpolation strength
@ -872,22 +774,22 @@ def parse_vector(node, socket):
# ZYX rotation, Z axis for now..
if node.rotation[2] != 0.0:
a = node.rotation[2]
out = 'vec2({0}.x * {1} - (1.0 - {0}.y) * {2}, 1.0 - ({0}.x * {2} + (1.0 - {0}.y) * {1}))'.format(out, math.cos(a), math.sin(a))
out = 'vec3({0}.x * {1} - (1.0 - {0}.y) * {2}, 1.0 - ({0}.x * {2} + (1.0 - {0}.y) * {1}), 0.0)'.format(out, math.cos(a), math.sin(a))
# if node.rotation[1] != 0.0:
# a = node.rotation[1]
# out = 'vec2({0}.x * {1} - {0}.z * {2}, {0}.x * {2} + {0}.z * {1})'.format(out, math.cos(a), math.sin(a))
# out = 'vec3({0}.x * {1} - {0}.z * {2}, {0}.x * {2} + {0}.z * {1}, 0.0)'.format(out, math.cos(a), math.sin(a))
# if node.rotation[0] != 0.0:
# a = node.rotation[0]
# out = 'vec2({0}.y * {1} - {0}.z * {2}, {0}.y * {2} + {0}.z * {1})'.format(out, math.cos(a), math.sin(a))
# out = 'vec3({0}.y * {1} - {0}.z * {2}, {0}.y * {2} + {0}.z * {1}, 0.0)'.format(out, math.cos(a), math.sin(a))
if node.scale[0] != 1.0 or node.scale[1] != 1.0 or node.scale[2] != 1.0:
out = '({0} * vec2({1}, {2}))'.format(out, node.scale[0], node.scale[1])
out = '({0} * vec3({1}, {2}, {3}))'.format(out, node.scale[0], node.scale[1], node.scale[2])
if node.translation[0] != 0.0 or node.translation[1] != 0.0 or node.translation[2] != 0.0:
out = '({0} + vec2({1}, {2}))'.format(out, node.translation[0], node.translation[1])
out = '({0} + vec3({1}, {2}, {3}))'.format(out, node.translation[0], node.translation[1], node.translation[2])
if node.use_min:
out = 'max({0}, vec2({1}, {2}))'.format(out, node.min[0], node.min[1])
out = 'max({0}, vec3({1}, {2}, {3}))'.format(out, node.min[0], node.min[1])
if node.use_max:
out = 'min({0}, vec2({1}, {2}))'.format(out, node.max[0], node.max[1])
return out, 2
out = 'min({0}, vec3({1}, {2}, {3}))'.format(out, node.max[0], node.max[1])
return out
elif node.type == 'NORMAL':
if socket == node.outputs[0]:
@ -1107,25 +1009,47 @@ def parse_value(node, socket):
return '0.0'
elif node.type == 'TEX_BRICK':
return '0.0'
curshader.add_function(c_functions.str_tex_brick)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
scale = parse_value_input(node.inputs[4])
return 'tex_brick_f({0} * {1})'.format(co, scale)
elif node.type == 'TEX_CHECKER':
# TODO: do not recompute when color socket is also connected
curshader.add_function(c_functions.str_tex_checker)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'mposition'
col1 = parse_vector_input(node.inputs[1])
col2 = parse_vector_input(node.inputs[2])
co = 'bposition'
scale = parse_value_input(node.inputs[3])
res = 'tex_checker({0}, {1}, {2}, {3}).r'.format(co, col1, col2, scale)
res = 'tex_checker_f({0}, {1}).r'.format(co, scale)
if sample_bump:
write_bump(node, res)
return res
elif node.type == 'TEX_GRADIENT':
return '0.0'
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
grad = node.gradient_type
if grad == 'LINEAR':
f = '{0}.x'.format(co)
elif grad == 'QUADRATIC':
f = '0.0'
elif grad == 'EASING':
f = '0.0'
elif grad == 'DIAGONAL':
f = '({0}.x + {0}.y) * 0.5'.format(co)
elif grad == 'RADIAL':
f = 'atan({0}.y, {0}.x) / PI2 + 0.5'.format(co)
elif grad == 'QUADRATIC_SPHERE':
f = '0.0'
elif grad == 'SPHERICAL':
f = 'max(1.0 - sqrt({0}.x * {0}.x + {0}.y * {0}.y + {0}.z * {0}.z), 0.0)'.format(co)
return '(clamp({0}, 0.0, 1.0))'.format(f)
elif node.type == 'TEX_IMAGE':
# Already fetched
@ -1144,26 +1068,35 @@ def parse_value(node, socket):
return '{0}.a'.format(tex_store)
elif node.type == 'TEX_MAGIC':
return '0.0'
curshader.add_function(c_functions.str_tex_magic)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
scale = parse_value_input(node.inputs[1])
return 'tex_magic_f({0} * {1} * 4.0)'.format(co, scale)
elif node.type == 'TEX_MUSGRAVE':
# Fall back to noise
curshader.add_function(c_functions.str_tex_noise)
curshader.add_function(c_functions.str_tex_musgrave)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'mposition'
co = 'bposition'
scale = parse_value_input(node.inputs[1])
# detail = parse_value_input(node.inputs[2])
# distortion = parse_value_input(node.inputs[3])
return 'tex_noise_f({0} * {1})'.format(co, scale)
return 'tex_musgrave_f({0} * {1} * 0.5)'.format(co, scale)
elif node.type == 'TEX_NOISE':
curshader.add_function(c_functions.str_tex_noise)
assets_add(get_sdk_path() + '/armory/Assets/' + 'noise256.png')
assets_add_embedded_data('noise256.png')
curshader.add_uniform('sampler2D snoise256', link='_noise256')
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'mposition'
co = 'bposition'
scale = parse_value_input(node.inputs[1])
# detail = parse_value_input(node.inputs[2])
# distortion = parse_value_input(node.inputs[3])
@ -1177,21 +1110,27 @@ def parse_value(node, socket):
elif node.type == 'TEX_VORONOI':
curshader.add_function(c_functions.str_tex_voronoi)
assets_add(get_sdk_path() + '/armory/Assets/' + 'noise64.png')
assets_add_embedded_data('noise64.png')
curshader.add_uniform('sampler2D snoise', link='_noise64')
assets_add(get_sdk_path() + '/armory/Assets/' + 'noise256.png')
assets_add_embedded_data('noise256.png')
curshader.add_uniform('sampler2D snoise256', link='_noise256')
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'mposition'
co = 'bposition'
scale = parse_value_input(node.inputs[1])
if node.coloring == 'INTENSITY':
return 'tex_voronoi({0} * (1.0 / {1})).a'.format(co, scale)
return 'tex_voronoi({0} * {1}).a'.format(co, scale)
else: # CELLS
return 'tex_voronoi({0} * (1.0 / {1})).r'.format(co, scale)
return 'tex_voronoi({0} * {1}).r'.format(co, scale)
elif node.type == 'TEX_WAVE':
return '0.0'
curshader.add_function(c_functions.str_tex_wave)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
scale = parse_value_input(node.inputs[1])
return 'tex_wave_f({0} * {1})'.format(co, scale)
elif node.type == 'LIGHT_FALLOFF':
# Constant, linear, quadratic
@ -1288,6 +1227,90 @@ def parse_value(node, socket):
else:
return '0.0'
##
def write_normal(inp):
if inp.is_linked:
normal_res = parse_vector_input(inp)
if normal_res != None:
curshader.write('n = {0};'.format(normal_res))
def parsing_basecolor(b):
global parsing_basecol
parsing_basecol = b
def res_var_name(node, socket):
return node_name(node.name) + '_' + safesrc(socket.name) + '_res'
def write_result(l):
res_var = res_var_name(l.from_node, l.from_socket)
st = l.from_socket.type
if res_var not in parsed:
parsed[res_var] = True
if st == 'RGB' or st == 'RGBA':
res = parse_rgb(l.from_node, l.from_socket)
if res == None:
return None
curshader.write('vec3 {0} = {1};'.format(res_var, res))
elif st == 'VECTOR':
res = parse_vector(l.from_node, l.from_socket)
if res == None:
return None
curshader.write('vec3 {0} = {1};'.format(res_var, res))
elif st == 'VALUE':
res = parse_value(l.from_node, l.from_socket)
if res == None:
return None
curshader.write('float {0} = {1};'.format(res_var, res))
# Normal map already parsed, return
elif l.from_node.type == 'NORMAL_MAP':
return None
return res_var
def glsl_type(t):
if t == 'RGB' or t == 'RGBA' or t == 'VECTOR':
return 'vec3'
else:
return 'float'
def to_uniform(inp):
uname = safesrc(inp.node.name) + safesrc(inp.name)
curshader.add_uniform(glsl_type(inp.type) + ' ' + uname)
return uname
def store_var_name(node):
return node_name(node.name) + '_store'
def texture_store(node, tex, tex_name, to_linear=False):
global parsing_basecol
global basecol_texname
global sample_bump
global sample_bump_res
mat_bind_texture(tex)
con.add_elem('tex', 2)
curshader.add_uniform('sampler2D {0}'.format(tex_name))
if node.inputs[0].is_linked:
uv_name = parse_vector_input(node.inputs[0])
else:
uv_name = 'texCoord'
tex_store = store_var_name(node)
if mat_texture_grad():
curshader.write('vec4 {0} = textureGrad({1}, {2}.xy, g2.xy, g2.zw);'.format(tex_store, tex_name, uv_name))
else:
curshader.write('vec4 {0} = texture({1}, {2}.xy);'.format(tex_store, tex_name, uv_name))
if sample_bump:
sample_bump_res = tex_store
curshader.write('float {0}_1 = textureOffset({1}, {2}.xy, ivec2(-2, 0)).r;'.format(tex_store, tex_name, uv_name))
curshader.write('float {0}_2 = textureOffset({1}, {2}.xy, ivec2(2, 0)).r;'.format(tex_store, tex_name, uv_name))
curshader.write('float {0}_3 = textureOffset({1}, {2}.xy, ivec2(0, -2)).r;'.format(tex_store, tex_name, uv_name))
curshader.write('float {0}_4 = textureOffset({1}, {2}.xy, ivec2(0, 2)).r;'.format(tex_store, tex_name, uv_name))
sample_bump = False
if to_linear:
curshader.write('{0}.rgb = pow({0}.rgb, vec3(2.2));'.format(tex_store))
if parsing_basecol:
basecol_texname = tex_store
return tex_store
def write_bump(node, res):
global sample_bump
global sample_bump_res
@ -1311,15 +1334,9 @@ def write_bump(node, res):
def to_vec1(v):
return str(v)
def to_vec2(v):
return 'vec2({0}, {1})'.format(v[0], v[1])
def to_vec3(v):
return 'vec3({0}, {1}, {2})'.format(v[0], v[1], v[2])
def to_vec4(v):
return 'vec4({0}, {1}, {2}, {3})'.format(v[0], v[1], v[2], v[3])
def node_by_type(nodes, ntype):
for n in nodes:
if n.type == ntype:

View file

@ -1,5 +1,5 @@
str_tex_checker = """vec3 tex_checker(const vec3 co, const vec3 col1, const vec3 col2, const float scale) {
vec3 p = co * scale;
vec3 p = (co) * scale;
// Prevent precision issues on unit coordinates
//p.x = (p.x + 0.000001) * 0.999999;
//p.y = (p.y + 0.000001) * 0.999999;
@ -10,20 +10,18 @@ str_tex_checker = """vec3 tex_checker(const vec3 co, const vec3 col1, const vec3
bool check = ((mod(xi, 2.0) == mod(yi, 2.0)) == bool(mod(zi, 2.0)));
return check ? col1 : col2;
}
vec3 tex_checker(const vec2 co, const vec3 col1, const vec3 col2, const float scale) {
return tex_checker(vec3(co.x, co.y, 1.0), col1, col2, scale);
float tex_checker_f(const vec3 co, const float scale) {
vec3 p = (co) * scale;
float xi = abs(floor(p.x));
float yi = abs(floor(p.y));
float zi = abs(floor(p.z));
return float((mod(xi, 2.0) == mod(yi, 2.0)) == bool(mod(zi, 2.0)));
}
"""
# Created by inigo quilez - iq/2013
# License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
str_tex_voronoi = """//vec3 hash(vec3 x) {
//return texture(snoise, (x.xy + vec2(3.0, 1.0) * x.z + 0.5) / 64.0, -100.0).xyz;
//x = vec3(dot(x, vec3(127.1, 311.7, 74.7)),
// dot(x, vec3(269.5, 183.3, 246.1)),
// dot(x, vec3(113.5, 271.9, 124.6)));
//return fract(sin(x) * 43758.5453123);
//}
str_tex_voronoi = """
vec4 tex_voronoi(const vec3 x) {
vec3 p = floor(x);
vec3 f = fract(x);
@ -34,9 +32,7 @@ vec4 tex_voronoi(const vec3 x) {
for (int i = -1; i <= 1; i++) {
vec3 b = vec3(float(i), float(j), float(k));
vec3 pb = p + b;
//vec3 r = vec3(b) - f + texture(snoise, (pb.xy + vec2(3.0, 1.0) * pb.z + 0.5) / 64.0, -100.0).xyz; // No bias in tese
vec3 r = vec3(b) - f + texture(snoise, (pb.xy + vec2(3.0, 1.0) * pb.z + 0.5) / 64.0).xyz;
//vec3 r = vec3(b) - f + hash(p + b);
vec3 r = vec3(b) - f + texture(snoise256, (pb.xy + vec2(3.0, 1.0) * pb.z + 0.5) / 256.0).xyz;
float d = dot(r, r);
if (d < res) {
id = dot(p + b, vec3(1.0, 57.0, 113.0));
@ -46,36 +42,34 @@ vec4 tex_voronoi(const vec3 x) {
vec3 col = 0.5 + 0.5 * cos(id * 0.35 + vec3(0.0, 1.0, 2.0));
return vec4(col, sqrt(res));
}
vec4 tex_voronoi(const vec2 x) {
return tex_voronoi(vec3(x.x, x.y, 1.0));
"""
# Based on https://www.shadertoy.com/view/4sfGzS
# Copyright © 2013 Inigo Quilez
# The MIT License - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
str_tex_noise = """
float tex_noise_f(const vec3 x) {
vec3 p = floor(x);
vec3 f = fract(x);
f = f * f * (3.0 - 2.0 * f);
vec2 uv = (p.xy + vec2(37.0, 17.0) * p.z) + f.xy;
vec2 rg = texture(snoise256, (uv + 0.5) / 256.0).yx;
return mix(rg.x, rg.y, f.z);
}
float tex_noise(vec3 p) {
p *= 1.25;
float f = 0.5 * tex_noise_f(p); p *= 2.01;
f += 0.25 * tex_noise_f(p); p *= 2.02;
f += 0.125 * tex_noise_f(p); p *= 2.03;
f += 0.0625 * tex_noise_f(p); p *= 2.01;
return 1.0 - f;
}
"""
# str_tex_noise = """
# float tex_noise_f(const vec3 x) {
# vec3 p = floor(x);
# vec3 f = fract(x);
# f = f * f * (3.0 - 2.0 * f);
# vec2 uv = (p.xy + vec2(37.0, 17.0) * p.z) + f.xy;
# vec2 rg = texture(snoisea, (uv + 0.5) / 64.0, -100.0).yx;
# return mix(rg.x, rg.y, f.z);
# }
# float tex_noise(vec3 q) {
# //return fract(sin(dot(q.xy, vec2(12.9898,78.233))) * 43758.5453);
# q *= 2.0; // Match to Cycles
# const mat3 m = mat3(0.00, 0.80, 0.60, -0.80, 0.36, -0.48, -0.60, -0.48, 0.64);
# float f = 0.5000 * tex_noise_f(q); q = m * q * 2.01;
# f += 0.2500 * tex_noise_f(q); q = m * q * 2.02;
# f += 0.1250 * tex_noise_f(q); q = m * q * 2.03;
# f += 0.0625 * tex_noise_f(q); q = m * q * 2.01;
# return pow(f, 3.0);
# }
# """
# Created by Nikita Miropolskiy, nikat/2013
# Based on noise created by Nikita Miropolskiy, nikat/2013
# Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
str_tex_noise = """
str_tex_musgrave = """
vec3 random3(const vec3 c) {
// Might not be precise on lowp floats
float j = 4096.0 * sin(dot(c, vec3(17.0, 59.4, 15.0)));
vec3 r;
r.z = fract(512.0 * j);
@ -85,7 +79,7 @@ vec3 random3(const vec3 c) {
r.y = fract(512.0 * j);
return r - 0.5;
}
float tex_noise_f(const vec3 p) {
float tex_musgrave_f(const vec3 p) {
const float F3 = 0.3333333;
const float G3 = 0.1666667;
vec3 s = floor(p + dot(p, vec3(F3)));
@ -111,15 +105,6 @@ float tex_noise_f(const vec3 p) {
d *= w;
return clamp(dot(d, vec4(52.0)), 0.0, 1.0);
}
float tex_noise(const vec3 p) {
return 0.5333333 * tex_noise_f(0.5 * p)
+ 0.2666667 * tex_noise_f(p)
+ 0.1333333 * tex_noise_f(2.0 * p)
+ 0.0666667 * tex_noise_f(4.0 * p);
}
float tex_noise(const vec2 p) {
return tex_noise(vec3(p.x, p.y, 1.0));
}
"""
str_hsv_to_rgb = """
@ -149,3 +134,47 @@ vec3 wavelength_to_rgb(const float t) {
return 1.0 - r * r;
}
"""
str_tex_magic = """
vec3 tex_magic(const vec3 p) {
float a = 1.0 - (sin(p.x) + sin(p.y));
float b = 1.0 - sin(p.x - p.y);
float c = 1.0 - sin(p.x + p.y);
return vec3(a, b, c);
}
float tex_magic_f(const vec3 p) {
vec3 c = tex_magic(p);
return (c.x + c.y + c.z) / 3.0;
}
"""
str_tex_brick = """
vec3 tex_brick(vec3 p, const vec3 c1, const vec3 c2, const vec3 c3) {
p /= vec3(0.9, 0.49, 0.49) / 2;
if (fract(p.y * 0.5) > 0.5) p.x += 0.5;
p = fract(p);
vec3 b = step(p, vec3(0.95, 0.9, 0.9));
return mix(c3, c1, b.x * b.y * b.z);
}
float tex_brick_f(vec3 p) {
p /= vec3(0.9, 0.49, 0.49) / 2;
if (fract(p.y * 0.5) > 0.5) p.x += 0.5;
p = fract(p);
vec3 b = step(p, vec3(0.95, 0.9, 0.9));
return mix(1.0, 0.0, b.x * b.y * b.z);
}
"""
str_tex_wave = """
float tex_wave_f(const vec3 p) {
return 1.0 - sin((p.x + p.y) * 10.0);
}
"""
str_brightcontrast = """
vec3 brightcontrast(const vec3 col, const float bright, const float contr) {
float a = 1.0 + contr;
float b = bright - contr * 0.5;
return max(a * col + b, 0.0);
}
"""

View file

@ -90,21 +90,15 @@ def make_finalize(con_mesh):
if export_wpos:
vert.add_uniform('mat4 W', '_worldMatrix')
vert.add_out('vec3 wposition')
vert.write_pre = True
vert.write_attrib('wposition = vec4(W * spos).xyz;')
vert.write_pre = False
elif write_wpos:
vert.add_uniform('mat4 W', '_worldMatrix')
vert.write_pre = True
vert.write_attrib('vec3 wposition = vec4(W * spos).xyz;')
vert.write_pre = False
frag_mpos = frag.contains('mposition') and not frag.contains('vec3 mposition')
frag_mpos = frag.contains('mposition') and not frag.contains('vec3 mposition') or vert.contains('mposition')
if frag_mpos:
vert.add_out('vec3 mposition')
vert.write_pre = True
vert.write('mposition = spos.xyz;')
vert.write_pre = False
vert.write_attrib('mposition = spos.xyz;')
if tese != None:
if frag_mpos:
@ -116,6 +110,25 @@ def make_finalize(con_mesh):
vert.write_pre = False
make_tess.interpolate(tese, 'mposition', 3, declare_out=False)
frag_bpos = frag.contains('bposition') and not frag.contains('vec3 bposition') or vert.contains('bposition')
if frag_bpos:
vert.add_out('vec3 bposition')
vert.add_uniform('vec3 dim', link='_dim')
vert.add_uniform('vec3 hdim', link='_halfDim')
vert.write_pre = True
vert.write('bposition = (spos.xyz + hdim) / dim;')
vert.write_pre = False
if tese != None:
if frag_bpos:
make_tess.interpolate(tese, 'bposition', 3, declare_out=True)
elif tese.contains('bposition') and not tese.contains('vec3 bposition'):
vert.add_out('vec3 bposition')
vert.write_pre = True
vert.write('bposition = spos.xyz;')
vert.write_pre = False
make_tess.interpolate(tese, 'bposition', 3, declare_out=False)
def make_base(con_mesh, parse_opacity):
global is_displacement
global write_material_attribs
@ -738,6 +751,9 @@ def make_forward_base(con_mesh, parse_opacity=False):
# frag.write('indirect = vec3(1.0 - traceAO(voxpos, n, voxels));') # AO view
else:
frag.write('vec4 indirectDiffuse = traceDiffuse(voxpos, n, voxels);')
frag.write('indirect = indirect * voxelgiEnv + vec3(indirectDiffuse.rgb * voxelgiDiff * basecol);')
frag.write('if (specular > 0.0) {')
frag.write('vec3 indirectSpecular = traceSpecular(voxels, voxpos, n, vVec, roughness);')
frag.write('indirectSpecular *= f0 * envBRDF.x + envBRDF.y;')
frag.write('indirect = indirect * voxelgiEnv + vec3(indirectDiffuse.rgb * voxelgiDiff * basecol + indirectSpecular * voxelgiSpec);')
frag.write('indirect += indirectSpecular * voxelgiSpec * specular;')
frag.write('}')

View file

@ -1,6 +1,7 @@
import arm.material.cycles as cycles
import arm.material.mat_state as mat_state
import arm.material.make_mesh as make_mesh
import arm.assets as assets
def make(context_id):
con_transluc = mat_state.data.add_context({ 'name': context_id, 'depth_write': False, 'compare_mode': 'less', 'cull_mode': 'clockwise', \
@ -30,4 +31,9 @@ def make(context_id):
frag.write('fragColor[0] = vec4(premultipliedReflect.rgb * w, premultipliedReflect.a);')
frag.write('fragColor[1] = vec4(premultipliedReflect.a * w, 0.0, 0.0, 1.0);')
make_mesh.make_finalize(con_transluc)
# assets.vs_equal(con_transluc, assets.shader_cons['transluc_vert']) # shader_cons has no transluc yet
# assets.fs_equal(con_transluc, assets.shader_cons['transluc_frag'])
return con_transluc

View file

@ -85,6 +85,15 @@ def make_gi(context_id):
vert.write('mpositionGeom = pos;')
vert.write_pre = False
export_bpos = frag.contains('bposition') and not frag.contains('vec3 bposition')
if export_bpos:
vert.add_out('vec3 bpositionGeom')
vert.add_uniform('vec3 dim', link='_dim')
vert.add_uniform('vec3 hdim', link='_halfDim')
vert.write_pre = True
vert.write('bpositionGeom = (pos.xyz + hdim) / dim;')
vert.write_pre = False
vert.add_uniform('mat4 W', '_worldMatrix')
vert.add_uniform('mat3 N', '_normalMatrix')
@ -117,6 +126,8 @@ def make_gi(context_id):
geom.add_out('vec2 texCoord')
if export_mpos:
geom.add_out('vec3 mposition')
if export_bpos:
geom.add_out('vec3 bposition')
geom.write('vec3 p1 = voxpositionGeom[1] - voxpositionGeom[0];')
geom.write('vec3 p2 = voxpositionGeom[2] - voxpositionGeom[0];')
@ -130,6 +141,8 @@ def make_gi(context_id):
geom.write(' texCoord = texCoordGeom[i];')
if export_mpos:
geom.write(' mposition = mpositionGeom[i];')
if export_bpos:
geom.write(' bposition = bpositionGeom[i];')
geom.write(' if (p.z > p.x && p.z > p.y) {')
geom.write(' gl_Position = vec4(voxposition.x, voxposition.y, 0.0, 1.0);')
geom.write(' }')

Binary file not shown.