Advancing new material builder

This commit is contained in:
Lubos Lenco 2016-12-17 23:48:18 +01:00
parent 924e187f9a
commit 19777385e5
10 changed files with 341 additions and 180 deletions

Binary file not shown.

View file

@ -1648,7 +1648,8 @@ class ArmoryExporter:
na['size'] = 3
na['values'] = ndata
om['vertex_arrays'].append(na)
if num_uv_layers > 0:
if self.get_export_uvs(exportMesh) == True and num_uv_layers > 0:
ta = {}
ta['attrib'] = "texcoord"
ta['size'] = 2
@ -1660,7 +1661,8 @@ class ArmoryExporter:
ta1['size'] = 2
ta1['values'] = t1data
om['vertex_arrays'].append(ta1)
if num_colors > 0:
if self.get_export_vcols(exportMesh) == True and num_colors > 0:
ca = {}
ca['attrib'] = "color"
ca['size'] = 3
@ -1707,7 +1709,7 @@ class ArmoryExporter:
om['index_arrays'].append(ia)
# Make tangents
if (self.get_export_tangents(exportMesh) == True and num_uv_layers > 0):
if self.get_export_tangents(exportMesh) == True and num_uv_layers > 0:
tana = {}
tana['attrib'] = "tangent"
tana['size'] = 3
@ -1864,7 +1866,7 @@ class ArmoryExporter:
# Write the color array if it exists.
colorCount = len(exportMesh.tessface_vertex_colors)
if (colorCount > 0):
if self.get_export_vcols(exportMesh) == True and colorCount > 0:
ca = {}
ca['attrib'] = "color"
ca['size'] = 3
@ -1873,7 +1875,7 @@ class ArmoryExporter:
# Write the texcoord arrays.
texcoordCount = len(exportMesh.tessface_uv_textures)
if (texcoordCount > 0):
if self.get_export_uvs(exportMesh) == True and texcoordCount > 0:
ta = {}
ta['attrib'] = "texcoord"
ta['size'] = 2
@ -1931,16 +1933,16 @@ class ArmoryExporter:
# bpy.data.meshes.remove(morphMesh)
# Write the index arrays.
# Write the index arrays
om['index_arrays'] = []
maxMaterialIndex = 0
for i in range(len(material_table)):
index = material_table[i]
if (index > maxMaterialIndex):
if index > maxMaterialIndex:
maxMaterialIndex = index
if (maxMaterialIndex == 0):
if maxMaterialIndex == 0:
# There is only one material, so write a single index array.
ia = {}
ia['size'] = 3
@ -1970,7 +1972,7 @@ class ArmoryExporter:
om['index_arrays'].append(ia)
# Export tangents
if (self.get_export_tangents(exportMesh) == True and len(exportMesh.uv_textures) > 0):
if self.get_export_tangents(exportMesh) == True and len(exportMesh.uv_textures) > 0:
tana = {}
tana['attrib'] = "tangent"
tana['size'] = 3
@ -2135,7 +2137,29 @@ class ArmoryExporter:
if wrd.arm_material_level == 'Restricted':
self.post_export_material(material, o)
else:
make_material_full.parse(material, o)
sd = make_material_full.parse(material, o)
uv_export = False
tan_export = False
vcol_export = False
for elem in sd['vertex_structure']:
if elem['name'] == 'tan':
tan_export = True
elif elem['name'] == 'tex':
uv_export = True
elif elem['name'] == 'col':
vcol_export = True
if (material.export_tangents != tan_export) or \
(material.export_uvs != uv_export) or \
(material.export_vcols != vcol_export):
material.export_uvs = uv_export
material.export_vcols = vcol_export
material.export_tangents = tan_export
mat_users = self.materialToObjectDict[material]
for ob in mat_users:
ob.data.mesh_cached = False
self.output['material_datas'].append(o)
@ -2399,6 +2423,18 @@ class ArmoryExporter:
return True
return False
def get_export_vcols(self, mesh):
for m in mesh.materials:
if m != None and m.export_vcols == True:
return True
return False
def get_export_uvs(self, mesh):
for m in mesh.materials:
if m != None and m.export_uvs == True:
return True
return False
def object_process_instancing(self, bobject, refs):
is_instanced = False
instance_offsets = None
@ -2925,7 +2961,6 @@ class ArmoryExporter:
# Delete mesh caches
for ob in mat_users:
ob.data.mesh_cached = False
break
# Process defs and append datas
if material.override_shader == False:

