Particle Info material node

This commit is contained in:
Lubos Lenco 2017-10-04 18:24:13 +02:00
parent 1ed22ad646
commit cdb1525566
5 changed files with 114 additions and 60 deletions

View file

@ -19,6 +19,7 @@ import arm.material.cycles_state as c_state
basecol_texname = ''
emission_found = False
particle_info = None # Particle info export
def parse(nodes, con, vert, frag, geom, tesc, tese, parse_surface=True, parse_opacity=True, parse_displacement=True, basecol_only=False):
output_node = node_by_type(nodes, 'OUTPUT_MATERIAL')
@ -43,6 +44,7 @@ def parse_output(node, _con, _vert, _frag, _geom, _tesc, _tese, _parse_surface,
global parse_teximage_vector
global basecol_texname
global emission_found
global particle_info
con = _con
vert = _vert
frag = _frag
@ -56,6 +58,14 @@ def parse_output(node, _con, _vert, _frag, _geom, _tesc, _tese, _parse_surface,
parse_teximage_vector = True
basecol_texname = ''
emission_found = False
particle_info = {}
particle_info['index'] = False
particle_info['age'] = False
particle_info['lifetime'] = False
particle_info['location'] = False
particle_info['size'] = False
particle_info['velocity'] = False
particle_info['angular_velocity'] = False
# Surface
if parse_surface or parse_opacity:
@ -716,6 +726,7 @@ def texture_store(node, tex, tex_name, to_linear=False):
return tex_store
def parse_vector(node, socket):
global particle_info
if node.type == 'GROUP':
return parse_group(node, socket)
@ -764,10 +775,13 @@ def parse_vector(node, socket):
elif node.type == 'PARTICLE_INFO':
if socket == node.outputs[3]: # Location
return 'vec3(0.0)'
particle_info['location'] = True
return 'p_location' if c_state.mat_get_material().arm_particle == 'gpu' else 'vec3(0.0)'
elif socket == node.outputs[5]: # Velocity
return 'vec3(0.0)'
particle_info['velocity'] = True
return 'p_velocity' if c_state.mat_get_material().arm_particle == 'gpu' else 'vec3(0.0)'
elif socket == node.outputs[6]: # Angular Velocity
particle_info['angular_velocity'] = True
return 'vec3(0.0)'
elif node.type == 'TANGENT':
@ -919,6 +933,7 @@ def parse_value_input(inp):
return tovec1(inp.default_value)
def parse_value(node, socket):
global particle_info
if node.type == 'GROUP':
if node.node_tree.name.startswith('Armory PBR'):
@ -1011,13 +1026,17 @@ def parse_value(node, socket):
elif node.type == 'PARTICLE_INFO':
if socket == node.outputs[0]: # Index
return '0.0'
particle_info['index'] = True
return 'p_index' if c_state.mat_get_material().arm_particle == 'gpu' else '0.0'
elif socket == node.outputs[1]: # Age
return '0.0'
particle_info['age'] = True
return 'p_age' if c_state.mat_get_material().arm_particle == 'gpu' else '0.0'
elif socket == node.outputs[2]: # Lifetime
return '0.0'
particle_info['lifetime'] = True
return 'p_lifetime' if c_state.mat_get_material().arm_particle == 'gpu' else '0.0'
elif socket == node.outputs[4]: # Size
return '0.0'
particle_info['size'] = True
return '1.0'
elif node.type == 'VALUE':
return tovec1(node.outputs[0].default_value)

View file

@ -111,8 +111,9 @@ def make_base(con_mesh, parse_opacity):
vert.add_uniform('mat3 N', '_normalMatrix')
vert.write_main_header('vec4 spos = vec4(pos, 1.0);')
if mat_utils.disp_linked(mat_state.output_node):
is_displacement = True
vattr_written = False
is_displacement = mat_utils.disp_linked(mat_state.output_node)
if is_displacement:
tesc = con_mesh.make_tesc()
tese = con_mesh.make_tese()
tesc.ins = vert.outs
@ -127,36 +128,9 @@ def make_base(con_mesh, parse_opacity):
make_tess.interpolate(tese, 'wnormal', 3, declare_out=True, normalize=True)
# No displacement
else:
is_displacement = False
frag.ins = vert.outs
written = False
if write_vertex_attribs != None:
written = write_vertex_attribs(vert)
if written == False:
billboard = mat_state.material.arm_billboard
particle = mat_state.material.arm_particle
wrd = bpy.data.worlds['Arm']
# Particles
if particle != 'off':
if particle == 'gpu':
make_particle.write(vert)
# Billboards
if billboard == 'spherical':
vert.add_uniform('mat4 WV', '_worldViewMatrix')
vert.add_uniform('mat4 P', '_projectionMatrix')
vert.write('gl_Position = P * (WV * vec4(0.0, 0.0, spos.z, 1.0) + vec4(spos.x, spos.y, 0.0, 0.0));')
else:
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix')
vert.write('gl_Position = WVP * spos;')
else:
# Billboards
if billboard == 'spherical':
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrixSphere')
elif billboard == 'cylindrical':
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrixCylinder')
else: # off
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix')
vert.write('gl_Position = WVP * spos;')
vattr_written = write_vertex_attribs(vert)
frag.add_include('../../Shaders/compiled.glsl')
@ -174,6 +148,32 @@ def make_base(con_mesh, parse_opacity):
if write_material_attribs_post != None:
write_material_attribs_post(con_mesh, frag)
if not is_displacement and not vattr_written:
billboard = mat_state.material.arm_billboard
particle = mat_state.material.arm_particle
wrd = bpy.data.worlds['Arm']
# Particles
if particle != 'off':
if particle == 'gpu':
make_particle.write(vert, particle_info=cycles.particle_info)
# Billboards
if billboard == 'spherical':
vert.add_uniform('mat4 WV', '_worldViewMatrix')
vert.add_uniform('mat4 P', '_projectionMatrix')
vert.write('gl_Position = P * (WV * vec4(0.0, 0.0, spos.z, 1.0) + vec4(spos.x, spos.y, 0.0, 0.0));')
else:
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix')
vert.write('gl_Position = WVP * spos;')
else:
# Billboards
if billboard == 'spherical':
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrixSphere')
elif billboard == 'cylindrical':
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrixCylinder')
else: # off
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix')
vert.write('gl_Position = WVP * spos;')
if con_mesh.is_elem('tex'):
vert.add_out('vec2 texCoord')
if mat_state.material.arm_tilesheet_mat:
@ -501,8 +501,8 @@ def make_forward(con_mesh):
# frag.write('fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));')
# Particle opacity
# if mat_state.material.arm_particle == 'gpu':
# frag.write('fragColor.rgb *= popac;')
if mat_state.material.arm_particle == 'gpu' and mat_state.material.arm_particle_fade:
frag.write('fragColor.rgb *= p_fade;')
def make_forward_base(con_mesh, parse_opacity=False):
wrd = bpy.data.worlds['Arm']

View file

@ -1,50 +1,82 @@
def write(vert):
import arm.material.mat_state as mat_state
def write(vert, particle_info=None):
# Outs
out_index = True if particle_info != None and particle_info['index'] else False
out_age = True if particle_info != None and particle_info['age'] else False
out_lifetime = True if particle_info != None and particle_info['lifetime'] else False
out_location = True if particle_info != None and particle_info['location'] else False
out_size = True if particle_info != None and particle_info['size'] else False
out_velocity = True if particle_info != None and particle_info['velocity'] else False
out_angular_velocity = True if particle_info != None and particle_info['angular_velocity'] else False
vert.add_uniform('mat4 pd', '_particleData')
str_tex_hash = "float fhash(float n) { return fract(sin(n) * 43758.5453); }"
vert.add_function(str_tex_hash)
# var ptime = (count - p.i) * spawnRate;
vert.write('float ptime = (pd[0][0] - gl_InstanceID) * pd[0][1];')
# ptime -= ptime * fhash(i) * r.lifetime_random;
vert.write('ptime -= ptime * fhash(gl_InstanceID) * pd[2][3];')
prep = 'float '
if out_age:
prep = ''
vert.add_out('float p_age')
# var p_age = (count - p.i) * spawnRate;
vert.write(prep + 'p_age = (pd[0][0] - gl_InstanceID) * pd[0][1];')
# p_age -= p_age * fhash(i) * r.lifetime_random;
vert.write('p_age -= p_age * fhash(gl_InstanceID) * pd[2][3];')
# lifetime
prep = 'float '
if out_lifetime:
prep = ''
vert.add_out('float p_lifetime')
vert.write(prep + 'p_lifetime = pd[0][2];')
# todo: properly discard
vert.write('if (gl_InstanceID > pd[0][0] || ptime < 0 || ptime > pd[0][2]) { spos.x = spos.y = spos.z = -99999; }')
vert.write('if (gl_InstanceID > pd[0][0] || p_age < 0 || p_age > p_lifetime) { spos.x = spos.y = spos.z = -99999; }')
vert.write('ptime /= 2;')
vert.write('p_age /= 2;')
# object_align_factor / 2 + gxyz
vert.write('vec3 ppos = vec3(pd[1][0], pd[1][1], pd[1][2]);')
prep = 'vec3 '
if out_velocity:
prep = ''
vert.add_out('vec3 p_velocity')
vert.write(prep + 'p_velocity = vec3(pd[1][0], pd[1][1], pd[1][2]);')
vert.write('p_velocity.x += fhash(gl_InstanceID) * pd[1][3] - pd[1][3] / 2;')
vert.write('p_velocity.y += fhash(gl_InstanceID + pd[0][3]) * pd[1][3] - pd[1][3] / 2;')
vert.write('p_velocity.z += fhash(gl_InstanceID + 2 * pd[0][3]) * pd[1][3] - pd[1][3] / 2;')
# factor_random = pd[1][3]
# p.i = gl_InstanceID
# particles.length = pd[0][3]
vert.write('ppos.x += fhash(gl_InstanceID) * pd[1][3] - pd[1][3] / 2;')
vert.write('ppos.y += fhash(gl_InstanceID + pd[0][3]) * pd[1][3] - pd[1][3] / 2;')
vert.write('ppos.z += fhash(gl_InstanceID + 2 * pd[0][3]) * pd[1][3] - pd[1][3] / 2;')
# gxyz
vert.write('ppos.x += (pd[2][0] * ptime) / 5;')
vert.write('ppos.y += (pd[2][1] * ptime) / 5;')
vert.write('ppos.z += (pd[2][2] * ptime) / 5;')
vert.write('p_velocity.x += (pd[2][0] * p_age) / 5;')
vert.write('p_velocity.y += (pd[2][1] * p_age) / 5;')
vert.write('p_velocity.z += (pd[2][2] * p_age) / 5;')
vert.write('ppos.x *= ptime;')
vert.write('ppos.y *= ptime;')
vert.write('ppos.z *= ptime;')
prep = 'vec3 '
if out_location:
prep = ''
vert.add_out('vec3 p_location')
vert.write(prep + 'p_location = p_velocity * p_age;')
vert.write('spos.xyz += ppos;')
vert.write('spos.xyz += p_location;')
# Particle opacity
# vert.add_out('float popac')
# vert.write('popac = sin(min((ptime / 2) * 3.141592, 3.141592));')
# Particle fade
if mat_state.material.arm_particle == 'gpu' and mat_state.material.arm_particle_fade:
vert.add_out('float p_fade')
vert.write('p_fade = sin(min((p_age / 2) * 3.141592, 3.141592));')
if out_index:
vert.add_out('float p_index');
vert.write('p_index = gl_InstanceID;')
def write_tilesheet(vert):
# tilesx, tilesy, framerate - pd[3][0], pd[3][1], pd[3][2]
vert.write('int frame = int((ptime / 2) / pd[3][2]);')
vert.write('int frame = int((p_age / 2) / pd[3][2]);')
vert.write('int tx = frame % int(pd[3][0]);')
vert.write('int ty = int(frame / pd[3][0]);')
vert.write('vec2 tilesheetOffset = vec2(tx * (1 / pd[3][0]), ty * (1 / pd[3][1]));')

View file

@ -295,6 +295,7 @@ def init_properties():
('gpu', 'GPU', 'GPU'),
('cpu', 'CPU', 'CPU')],
name="Particle", default='off', description="Use this material for particle system rendering", update=assets.invalidate_shader_cache)
bpy.types.Material.arm_particle_fade = bpy.props.BoolProperty(name="Particle Fade", description="Fade particles in and out", default=False)
bpy.types.Material.arm_tilesheet_mat = bpy.props.BoolProperty(name="Tilesheet", description="Generate tilesheet shaders", default=False)
bpy.types.Material.arm_blending = bpy.props.BoolProperty(name="Blending", description="Enable additive blending", default=False)
# For scene

View file

@ -270,6 +270,8 @@ class MaterialPropsPanel(bpy.types.Panel):
layout.prop(mat, 'arm_skip_context')
layout.prop(mat, 'arm_billboard')
layout.prop(mat, 'arm_particle')
if mat.arm_particle == 'gpu':
layout.prop(mat, 'arm_particle_fade')
row = layout.row()
row.prop(mat, 'arm_tilesheet_mat')
row.prop(mat, 'arm_blending')