ead7dc9d32
This was done because the original "_biasLightWorldViewProjectionMatrix" relies on renderpath.light, which is problematic when rendering the deferred light pass and there is a sun and other lights of different type on the scene. Which would result on the wrong light being picked up for the calculation of the uniform value.
742 lines
31 KiB
Python
742 lines
31 KiB
Python
import bpy
|
|
import arm.assets as assets
|
|
import arm.material.mat_state as mat_state
|
|
import arm.material.mat_utils as mat_utils
|
|
import arm.material.cycles as cycles
|
|
import arm.material.make_tess as make_tess
|
|
import arm.material.make_particle as make_particle
|
|
import arm.material.make_cluster as make_cluster
|
|
import arm.material.make_finalize as make_finalize
|
|
import arm.material.make_attrib as make_attrib
|
|
import arm.utils
|
|
|
|
is_displacement = False
|
|
write_material_attribs = None
|
|
write_material_attribs_post = None
|
|
write_vertex_attribs = None
|
|
|
|
def make(context_id, rpasses):
|
|
wrd = bpy.data.worlds['Arm']
|
|
rpdat = arm.utils.get_rp()
|
|
rid = rpdat.rp_renderer
|
|
|
|
con = { 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' }
|
|
|
|
# Blend context
|
|
mat = mat_state.material
|
|
blend = mat.arm_blending
|
|
particle = mat_state.material.arm_particle_flag
|
|
dprepass = rid == 'Forward' and rpdat.rp_depthprepass
|
|
if blend:
|
|
con['name'] = 'blend'
|
|
con['blend_source'] = mat.arm_blending_source
|
|
con['blend_destination'] = mat.arm_blending_destination
|
|
con['blend_operation'] = mat.arm_blending_operation
|
|
con['alpha_blend_source'] = mat.arm_blending_source_alpha
|
|
con['alpha_blend_destination'] = mat.arm_blending_destination_alpha
|
|
con['alpha_blend_operation'] = mat.arm_blending_operation_alpha
|
|
con['depth_write'] = False
|
|
con['compare_mode'] = 'less'
|
|
elif particle:
|
|
pass
|
|
elif dprepass: # Depth prepass was performed
|
|
con['depth_write'] = False
|
|
con['compare_mode'] = 'equal'
|
|
|
|
attachment_format = 'RGBA32' if '_LDR' in wrd.world_defs else 'RGBA64'
|
|
con['color_attachments'] = [attachment_format, attachment_format]
|
|
if '_gbuffer2' in wrd.world_defs:
|
|
con['color_attachments'].append(attachment_format)
|
|
|
|
con_mesh = mat_state.data.add_context(con)
|
|
mat_state.con_mesh = con_mesh
|
|
|
|
if rid == 'Forward' or blend:
|
|
if rpdat.arm_material_model == 'Mobile':
|
|
make_forward_mobile(con_mesh)
|
|
elif rpdat.arm_material_model == 'Solid':
|
|
make_forward_solid(con_mesh)
|
|
else:
|
|
make_forward(con_mesh)
|
|
elif rid == 'Deferred':
|
|
make_deferred(con_mesh, rpasses)
|
|
elif rid == 'Raytracer':
|
|
make_raytracer(con_mesh)
|
|
|
|
make_finalize.make(con_mesh)
|
|
|
|
assets.vs_equal(con_mesh, assets.shader_cons['mesh_vert'])
|
|
|
|
return con_mesh
|
|
|
|
def make_base(con_mesh, parse_opacity):
|
|
global is_displacement
|
|
global write_material_attribs
|
|
global write_material_attribs_post
|
|
global write_vertex_attribs
|
|
wrd = bpy.data.worlds['Arm']
|
|
|
|
vert = con_mesh.make_vert()
|
|
frag = con_mesh.make_frag()
|
|
geom = None
|
|
tesc = None
|
|
tese = None
|
|
|
|
vert.add_uniform('mat3 N', '_normalMatrix')
|
|
vert.write_attrib('vec4 spos = vec4(pos.xyz, 1.0);')
|
|
|
|
vattr_written = False
|
|
rpdat = arm.utils.get_rp()
|
|
is_displacement = mat_utils.disp_linked(mat_state.output_node)
|
|
if is_displacement:
|
|
if rpdat.arm_rp_displacement == 'Vertex':
|
|
frag.ins = vert.outs
|
|
else: # Tessellation
|
|
tesc = con_mesh.make_tesc()
|
|
tese = con_mesh.make_tese()
|
|
tesc.ins = vert.outs
|
|
tese.ins = tesc.outs
|
|
frag.ins = tese.outs
|
|
make_tess.tesc_levels(tesc, rpdat.arm_tess_mesh_inner, rpdat.arm_tess_mesh_outer)
|
|
make_tess.interpolate(tese, 'wposition', 3, declare_out=True)
|
|
make_tess.interpolate(tese, 'wnormal', 3, declare_out=True, normalize=True)
|
|
# No displacement
|
|
else:
|
|
frag.ins = vert.outs
|
|
if write_vertex_attribs != None:
|
|
vattr_written = write_vertex_attribs(vert)
|
|
|
|
frag.add_include('compiled.inc')
|
|
|
|
written = False
|
|
if write_material_attribs != None:
|
|
written = write_material_attribs(con_mesh, frag)
|
|
if written == False:
|
|
frag.write('vec3 basecol;')
|
|
frag.write('float roughness;')
|
|
frag.write('float metallic;')
|
|
frag.write('float occlusion;')
|
|
frag.write('float specular;')
|
|
if '_Emission' in wrd.world_defs:
|
|
frag.write('float emission;')
|
|
if parse_opacity:
|
|
frag.write('float opacity;')
|
|
cycles.parse(mat_state.nodes, con_mesh, vert, frag, geom, tesc, tese, parse_opacity=parse_opacity)
|
|
if write_material_attribs_post != None:
|
|
write_material_attribs_post(con_mesh, frag)
|
|
|
|
vert.add_out('vec3 wnormal')
|
|
make_attrib.write_norpos(con_mesh, vert)
|
|
frag.write_attrib('vec3 n = normalize(wnormal);')
|
|
|
|
if not is_displacement and not vattr_written:
|
|
make_attrib.write_vertpos(vert)
|
|
|
|
if con_mesh.is_elem('tex'):
|
|
vert.add_out('vec2 texCoord')
|
|
vert.add_uniform('float texUnpack', link='_texUnpack')
|
|
if mat_state.material.arm_tilesheet_flag:
|
|
if mat_state.material.arm_particle_flag and rpdat.arm_particles == 'On':
|
|
make_particle.write_tilesheet(vert)
|
|
else:
|
|
vert.add_uniform('vec2 tilesheetOffset', '_tilesheetOffset')
|
|
vert.write_attrib('texCoord = tex * texUnpack + tilesheetOffset;')
|
|
else:
|
|
vert.write_attrib('texCoord = tex * texUnpack;')
|
|
|
|
if tese is not None:
|
|
tese.write_pre = True
|
|
make_tess.interpolate(tese, 'texCoord', 2, declare_out=frag.contains('texCoord'))
|
|
tese.write_pre = False
|
|
|
|
if con_mesh.is_elem('tex1'):
|
|
vert.add_out('vec2 texCoord1')
|
|
vert.add_uniform('float texUnpack', link='_texUnpack')
|
|
vert.write_attrib('texCoord1 = tex1 * texUnpack;')
|
|
if tese is not None:
|
|
tese.write_pre = True
|
|
make_tess.interpolate(tese, 'texCoord1', 2, declare_out=frag.contains('texCoord1'))
|
|
tese.write_pre = False
|
|
|
|
if con_mesh.is_elem('col'):
|
|
vert.add_out('vec3 vcolor')
|
|
vert.write_attrib('vcolor = col.rgb;')
|
|
if tese is not None:
|
|
tese.write_pre = True
|
|
make_tess.interpolate(tese, 'vcolor', 3, declare_out=frag.contains('vcolor'))
|
|
tese.write_pre = False
|
|
|
|
if con_mesh.is_elem('tang'):
|
|
if tese is not None:
|
|
tese.add_out('mat3 TBN')
|
|
tese.write_attrib('vec3 wbitangent = normalize(cross(wnormal, wtangent));')
|
|
tese.write_attrib('TBN = mat3(wtangent, wbitangent, wnormal);')
|
|
else:
|
|
vert.add_out('mat3 TBN')
|
|
vert.write_attrib('vec3 tangent = normalize(N * tang.xyz);')
|
|
vert.write_attrib('vec3 bitangent = normalize(cross(wnormal, tangent));')
|
|
vert.write_attrib('TBN = mat3(tangent, bitangent, wnormal);')
|
|
|
|
if is_displacement:
|
|
if rpdat.arm_rp_displacement == 'Vertex':
|
|
sh = vert
|
|
else:
|
|
sh = tese
|
|
if(con_mesh.is_elem('ipos')):
|
|
vert.write('wposition = vec4(W * spos).xyz;')
|
|
sh.add_uniform('mat4 VP', '_viewProjectionMatrix')
|
|
sh.write('wposition += wnormal * disp;')
|
|
sh.write('gl_Position = VP * vec4(wposition, 1.0);')
|
|
|
|
def make_deferred(con_mesh, rpasses):
|
|
wrd = bpy.data.worlds['Arm']
|
|
rpdat = arm.utils.get_rp()
|
|
|
|
arm_discard = mat_state.material.arm_discard
|
|
parse_opacity = arm_discard or 'translucent' in rpasses
|
|
|
|
make_base(con_mesh, parse_opacity=parse_opacity)
|
|
|
|
frag = con_mesh.frag
|
|
vert = con_mesh.vert
|
|
tese = con_mesh.tese
|
|
|
|
if parse_opacity:
|
|
if arm_discard:
|
|
opac = mat_state.material.arm_discard_opacity
|
|
else:
|
|
opac = '0.9999' # 1.0 - eps
|
|
frag.write('if (opacity < {0}) discard;'.format(opac))
|
|
|
|
gapi = arm.utils.get_gapi()
|
|
if '_gbuffer2' in wrd.world_defs:
|
|
frag.add_out('vec4 fragColor[3]')
|
|
if '_Veloc' in wrd.world_defs:
|
|
if tese == None:
|
|
vert.add_uniform('mat4 prevWVP', link='_prevWorldViewProjectionMatrix')
|
|
vert.add_out('vec4 wvpposition')
|
|
vert.add_out('vec4 prevwvpposition')
|
|
vert.write('wvpposition = gl_Position;')
|
|
if is_displacement:
|
|
vert.add_uniform('mat4 invW', link='_inverseWorldMatrix')
|
|
vert.write('prevwvpposition = prevWVP * (invW * vec4(wposition, 1.0));')
|
|
else:
|
|
vert.write('prevwvpposition = prevWVP * spos;')
|
|
else:
|
|
tese.add_out('vec4 wvpposition')
|
|
tese.add_out('vec4 prevwvpposition')
|
|
tese.write('wvpposition = gl_Position;')
|
|
if is_displacement:
|
|
tese.add_uniform('mat4 invW', link='_inverseWorldMatrix')
|
|
tese.add_uniform('mat4 prevWVP', '_prevWorldViewProjectionMatrix')
|
|
tese.write('prevwvpposition = prevWVP * (invW * vec4(wposition, 1.0));')
|
|
else:
|
|
vert.add_uniform('mat4 prevW', link='_prevWorldMatrix')
|
|
vert.add_out('vec3 prevwposition')
|
|
vert.write('prevwposition = vec4(prevW * spos).xyz;')
|
|
tese.add_uniform('mat4 prevVP', '_prevViewProjectionMatrix')
|
|
make_tess.interpolate(tese, 'prevwposition', 3)
|
|
tese.write('prevwvpposition = prevVP * vec4(prevwposition, 1.0);')
|
|
else:
|
|
frag.add_out('vec4 fragColor[2]')
|
|
|
|
# Pack gbuffer
|
|
frag.add_include('std/gbuffer.glsl')
|
|
|
|
if mat_state.material.arm_two_sided:
|
|
frag.write('if (!gl_FrontFacing) n *= -1;') # Flip normal when drawing back-face
|
|
|
|
frag.write('n /= (abs(n.x) + abs(n.y) + abs(n.z));')
|
|
frag.write('n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);')
|
|
|
|
if '_Emission' in wrd.world_defs or '_SSS' in wrd.world_defs or '_Hair' in wrd.world_defs:
|
|
frag.write('uint matid = 0;')
|
|
if '_Emission' in wrd.world_defs:
|
|
frag.write('if (emission > 0) { basecol *= emission; matid = 1; }')
|
|
if '_SSS' in wrd.world_defs or '_Hair' in wrd.world_defs:
|
|
frag.add_uniform('int materialID')
|
|
frag.write('if (materialID == 2) matid = 2;')
|
|
else:
|
|
frag.write('const uint matid = 0;')
|
|
|
|
frag.write('fragColor[0] = vec4(n.xy, roughness, packFloatInt16(metallic, matid));')
|
|
frag.write('fragColor[1] = vec4(basecol, packFloat2(occlusion, specular));')
|
|
|
|
if '_gbuffer2' in wrd.world_defs:
|
|
if '_Veloc' in wrd.world_defs:
|
|
frag.write('vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;')
|
|
frag.write('vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5;')
|
|
frag.write('fragColor[2].rg = vec2(posa - posb);')
|
|
|
|
if mat_state.material.arm_ignore_irradiance:
|
|
frag.write('fragColor[2].b = 1.0;')
|
|
|
|
return con_mesh
|
|
|
|
def make_raytracer(con_mesh):
|
|
con_mesh.data['vertex_elements'] = [{'name': 'pos', 'data': 'float3'}, {'name': 'nor', 'data': 'float3'}, {'name': 'tex', 'data': 'float2'}]
|
|
wrd = bpy.data.worlds['Arm']
|
|
vert = con_mesh.make_vert()
|
|
frag = con_mesh.make_frag()
|
|
vert.add_out('vec3 n')
|
|
vert.add_out('vec2 uv')
|
|
vert.write('n = nor;')
|
|
vert.write('uv = tex;')
|
|
vert.write('gl_Position = vec4(pos.xyz, 1.0);')
|
|
|
|
def make_forward_mobile(con_mesh):
|
|
wrd = bpy.data.worlds['Arm']
|
|
vert = con_mesh.make_vert()
|
|
frag = con_mesh.make_frag()
|
|
geom = None
|
|
tesc = None
|
|
tese = None
|
|
|
|
vert.add_uniform('mat3 N', '_normalMatrix')
|
|
vert.write_attrib('vec4 spos = vec4(pos.xyz, 1.0);')
|
|
frag.ins = vert.outs
|
|
|
|
make_attrib.write_vertpos(vert)
|
|
|
|
frag.add_include('compiled.inc')
|
|
frag.write('vec3 basecol;')
|
|
frag.write('float roughness;')
|
|
frag.write('float metallic;')
|
|
frag.write('float occlusion;')
|
|
frag.write('float specular;')
|
|
if '_Emission' in wrd.world_defs:
|
|
frag.write('float emission;')
|
|
|
|
arm_discard = mat_state.material.arm_discard
|
|
blend = mat_state.material.arm_blending
|
|
is_transluc = mat_utils.is_transluc(mat_state.material)
|
|
parse_opacity = (blend and is_transluc) or arm_discard
|
|
if parse_opacity:
|
|
frag.write('float opacity;')
|
|
|
|
cycles.parse(mat_state.nodes, con_mesh, vert, frag, geom, tesc, tese, parse_opacity=parse_opacity, parse_displacement=False)
|
|
|
|
if arm_discard:
|
|
opac = mat_state.material.arm_discard_opacity
|
|
frag.write('if (opacity < {0}) discard;'.format(opac))
|
|
|
|
if con_mesh.is_elem('tex'):
|
|
vert.add_out('vec2 texCoord')
|
|
vert.add_uniform('float texUnpack', link='_texUnpack')
|
|
if mat_state.material.arm_tilesheet_flag:
|
|
vert.add_uniform('vec2 tilesheetOffset', '_tilesheetOffset')
|
|
vert.write('texCoord = tex * texUnpack + tilesheetOffset;')
|
|
else:
|
|
vert.write('texCoord = tex * texUnpack;')
|
|
|
|
if con_mesh.is_elem('col'):
|
|
vert.add_out('vec3 vcolor')
|
|
vert.write('vcolor = col.rgb;')
|
|
|
|
if con_mesh.is_elem('tang'):
|
|
vert.add_out('mat3 TBN')
|
|
make_attrib.write_norpos(con_mesh, vert, declare=True)
|
|
vert.write('vec3 tangent = normalize(N * tang.xyz);')
|
|
vert.write('vec3 bitangent = normalize(cross(wnormal, tangent));')
|
|
vert.write('TBN = mat3(tangent, bitangent, wnormal);')
|
|
else:
|
|
vert.add_out('vec3 wnormal')
|
|
make_attrib.write_norpos(con_mesh, vert)
|
|
frag.write_attrib('vec3 n = normalize(wnormal);')
|
|
|
|
frag.add_include('std/math.glsl')
|
|
frag.add_include('std/brdf.glsl')
|
|
|
|
frag.add_out('vec4 fragColor')
|
|
blend = mat_state.material.arm_blending
|
|
if blend:
|
|
if parse_opacity:
|
|
frag.write('fragColor = vec4(basecol, opacity);')
|
|
else:
|
|
frag.write('fragColor = vec4(basecol, 1.0);')
|
|
return
|
|
|
|
is_shadows = '_ShadowMap' in wrd.world_defs
|
|
is_shadows_atlas = '_ShadowMapAtlas' in wrd.world_defs
|
|
shadowmap_sun = 'shadowMap'
|
|
if is_shadows_atlas:
|
|
is_single_atlas = '_SingleAtlas' in wrd.world_defs
|
|
shadowmap_sun = 'shadowMapAtlasSun' if not is_single_atlas else 'shadowMapAtlas'
|
|
frag.add_uniform('vec2 smSizeUniform', '_shadowMapSize', included=True)
|
|
frag.write('vec3 direct = vec3(0.0);')
|
|
|
|
if '_Sun' in wrd.world_defs:
|
|
frag.add_uniform('vec3 sunCol', '_sunColor')
|
|
frag.add_uniform('vec3 sunDir', '_sunDirection')
|
|
frag.write('float svisibility = 1.0;')
|
|
frag.write('float sdotNL = max(dot(n, sunDir), 0.0);')
|
|
if is_shadows:
|
|
vert.add_out('vec4 lightPosition')
|
|
vert.add_uniform('mat4 LWVP', '_biasLightWorldViewProjectionMatrixSun')
|
|
vert.write('lightPosition = LWVP * spos;')
|
|
frag.add_uniform('bool receiveShadow')
|
|
frag.add_uniform(f'sampler2DShadow {shadowmap_sun}')
|
|
frag.add_uniform('float shadowsBias', '_sunShadowsBias')
|
|
|
|
frag.write('if (receiveShadow) {')
|
|
if '_CSM' in wrd.world_defs:
|
|
frag.add_include('std/shadows.glsl')
|
|
frag.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True)
|
|
frag.add_uniform('vec3 eye', '_cameraPosition')
|
|
frag.write(f'svisibility = shadowTestCascade({shadowmap_sun}, eye, wposition + n * shadowsBias * 10, shadowsBias);')
|
|
else:
|
|
frag.write('if (lightPosition.w > 0.0) {')
|
|
frag.write(' vec3 lPos = lightPosition.xyz / lightPosition.w;')
|
|
if '_Legacy' in wrd.world_defs:
|
|
frag.write(f' svisibility = float(texture({shadowmap_sun}, vec2(lPos.xy)).r > lPos.z - shadowsBias);')
|
|
else:
|
|
frag.write(f' svisibility = texture({shadowmap_sun}, vec3(lPos.xy, lPos.z - shadowsBias)).r;')
|
|
frag.write('}')
|
|
frag.write('}') # receiveShadow
|
|
frag.write('direct += basecol * sdotNL * sunCol * svisibility;')
|
|
|
|
if '_SinglePoint' in wrd.world_defs:
|
|
frag.add_uniform('vec3 pointPos', '_pointPosition')
|
|
frag.add_uniform('vec3 pointCol', '_pointColor')
|
|
if '_Spot' in wrd.world_defs:
|
|
frag.add_uniform('vec3 spotDir', link='_spotDirection')
|
|
frag.add_uniform('vec2 spotData', link='_spotData')
|
|
frag.write('float visibility = 1.0;')
|
|
frag.write('vec3 ld = pointPos - wposition;')
|
|
frag.write('vec3 l = normalize(ld);')
|
|
frag.write('float dotNL = max(dot(n, l), 0.0);')
|
|
if is_shadows:
|
|
frag.add_uniform('bool receiveShadow')
|
|
frag.add_uniform('float pointBias', link='_pointShadowsBias')
|
|
frag.add_include('std/shadows.glsl')
|
|
|
|
frag.write('if (receiveShadow) {')
|
|
if '_Spot' in wrd.world_defs:
|
|
vert.add_out('vec4 spotPosition')
|
|
vert.add_uniform('mat4 LWVPSpotArray[1]', link='_biasLightWorldViewProjectionMatrixSpotArray')
|
|
vert.write('spotPosition = LWVPSpotArray[0] * spos;')
|
|
frag.add_uniform('sampler2DShadow shadowMapSpot[1]')
|
|
frag.write('if (spotPosition.w > 0.0) {')
|
|
frag.write(' vec3 lPos = spotPosition.xyz / spotPosition.w;')
|
|
if '_Legacy' in wrd.world_defs:
|
|
frag.write(' visibility = float(texture(shadowMapSpot[0], vec2(lPos.xy)).r > lPos.z - pointBias);')
|
|
else:
|
|
frag.write(' visibility = texture(shadowMapSpot[0], vec3(lPos.xy, lPos.z - pointBias)).r;')
|
|
frag.write('}')
|
|
else:
|
|
frag.add_uniform('vec2 lightProj', link='_lightPlaneProj')
|
|
frag.add_uniform('samplerCubeShadow shadowMapPoint[1]')
|
|
frag.write('const float s = shadowmapCubePcfSize;') # TODO: incorrect...
|
|
frag.write('float compare = lpToDepth(ld, lightProj) - pointBias * 1.5;')
|
|
frag.write('#ifdef _InvY')
|
|
frag.write('l.y = -l.y;')
|
|
frag.write('#endif')
|
|
if '_Legacy' in wrd.world_defs:
|
|
frag.write('visibility = float(texture(shadowMapPoint[0], vec3(-l + n * pointBias * 20)).r > compare);')
|
|
else:
|
|
frag.write('visibility = texture(shadowMapPoint[0], vec4(-l + n * pointBias * 20, compare)).r;')
|
|
frag.write('}') # receiveShadow
|
|
|
|
frag.write('direct += basecol * dotNL * pointCol * attenuate(distance(wposition, pointPos)) * visibility;')
|
|
|
|
if '_Clusters' in wrd.world_defs:
|
|
frag.add_include('std/light_mobile.glsl')
|
|
frag.write('vec3 albedo = basecol;')
|
|
frag.write('vec3 f0 = surfaceF0(basecol, metallic);')
|
|
make_cluster.write(vert, frag)
|
|
|
|
if '_Irr' in wrd.world_defs:
|
|
frag.add_include('std/shirr.glsl')
|
|
frag.add_uniform('vec4 shirr[7]', link='_envmapIrradiance')
|
|
env_str = 'shIrradiance(n, shirr)'
|
|
else:
|
|
env_str = '0.5'
|
|
|
|
frag.add_uniform('float envmapStrength', link='_envmapStrength')
|
|
frag.write('fragColor = vec4(direct + basecol * {0} * envmapStrength, 1.0);'.format(env_str))
|
|
|
|
if '_LDR' in wrd.world_defs:
|
|
frag.write('fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));')
|
|
|
|
def make_forward_solid(con_mesh):
|
|
wrd = bpy.data.worlds['Arm']
|
|
vert = con_mesh.make_vert()
|
|
frag = con_mesh.make_frag()
|
|
geom = None
|
|
tesc = None
|
|
tese = None
|
|
|
|
for e in con_mesh.data['vertex_elements']:
|
|
if e['name'] == 'nor':
|
|
con_mesh.data['vertex_elements'].remove(e)
|
|
break
|
|
|
|
vert.write_attrib('vec4 spos = vec4(pos.xyz, 1.0);')
|
|
frag.ins = vert.outs
|
|
|
|
make_attrib.write_vertpos(vert)
|
|
|
|
frag.add_include('compiled.inc')
|
|
frag.write('vec3 basecol;')
|
|
frag.write('float roughness;')
|
|
frag.write('float metallic;')
|
|
frag.write('float occlusion;')
|
|
frag.write('float specular;')
|
|
if '_Emission' in wrd.world_defs:
|
|
frag.write('float emission;')
|
|
|
|
arm_discard = mat_state.material.arm_discard
|
|
blend = mat_state.material.arm_blending
|
|
is_transluc = mat_utils.is_transluc(mat_state.material)
|
|
parse_opacity = (blend and is_transluc) or arm_discard
|
|
if parse_opacity:
|
|
frag.write('float opacity;')
|
|
|
|
cycles.parse(mat_state.nodes, con_mesh, vert, frag, geom, tesc, tese, parse_opacity=parse_opacity, parse_displacement=False, basecol_only=True)
|
|
|
|
if arm_discard:
|
|
opac = mat_state.material.arm_discard_opacity
|
|
frag.write('if (opacity < {0}) discard;'.format(opac))
|
|
|
|
if con_mesh.is_elem('tex'):
|
|
vert.add_out('vec2 texCoord')
|
|
vert.add_uniform('float texUnpack', link='_texUnpack')
|
|
if mat_state.material.arm_tilesheet_flag:
|
|
vert.add_uniform('vec2 tilesheetOffset', '_tilesheetOffset')
|
|
vert.write('texCoord = tex * texUnpack + tilesheetOffset;')
|
|
else:
|
|
vert.write('texCoord = tex * texUnpack;')
|
|
|
|
if con_mesh.is_elem('col'):
|
|
vert.add_out('vec3 vcolor')
|
|
vert.write('vcolor = col.rgb;')
|
|
|
|
make_attrib.write_norpos(con_mesh, vert, write_nor=False)
|
|
|
|
frag.add_out('vec4 fragColor')
|
|
if blend and parse_opacity:
|
|
frag.write('fragColor = vec4(basecol, opacity);')
|
|
else:
|
|
frag.write('fragColor = vec4(basecol, 1.0);')
|
|
|
|
if '_LDR' in wrd.world_defs:
|
|
frag.write('fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));')
|
|
|
|
def make_forward(con_mesh):
|
|
wrd = bpy.data.worlds['Arm']
|
|
rpdat = arm.utils.get_rp()
|
|
blend = mat_state.material.arm_blending
|
|
parse_opacity = blend or mat_utils.is_transluc(mat_state.material)
|
|
|
|
make_forward_base(con_mesh, parse_opacity=parse_opacity)
|
|
|
|
frag = con_mesh.frag
|
|
|
|
if '_LTC' in wrd.world_defs:
|
|
frag.add_uniform('vec3 lightArea0', '_lightArea0', included=True)
|
|
frag.add_uniform('vec3 lightArea1', '_lightArea1', included=True)
|
|
frag.add_uniform('vec3 lightArea2', '_lightArea2', included=True)
|
|
frag.add_uniform('vec3 lightArea3', '_lightArea3', included=True)
|
|
frag.add_uniform('sampler2D sltcMat', '_ltcMat', included=True)
|
|
frag.add_uniform('sampler2D sltcMag', '_ltcMag', included=True)
|
|
if '_ShadowMap' in wrd.world_defs:
|
|
if '_SinglePoint' in wrd.world_defs:
|
|
frag.add_uniform('mat4 LWVPSpot[0]', link='_biasLightViewProjectionMatrixSpot0', included=True)
|
|
frag.add_uniform('sampler2DShadow shadowMapSpot[1]', included=True)
|
|
if '_Clusters' in wrd.world_defs:
|
|
frag.add_uniform('mat4 LWVPSpotArray[4]', link='_biasLightWorldViewProjectionMatrixSpotArray', included=True)
|
|
frag.add_uniform('sampler2DShadow shadowMapSpot[4]', included=True)
|
|
|
|
if not blend:
|
|
mrt = rpdat.rp_ssr
|
|
if mrt:
|
|
# Store light gbuffer for post-processing
|
|
frag.add_out('vec4 fragColor[2]')
|
|
frag.add_include('std/gbuffer.glsl')
|
|
frag.write('n /= (abs(n.x) + abs(n.y) + abs(n.z));')
|
|
frag.write('n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);')
|
|
frag.write('fragColor[0] = vec4(direct + indirect, packFloat2(occlusion, specular));')
|
|
frag.write('fragColor[1] = vec4(n.xy, roughness, metallic);')
|
|
else:
|
|
frag.add_out('vec4 fragColor[1]')
|
|
frag.write('fragColor[0] = vec4(direct + indirect, 1.0);')
|
|
|
|
if '_LDR' in wrd.world_defs:
|
|
frag.add_include('std/tonemap.glsl')
|
|
frag.write('fragColor[0].rgb = tonemapFilmic(fragColor[0].rgb);')
|
|
|
|
# Particle opacity
|
|
if mat_state.material.arm_particle_flag and arm.utils.get_rp().arm_particles == 'On' and mat_state.material.arm_particle_fade:
|
|
frag.write('fragColor[0].rgb *= p_fade;')
|
|
|
|
def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
|
global is_displacement
|
|
wrd = bpy.data.worlds['Arm']
|
|
|
|
arm_discard = mat_state.material.arm_discard
|
|
make_base(con_mesh, parse_opacity=(parse_opacity or arm_discard))
|
|
|
|
blend = mat_state.material.arm_blending
|
|
|
|
vert = con_mesh.vert
|
|
frag = con_mesh.frag
|
|
tese = con_mesh.tese
|
|
|
|
if parse_opacity or arm_discard:
|
|
if arm_discard or blend:
|
|
opac = mat_state.material.arm_discard_opacity
|
|
frag.write('if (opacity < {0}) discard;'.format(opac))
|
|
elif transluc_pass:
|
|
frag.write('if (opacity == 1.0) discard;')
|
|
else:
|
|
opac = '0.9999' # 1.0 - eps
|
|
frag.write('if (opacity < {0}) discard;'.format(opac))
|
|
|
|
if blend:
|
|
frag.add_out('vec4 fragColor[1]')
|
|
if parse_opacity:
|
|
frag.write('fragColor[0] = vec4(basecol, opacity);')
|
|
else:
|
|
# frag.write('fragColor[0] = vec4(basecol * lightCol * visibility, 1.0);')
|
|
frag.write('fragColor[0] = vec4(basecol, 1.0);')
|
|
# TODO: Fade out fragments near depth buffer here
|
|
return
|
|
|
|
frag.write_attrib('vec3 vVec = normalize(eyeDir);')
|
|
frag.write_attrib('float dotNV = max(dot(n, vVec), 0.0);')
|
|
|
|
sh = tese if tese is not None else vert
|
|
sh.add_out('vec3 eyeDir')
|
|
sh.add_uniform('vec3 eye', '_cameraPosition')
|
|
sh.write('eyeDir = eye - wposition;')
|
|
|
|
frag.add_include('std/light.glsl')
|
|
is_shadows = '_ShadowMap' in wrd.world_defs
|
|
is_shadows_atlas = '_ShadowMapAtlas' in wrd.world_defs
|
|
is_single_atlas = is_shadows_atlas and '_SingleAtlas' in wrd.world_defs
|
|
shadowmap_sun = 'shadowMap'
|
|
if is_shadows_atlas:
|
|
shadowmap_sun = 'shadowMapAtlasSun' if not is_single_atlas else 'shadowMapAtlas'
|
|
frag.add_uniform('vec2 smSizeUniform', '_shadowMapSize', included=True)
|
|
|
|
frag.write('vec3 albedo = surfaceAlbedo(basecol, metallic);')
|
|
frag.write('vec3 f0 = surfaceF0(basecol, metallic);')
|
|
|
|
if '_Brdf' in wrd.world_defs:
|
|
frag.add_uniform('sampler2D senvmapBrdf', link='$brdf.png')
|
|
frag.write('vec2 envBRDF = texture(senvmapBrdf, vec2(roughness, 1.0 - dotNV)).xy;')
|
|
|
|
if '_Irr' in wrd.world_defs:
|
|
frag.add_include('std/shirr.glsl')
|
|
frag.add_uniform('vec4 shirr[7]', link='_envmapIrradiance')
|
|
frag.write('vec3 indirect = shIrradiance(n, shirr);')
|
|
if '_EnvTex' in wrd.world_defs:
|
|
frag.write('indirect /= PI;')
|
|
frag.write('indirect *= albedo;')
|
|
if '_Rad' in wrd.world_defs:
|
|
frag.add_uniform('sampler2D senvmapRadiance', link='_envmapRadiance')
|
|
frag.add_uniform('int envmapNumMipmaps', link='_envmapNumMipmaps')
|
|
frag.write('vec3 reflectionWorld = reflect(-vVec, n);')
|
|
frag.write('float lod = getMipFromRoughness(roughness, envmapNumMipmaps);')
|
|
frag.write('vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;')
|
|
if '_EnvLDR' in wrd.world_defs:
|
|
frag.write('prefilteredColor = pow(prefilteredColor, vec3(2.2));')
|
|
frag.write('indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;')
|
|
elif '_EnvCol' in wrd.world_defs:
|
|
frag.add_uniform('vec3 backgroundCol', link='_backgroundCol')
|
|
frag.write('indirect += backgroundCol * f0;')
|
|
else:
|
|
frag.write('vec3 indirect = albedo;')
|
|
frag.write('indirect *= occlusion;')
|
|
|
|
frag.add_uniform('float envmapStrength', link='_envmapStrength')
|
|
frag.write('indirect *= envmapStrength;')
|
|
|
|
if '_VoxelAOvar' in wrd.world_defs:
|
|
frag.add_include('std/conetrace.glsl')
|
|
frag.add_uniform('sampler3D voxels')
|
|
if '_VoxelGICam' in wrd.world_defs:
|
|
frag.add_uniform('vec3 eyeSnap', link='_cameraPositionSnap')
|
|
frag.write('vec3 voxpos = (wposition - eyeSnap) / voxelgiHalfExtents;')
|
|
else:
|
|
frag.write('vec3 voxpos = wposition / voxelgiHalfExtents;')
|
|
frag.write('indirect *= vec3(1.0 - traceAO(voxpos, n, voxels));')
|
|
|
|
frag.write('vec3 direct = vec3(0.0);')
|
|
|
|
if '_Sun' in wrd.world_defs:
|
|
frag.add_uniform('vec3 sunCol', '_sunColor')
|
|
frag.add_uniform('vec3 sunDir', '_sunDirection')
|
|
frag.write('float svisibility = 1.0;')
|
|
frag.write('vec3 sh = normalize(vVec + sunDir);')
|
|
frag.write('float sdotNL = dot(n, sunDir);')
|
|
frag.write('float sdotNH = dot(n, sh);')
|
|
frag.write('float sdotVH = dot(vVec, sh);')
|
|
if is_shadows:
|
|
frag.add_uniform('bool receiveShadow')
|
|
frag.add_uniform(f'sampler2DShadow {shadowmap_sun}', top=True)
|
|
frag.add_uniform('float shadowsBias', '_sunShadowsBias')
|
|
frag.write('if (receiveShadow) {')
|
|
if '_CSM' in wrd.world_defs:
|
|
frag.add_include('std/shadows.glsl')
|
|
frag.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True)
|
|
frag.add_uniform('vec3 eye', '_cameraPosition')
|
|
frag.write(f'svisibility = shadowTestCascade({shadowmap_sun}, eye, wposition + n * shadowsBias * 10, shadowsBias);')
|
|
else:
|
|
if tese is not None:
|
|
tese.add_out('vec4 lightPosition')
|
|
tese.add_uniform('mat4 LVP', '_biasLightViewProjectionMatrix')
|
|
tese.write('lightPosition = LVP * vec4(wposition, 1.0);')
|
|
else:
|
|
if is_displacement:
|
|
vert.add_out('vec4 lightPosition')
|
|
vert.add_uniform('mat4 LVP', '_biasLightViewProjectionMatrix')
|
|
vert.write('lightPosition = LVP * vec4(wposition, 1.0);')
|
|
else:
|
|
vert.add_out('vec4 lightPosition')
|
|
vert.add_uniform('mat4 LWVP', '_biasLightWorldViewProjectionMatrixSun')
|
|
vert.write('lightPosition = LWVP * spos;')
|
|
frag.write('vec3 lPos = lightPosition.xyz / lightPosition.w;')
|
|
frag.write('const vec2 smSize = shadowmapSize;')
|
|
frag.write(f'svisibility = PCF({shadowmap_sun}, lPos.xy, lPos.z - shadowsBias, smSize);')
|
|
frag.write('}') # receiveShadow
|
|
if '_VoxelShadow' in wrd.world_defs and '_VoxelAOvar' in wrd.world_defs:
|
|
frag.write('svisibility *= 1.0 - traceShadow(voxels, voxpos, sunDir);')
|
|
frag.write('direct += (lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;')
|
|
# sun
|
|
|
|
if '_SinglePoint' in wrd.world_defs:
|
|
frag.add_uniform('vec3 pointPos', link='_pointPosition')
|
|
frag.add_uniform('vec3 pointCol', link='_pointColor')
|
|
if '_Spot' in wrd.world_defs:
|
|
frag.add_uniform('vec3 spotDir', link='_spotDirection')
|
|
frag.add_uniform('vec2 spotData', link='_spotData')
|
|
if is_shadows:
|
|
frag.add_uniform('bool receiveShadow')
|
|
frag.add_uniform('float pointBias', link='_pointShadowsBias')
|
|
if '_Spot' in wrd.world_defs:
|
|
# Skip world matrix, already in world-space
|
|
frag.add_uniform('mat4 LWVPSpot[1]', link='_biasLightViewProjectionMatrixSpotArray', included=True)
|
|
frag.add_uniform('sampler2DShadow shadowMapSpot[1]', included=True)
|
|
else:
|
|
frag.add_uniform('vec2 lightProj', link='_lightPlaneProj', included=True)
|
|
frag.add_uniform('samplerCubeShadow shadowMapPoint[1]', included=True)
|
|
frag.write('direct += sampleLight(')
|
|
frag.write(' wposition, n, vVec, dotNV, pointPos, pointCol, albedo, roughness, specular, f0')
|
|
if is_shadows:
|
|
frag.write(' , 0, pointBias, receiveShadow')
|
|
if '_Spot' in wrd.world_defs:
|
|
frag.write(' , true, spotData.x, spotData.y, spotDir')
|
|
if '_VoxelShadow' in wrd.world_defs and '_VoxelAOvar' in wrd.world_defs:
|
|
frag.write(' , voxels, voxpos')
|
|
frag.write(');')
|
|
|
|
if '_Clusters' in wrd.world_defs:
|
|
make_cluster.write(vert, frag)
|
|
|
|
if '_Emission' in wrd.world_defs:
|
|
frag.write('if (emission > 0.0) {')
|
|
frag.write(' direct = vec3(0.0);')
|
|
frag.write(' indirect += basecol * emission;')
|
|
frag.write('}')
|