View file

@ -0,0 +1,115 @@
str_tex_checker = """vec3 tex_checker(const vec3 co, const vec3 col1, const vec3 col2, const float 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;
//p.z = (p.z + 0.000001) * 0.999999;
float xi = abs(floor(p.x));
float yi = abs(floor(p.y));
float zi = abs(floor(p.z));
bool check = ((mod(xi, 2.0) == mod(yi, 2.0)) == bool(mod(zi, 2.0)));
return check ? col1 : col2;
}
"""
# 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);
//}
vec4 tex_voronoi(const vec3 x) {
vec3 xx = x / 3.0; // Match cycles
vec3 p = floor(xx);
vec3 f = fract(xx);
float id = 0.0;
float res = 100.0;
for (int k = -1; k <= 1; k++)
for (int j = -1; j <= 1; j++)
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);
float d = dot(r, r);
if (d < res) {
id = dot(p + b, vec3(1.0, 57.0, 113.0));
res = d;
}
}
vec3 col = 0.5 + 0.5 * cos(id * 0.35 + vec3(0.0, 1.0, 2.0));
return vec4(col, sqrt(res));
}
"""
# 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
# Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
str_tex_noise = """
vec3 random3(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);
j *= 0.125;
r.x = fract(512.0 * j);
j *= 0.125;
r.y = fract(512.0 * j);
return r - 0.5;
}
float tex_noise_f(vec3 p) {
const float F3 = 0.3333333;
const float G3 = 0.1666667;
vec3 s = floor(p + dot(p, vec3(F3)));
vec3 x = p - s + dot(s, vec3(G3));
vec3 e = step(vec3(0.0), x - x.yzx);
vec3 i1 = e*(1.0 - e.zxy);
vec3 i2 = 1.0 - e.zxy*(1.0 - e);
vec3 x1 = x - i1 + G3;
vec3 x2 = x - i2 + 2.0*G3;
vec3 x3 = x - 1.0 + 3.0*G3;
vec4 w, d;
w.x = dot(x, x);
w.y = dot(x1, x1);
w.z = dot(x2, x2);
w.w = dot(x3, x3);
w = max(0.6 - w, 0.0);
d.x = dot(random3(s), x);
d.y = dot(random3(s + i1), x1);
d.z = dot(random3(s + i2), x2);
d.w = dot(random3(s + 1.0), x3);
w *= w;
w *= w;
d *= w;
return clamp(dot(d, vec4(52.0)), 0.0, 1.0);
}
float tex_noise(vec3 p) {
return 0.5333333 * tex_noise_f(p)
+ 0.2666667 * tex_noise_f(2.0 * p)
+ 0.1333333 * tex_noise_f(4.0 * p)
+ 0.0666667 * tex_noise_f(8.0 * p);
}
"""

View file

@ -61,6 +61,8 @@ def parse(material, mat_data):
assets.add_shader_data(shader_data_path)
mat_data['shader'] = shader_data_name + '/' + shader_data_name
return state.data.sd
def make_mat_context(name):
c = {}
c['name'] = name

View file

@ -18,124 +18,9 @@ import armutils
import assets
import material.make_texture as make_texture
import material.mat_state as mat_state
import material.functions
import make_state as state
str_tex_checker = """vec3 tex_checker(const vec3 co, const vec3 col1, const vec3 col2, const float 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;
//p.z = (p.z + 0.000001) * 0.999999;
float xi = abs(floor(p.x));
float yi = abs(floor(p.y));
float zi = abs(floor(p.z));
bool check = ((mod(xi, 2.0) == mod(yi, 2.0)) == bool(mod(zi, 2.0)));
return check ? col1 : col2;
}
"""
# 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);
//}
vec4 tex_voronoi(const vec3 x) {
vec3 xx = x / 3.0; // Match cycles
vec3 p = floor(xx);
vec3 f = fract(xx);
float id = 0.0;
float res = 100.0;
for (int k = -1; k <= 1; k++)
for (int j = -1; j <= 1; j++)
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);
float d = dot(r, r);
if (d < res) {
id = dot(p + b, vec3(1.0, 57.0, 113.0));
res = d;
}
}
vec3 col = 0.5 + 0.5 * cos(id * 0.35 + vec3(0.0, 1.0, 2.0));
return vec4(col, sqrt(res));
}
"""
# 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
# Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
str_tex_noise = """
vec3 random3(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);
j *= 0.125;
r.x = fract(512.0 * j);
j *= 0.125;
r.y = fract(512.0 * j);
return r - 0.5;
}
float tex_noise_f(vec3 p) {
const float F3 = 0.3333333;
const float G3 = 0.1666667;
vec3 s = floor(p + dot(p, vec3(F3)));
vec3 x = p - s + dot(s, vec3(G3));
vec3 e = step(vec3(0.0), x - x.yzx);
vec3 i1 = e*(1.0 - e.zxy);
vec3 i2 = 1.0 - e.zxy*(1.0 - e);
vec3 x1 = x - i1 + G3;
vec3 x2 = x - i2 + 2.0*G3;
vec3 x3 = x - 1.0 + 3.0*G3;
vec4 w, d;
w.x = dot(x, x);
w.y = dot(x1, x1);
w.z = dot(x2, x2);
w.w = dot(x3, x3);
w = max(0.6 - w, 0.0);
d.x = dot(random3(s), x);
d.y = dot(random3(s + i1), x1);
d.z = dot(random3(s + i2), x2);
d.w = dot(random3(s + 1.0), x3);
w *= w;
w *= w;
d *= w;
return clamp(dot(d, vec4(52.0)), 0.0, 1.0);
}
float tex_noise(vec3 p) {
return 0.5333333 * tex_noise_f(p)
+ 0.2666667 * tex_noise_f(2.0 * p)
+ 0.1333333 * tex_noise_f(4.0 * p)
+ 0.0666667 * tex_noise_f(8.0 * p);
}
"""
def parse(nodes, vert, frag, geom, tesc, tese, parse_surface=True):
output_node = node_by_type(nodes, 'OUTPUT_MATERIAL')
if output_node != None:
@ -151,8 +36,6 @@ def parse_output(node, _vert, _frag, _geom, _tesc, _tese, parse_surface):
global geom
global tesc
global tese
global str_tex_checker
global str_tex_voronoi
vert = _vert
frag = _frag
geom = _geom
@ -176,7 +59,7 @@ def parse_output(node, _vert, _frag, _geom, _tesc, _tese, parse_surface):
# parse_volume_input(node.inputs[1])
# Displacement
if armutils.tess_enabled(state.target) and node.inputs[2].is_linked:
if armutils.tess_enabled(state.target) and node.inputs[2].is_linked and tese != None:
parsed = []
parents = []
normal_written = False
@ -231,8 +114,10 @@ def parse_shader_input(inp):
def write_normal(inp):
if inp.is_linked:
curshader.write('n = {0};'.format(parse_vector_input(inp)))
normal_written = True
normal_res = parse_vector_input(inp)
if normal_res != None:
curshader.write('n = {0};'.format(normal_res))
normal_written = True
def parse_shader(node, socket):
out_basecol = 'vec3(0.8)'
@ -242,7 +127,11 @@ def parse_shader(node, socket):
if node.type == 'GROUP':
if node.node_tree.name.startswith('Armory PBR'):
pass
out_basecol = parse_vector_input(node.inputs[0])
out_roughness = parse_value_input(node.inputs[3])
out_metallic = parse_value_input(node.inputs[5])
out_occlusion = parse_value_input(node.inputs[1])
parse_normal_map_color_input(node.inputs[6])
else:
return parse_group(node, socket)
@ -361,12 +250,18 @@ def write_result(l):
parsed.append(res_var)
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))
return res_var
@ -398,8 +293,10 @@ def parse_rgb(node, socket):
return parse_input_group(node, socket)
elif node.type == 'ATTRIBUTE':
# Vcols
pass
# Vcols only for now
# node.attribute_name
mat_state.data.add_elem('col', 3)
return 'color'
elif node.type == 'RGB':
return tovec3(socket.default_value)
@ -409,7 +306,7 @@ def parse_rgb(node, socket):
return tovec3([0.0, 0.0, 0.0])
elif node.type == 'TEX_CHECKER':
curshader.add_function(str_tex_checker)
curshader.add_function(functions.str_tex_checker)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
@ -462,7 +359,7 @@ def parse_rgb(node, socket):
elif node.type == 'TEX_MUSGRAVE':
# Fall back to noise
curshader.add_function(str_tex_noise)
curshader.add_function(functions.str_tex_noise)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
@ -473,7 +370,7 @@ def parse_rgb(node, socket):
return 'vec3(tex_noise_f({0} * {1}))'.format(co, scale)
elif node.type == 'TEX_NOISE':
curshader.add_function(str_tex_noise)
curshader.add_function(functions.str_tex_noise)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
@ -493,7 +390,7 @@ def parse_rgb(node, socket):
return tovec3([0.0, 0.0, 0.0])
elif node.type == 'TEX_VORONOI':
curshader.add_function(str_tex_voronoi)
curshader.add_function(functions.str_tex_voronoi)
assets.add(armutils.get_sdk_path() + '/armory/Assets/' + 'noise64.png')
assets.add_embedded_data('noise64.png')
curshader.add_uniform('sampler2D snoise', link='_noise64')
@ -731,7 +628,7 @@ def parse_vector(node, socket):
# height = parse_value_input(node.inputs[2])
# nor = parse_vector_input(node.inputs[3])
# Sample height around the normal and compute normal
return 'wnormal'
return 'n'
elif node.type == 'MAPPING':
# vector = parse_vector_input(node.inputs[0])
@ -748,8 +645,8 @@ def parse_vector(node, socket):
#space = node.space
#map = node.uv_map
# strength = parse_value_input(node.inputs[0])
# color = parse_vector_input(node.inputs[1])
return 'vec3(0.0)'
parse_normal_map_color_input(node.inputs[1]) # Color
return None
elif node.type == 'CURVE_VEC':
# fac = parse_value_input(node.inputs[0])
@ -786,6 +683,15 @@ def parse_vector(node, socket):
elif op == 'NORMALIZE':
return 'normalize({0})'.format(vec1)
def parse_normal_map_color_input(inp):
if inp.is_linked == False:
return
frag.write_pre = True
frag.write('vec3 n = ({0}) * 2.0 - 1.0;'.format(parse_vector_input(inp)))
frag.write('n = normalize(TBN * normalize(n));')
mat_state.data.add_elem('tan', 3)
frag.write_pre = False
def parse_value_input(inp):
if inp.is_linked:
l = inp.links[0]
@ -805,7 +711,14 @@ def parse_value_input(inp):
def parse_value(node, socket):
if node.type == 'GROUP':
return parse_group(node, socket)
if node.node_tree.name.startswith('Armory PBR'):
# Displacement
if socket == node.outputs[1]:
return parse_value_input(node.inputs[10])
else:
return None
else:
return parse_group(node, socket)
elif node.type == 'GROUP_INPUT':
return parse_input_group(node, socket)
@ -907,7 +820,7 @@ def parse_value(node, socket):
elif node.type == 'TEX_CHECKER':
# TODO: do not recompute when color socket is also connected
curshader.add_function(str_tex_checker)
curshader.add_function(functions.str_tex_checker)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
@ -928,7 +841,7 @@ def parse_value(node, socket):
elif node.type == 'TEX_MUSGRAVE':
# Fall back to noise
curshader.add_function(str_tex_noise)
curshader.add_function(functions.str_tex_noise)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
@ -939,7 +852,7 @@ def parse_value(node, socket):
return 'tex_noise_f({0} * {1})'.format(co, scale)
elif node.type == 'TEX_NOISE':
curshader.add_function(str_tex_noise)
curshader.add_function(functions.str_tex_noise)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
@ -953,7 +866,7 @@ def parse_value(node, socket):
return '0.0'
elif node.type == 'TEX_VORONOI':
curshader.add_function(str_tex_voronoi)
curshader.add_function(functions.str_tex_voronoi)
assets.add(armutils.get_sdk_path() + '/armory/Assets/' + 'noise64.png')
assets.add_embedded_data('noise64.png')
curshader.add_uniform('sampler2D snoise', link='_noise64')

View file

@ -15,7 +15,15 @@ def mesh(context_id):
# Displacement linked
tess_enabled = armutils.tess_enabled(state.target)
output_node = make_cycles.node_by_type(mat_state.nodes, 'OUTPUT_MATERIAL')
if tess_enabled and output_node != None and output_node.inputs[2].is_linked:
if output_node == None:
return None
if output_node.inputs[2].is_linked:
l = output_node.inputs[2].links[0]
if l.from_node.type == 'GROUP' and l.from_node.node_tree.name.startswith('Armory PBR') and l.from_node.inputs[10].is_linked == False:
tess_enabled = False
if tess_enabled and output_node.inputs[2].is_linked:
tesc = con_mesh.make_tesc()
tese = con_mesh.make_tese()
tesc.ins = vert.outs
@ -23,11 +31,8 @@ def mesh(context_id):
frag.ins = tese.outs
vert.add_out('vec3 wposition')
vert.add_out('vec3 wnormal')
vert.add_uniform('mat4 W', '_worldMatrix')
vert.add_uniform('mat4 N', '_normalMatrix')
vert.write('vec4 spos = vec4(pos, 1.0);')
vert.write('wnormal = normalize(mat3(N) * nor);')
vert.write('wposition = vec4(W * spos).xyz;')
const = {}
@ -54,10 +59,9 @@ def mesh(context_id):
tese.write('vec3 n2 = gl_TessCoord.z * tc_wnormal[2];')
tese.write('wnormal = normalize(n0 + n1 + n2);')
# No displacement
# No displacement
else:
frag.ins = vert.outs
vert.add_out('vec3 wnormal')
vert.add_out('vec3 wposition')
vert.add_out('vec3 eyeDir')
vert.add_uniform('mat4 W', '_worldMatrix')
@ -65,14 +69,12 @@ def mesh(context_id):
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix')
vert.add_uniform('vec3 eye', '_cameraPosition')
vert.write('vec4 spos = vec4(pos, 1.0);')
vert.write('wnormal = normalize(mat3(N) * nor);')
vert.write('wposition = vec4(W * spos).xyz;')
vert.write('eyeDir = eye - wposition;')
vert.write('gl_Position = WVP * spos;')
frag.add_include('../../Shaders/compiled.glsl')
frag.add_include('../../Shaders/std/gbuffer.glsl')
frag.write('vec3 n = normalize(wnormal);')
frag.write('vec3 v = normalize(eyeDir);')
# frag.write('float dotNV = dot(n, v);')
frag.write('float dotNV = max(dot(n, v), 0.0);')
@ -89,17 +91,62 @@ def mesh(context_id):
vert.write('texCoord = tex;')
if tese != None:
if 'texCoord' in frag.main:
if 'texCoord' in frag.main or 'texCoord' in frag.main_pre:
tese.add_out('vec2 texCoord')
tese.write_pre('vec2 tc0 = gl_TessCoord.x * tc_texCoord[0];')
tese.write_pre('vec2 tc1 = gl_TessCoord.y * tc_texCoord[1];')
tese.write_pre('vec2 tc2 = gl_TessCoord.z * tc_texCoord[2];')
tese.write_pre('texCoord = tc0 + tc1 + tc2;')
elif 'texCoord' in tese.main:
tese.write_pre('vec2 tc0 = gl_TessCoord.x * tc_texCoord[0];')
tese.write_pre('vec2 tc1 = gl_TessCoord.y * tc_texCoord[1];')
tese.write_pre('vec2 tc2 = gl_TessCoord.z * tc_texCoord[2];')
tese.write_pre('vec2 texCoord = tc0 + tc1 + tc2;')
tese.write_pre = True
tese.write('vec2 tc0 = gl_TessCoord.x * tc_texCoord[0];')
tese.write('vec2 tc1 = gl_TessCoord.y * tc_texCoord[1];')
tese.write('vec2 tc2 = gl_TessCoord.z * tc_texCoord[2];')
tese.write('texCoord = tc0 + tc1 + tc2;')
tese.write_pre = False
elif 'texCoord' in tese.main or 'texCoord' in tese.main_pre:
tese.write_pre = True
tese.write('vec2 tc0 = gl_TessCoord.x * tc_texCoord[0];')
tese.write('vec2 tc1 = gl_TessCoord.y * tc_texCoord[1];')
tese.write('vec2 tc2 = gl_TessCoord.z * tc_texCoord[2];')
tese.write('vec2 texCoord = tc0 + tc1 + tc2;')
tese.write_pre = False
if mat_state.data.is_elem('col'):
vert.add_out('vec3 color')
vert.write('color = col;')
if tese != None:
tese.add_out('vec3 color')
tese.write('vec3 col0 = gl_TessCoord.x * tc_color[0];')
tese.write('vec3 col1 = gl_TessCoord.y * tc_color[1];')
tese.write('vec3 col2 = gl_TessCoord.z * tc_color[2];')
tese.write('color = col0 + col1 + col2;')
if mat_state.data.is_elem('tan'):
if tese != None:
vert.add_out('vec3 wnormal')
vert.add_out('vec3 wtangent')
vert.add_uniform('mat4 N', '_normalMatrix')
vert.write('wnormal = normalize(mat3(N) * nor);')
vert.write('wtangent = normalize(mat3(N) * tan);')
tese.add_out('mat3 TBN')
tese.write('vec3 tan0 = gl_TessCoord.x * tc_wtangent[0];')
tese.write('vec3 tan1 = gl_TessCoord.y * tc_wtangent[1];')
tese.write('vec3 tan2 = gl_TessCoord.z * tc_wtangent[2];')
tese.write('vec3 wtangent = normalize(tan0 + tan1 + tan2);')
tese.write('vec3 wbitangent = normalize(cross(wnormal, wtangent));')
tese.write('TBN = mat3(wtangent, wbitangent, wnormal);')
else:
vert.add_out('mat3 TBN')
vert.add_uniform('mat4 N', '_normalMatrix')
vert.write('vec3 wnormal = normalize(mat3(N) * nor);')
vert.write('vec3 tangent = normalize(mat3(N) * tan);')
vert.write('vec3 bitangent = normalize(cross(wnormal, tangent));')
vert.write('TBN = mat3(tangent, bitangent, wnormal);')
else:
vert.add_uniform('mat4 N', '_normalMatrix')
vert.add_out('vec3 wnormal')
vert.write('wnormal = normalize(mat3(N) * nor);')
frag.write_pre = True
frag.write('vec3 n = normalize(wnormal);')
frag.write_pre = False
if tese != None:
tese.add_uniform('mat4 VP', '_viewProjectionMatrix')
@ -129,7 +176,16 @@ def shadows(context_id):
# Displacement linked
tess_enabled = armutils.tess_enabled(state.target)
tess_enabled_shadow = mat_state.material.height_tess_shadows
output_node = make_cycles.node_by_type(mat_state.nodes, 'OUTPUT_MATERIAL')
if output_node == None:
return None
if output_node.inputs[2].is_linked:
l = output_node.inputs[2].links[0]
if l.from_node.type == 'GROUP' and l.from_node.node_tree.name.startswith('Armory PBR') and l.from_node.inputs[10].is_linked == False:
tess_enabled = False
if tess_enabled and tess_enabled_shadow and output_node != None and output_node.inputs[2].is_linked:
tesc = con_shadowmap.make_tesc()
tese = con_shadowmap.make_tese()
@ -172,10 +228,12 @@ def shadows(context_id):
if tese != None and 'texCoord' in tese.main:
vert.add_out('vec2 texCoord')
vert.write('texCoord = tex;')
tese.write_pre('vec2 tc0 = gl_TessCoord.x * tc_texCoord[0];')
tese.write_pre('vec2 tc1 = gl_TessCoord.y * tc_texCoord[1];')
tese.write_pre('vec2 tc2 = gl_TessCoord.z * tc_texCoord[2];')
tese.write_pre('vec2 texCoord = tc0 + tc1 + tc2;')
tese.write_pre = True
tese.write('vec2 tc0 = gl_TessCoord.x * tc_texCoord[0];')
tese.write('vec2 tc1 = gl_TessCoord.y * tc_texCoord[1];')
tese.write('vec2 tc2 = gl_TessCoord.z * tc_texCoord[2];')
tese.write('vec2 texCoord = tc0 + tc1 + tc2;')
tese.write_pre = False
tese.add_uniform('mat4 LVP', '_lampViewProjectionMatrix')
# tese.add_uniform('mat4 LWVP', '_lampWorldViewProjectionMatrix')

View file

@ -1,13 +1,25 @@
import bpy
import material.mat_state as state
import material.make_cycles as make_cycles
import armutils
import assets
def mesh(context_id):
wrd = bpy.data.worlds['Arm']
if '_PCSS' in wrd.world_defs:
is_pcss = True
else:
is_pcss = False
con_mesh = state.data.add_context({ 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' })
vert = con_mesh.make_vert()
frag = con_mesh.make_frag()
geom = None
tesc = None
tese = None
frag.ins = vert.outs
vert.add_out('vec3 wnormal')
@ -49,10 +61,12 @@ def mesh(context_id):
vert.add_out('vec4 lampPos')
vert.add_uniform('mat4 LWVP', '_lampWorldViewProjectionMatrix')
vert.write('lampPos = LWVP * spos;')
frag.add_include('../../Shaders/std/shadows.glsl')
# frag.add_include('../../Shaders/std/shadows_pcss.glsl')
if is_pcss:
frag.add_include('../../Shaders/std/shadows_pcss.glsl')
frag.add_uniform('sampler2D snoise', link='_noise64', included=True)
else:
frag.add_include('../../Shaders/std/shadows.glsl')
frag.add_uniform('sampler2D shadowMap', included=True)
# frag.add_uniform('sampler2D snoise', link='_noise64', included=True)
frag.add_uniform('float lampSizeUV', link='_lampSizeUV', included=True)
frag.add_uniform('bool receiveShadow')
frag.add_uniform('float shadowsBias', '_lampShadowsBias')
@ -61,8 +75,10 @@ def mesh(context_id):
frag.tab += 1
frag.write('vec3 lpos = lampPos.xyz / lampPos.w;')
frag.write('lpos.xy = lpos.xy * 0.5 + 0.5;')
frag.write('visibility = PCF(lpos.xy, lpos.z - shadowsBias);')
# frag.write('visibility = PCSS(lpos.xy, lpos.z - shadowsBias);')
if is_pcss:
frag.write('visibility = PCSS(lpos.xy, lpos.z - shadowsBias);')
else:
frag.write('visibility = PCF(lpos.xy, lpos.z - shadowsBias);')
frag.tab -= 1
frag.write('}')
@ -85,7 +101,7 @@ def mesh(context_id):
frag.write('float metallic;')
frag.write('float occlusion;')
make_cycles.parse(state.nodes, vert, frag)
make_cycles.parse(state.nodes, vert, frag, geom, tesc, tese)
frag.write('vec3 albedo = surfaceAlbedo(basecol, metallic);')
frag.write('vec3 f0 = surfaceF0(basecol, metallic);')
@ -107,10 +123,14 @@ def shadows(context_id):
con_shadowmap = state.data.add_context({ 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' })
vert = con_shadowmap.make_vert()
frag = con_shadowmap.make_frag()
geom = None
tesc = None
tese = None
vert.add_uniform('mat4 LWVP', '_lampWorldViewProjectionMatrix')
vert.write('gl_Position = LWVP * vec4(pos, 1.0);')
frag = con_shadowmap.make_frag()
frag.write('fragColor = vec4(0.0);')
return con_shadowmap

View file

@ -11,6 +11,7 @@ class Shader:
self.functions = {}
self.main = ''
self.main_pre = ''
self.write_pre = False
self.tab = 1
def add_include(self, s):
@ -40,11 +41,11 @@ class Shader:
return
self.functions[fname] = s
def write_pre(self, s):
self.main_pre += '\t' * 1 + s + '\n'
def write(self, s):
self.main += '\t' * self.tab + s + '\n'
if self.write_pre:
self.main_pre += '\t' * 1 + s + '\n'
else:
self.main += '\t' * self.tab + s + '\n'
def write_tesc_levels(self):
self.write('if (gl_InvocationID == 0) {')

View file

@ -23,6 +23,12 @@ class ShaderData:
return True
return False
def get_elem(self, name):
for elem in self.sd['vertex_structure']:
if elem['name'] == name:
return elem
return None
def add_context(self, props):
con = ShaderContext(self.material, self.sd, props)
if con not in self.sd['contexts']:
@ -30,6 +36,15 @@ class ShaderData:
return con
def get(self):
# TODO: temporary, Sort vertex data
for sd in self.data['shader_datas']:
vs = []
ar = ['pos', 'nor', 'tex', 'col', 'tan', 'bone', 'weight', 'off']
for ename in ar:
elem = self.get_elem(ename)
if elem != None:
vs.append(elem)
sd['vertex_structure'] = vs
return self.data
class ShaderContext:

View file

@ -330,6 +330,8 @@ def init_properties():
bpy.types.Material.override_shader_context = bpy.props.BoolProperty(name="Override Context", default=False)
bpy.types.Material.override_shader_context_name = bpy.props.StringProperty(name="Name", default='')
bpy.types.Material.stencil_mask = bpy.props.IntProperty(name="Stencil Mask", default=0)
bpy.types.Material.export_uvs = bpy.props.BoolProperty(name="Export UVs", default=False)
bpy.types.Material.export_vcols = bpy.props.BoolProperty(name="Export VCols", default=False)
bpy.types.Material.export_tangents = bpy.props.BoolProperty(name="Export Tangents", default=False)
bpy.types.Material.skip_context = bpy.props.StringProperty(name="Skip Context", default='')
bpy.types.Material.overlay = bpy.props.BoolProperty(name="X-Ray", default=False)