More VR, restricted materials gen

This commit is contained in:
Lubos Lenco 2017-04-26 14:21:22 +02:00
parent 2099b1b80d
commit 56190c05f2
10 changed files with 206 additions and 36 deletions

BIN
Assets/vr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,43 @@
package armory.trait;
import iron.Trait;
import iron.system.Input;
import iron.system.Time;
import iron.object.CameraObject;
import iron.math.Vec4;
@:keep
class VRNavigation extends Trait {
#if arm_vr
static inline var speed = 5.0;
var camera:CameraObject;
var mouse:Mouse;
public function new() {
super();
notifyOnInit(init);
notifyOnUpdate(update);
}
function init() {
mouse = Input.getMouse();
camera = cast(object, CameraObject);
}
var look = new Vec4();
function update() {
// Testing..
if (mouse.down()) {
var vr = kha.vr.VrInterface.instance;
var V = (vr != null && vr.IsPresenting()) ? camera.leftV : camera.V;
look.set(-V._02, -V._12, -V._22);
camera.move(look, Time.delta * speed);
}
}
#end
}

View file

@ -771,6 +771,8 @@ def traverse_renderpath(node, node_group, render_targets, depth_buffers):
elif node.bl_idname == 'DrawStereoNodeType':
assets.add_khafile_def('arm_vr')
bpy.data.worlds['Arm'].rp_defs += '_VR'
assets.add(build_node_trees.assets_path + 'vr.png')
assets.add_embedded_data('vr.png')
elif node.bl_idname == 'CallFunctionNodeType':
global dynRes_added

View file

@ -17,12 +17,12 @@
import arm.material.cycles_functions as c_functions
import arm.material.cycles_state as c_state
def parse(nodes, vert, frag, geom, tesc, tese, parse_surface=True, parse_opacity=True, parse_displacement=True):
def parse(nodes, 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')
if output_node != None:
parse_output(output_node, vert, frag, geom, tesc, tese, parse_surface, parse_opacity, parse_displacement)
parse_output(output_node, vert, frag, geom, tesc, tese, parse_surface, parse_opacity, parse_displacement, basecol_only)
def parse_output(node, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse_opacity, parse_displacement):
def parse_output(node, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse_opacity, _parse_displacement, _basecol_only):
global parsed # Compute nodes only once
global parents
global normal_written # Normal socket is linked on shader node - overwrite fs normal
@ -36,6 +36,7 @@ def parse_output(node, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse
global parse_opacity
global parsing_basecol
global parse_teximage_vector
global basecol_only
vert = _vert
frag = _frag
geom = _geom
@ -45,6 +46,7 @@ def parse_output(node, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse
parse_opacity = _parse_opacity
parsing_basecol = False
parse_teximage_vector = True
basecol_only = _basecol_only
# Surface
if parse_surface or parse_opacity:
@ -52,13 +54,18 @@ def parse_output(node, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse
parents = []
normal_written = False
curshader = frag
if basecol_only:
frag.lock = True
out_basecol, out_roughness, out_metallic, out_occlusion, out_opacity = parse_shader_input(node.inputs[0])
if parse_surface:
frag.lock = False
frag.write('basecol = {0};'.format(out_basecol))
frag.write('roughness = {0};'.format(out_roughness))
frag.write('metallic = {0};'.format(out_metallic))
frag.write('occlusion = {0};'.format(out_occlusion))
if not basecol_only:
frag.write('roughness = {0};'.format(out_roughness))
frag.write('metallic = {0};'.format(out_metallic))
frag.write('occlusion = {0};'.format(out_occlusion))
if parse_opacity:
frag.write('opacity = {0};'.format(out_opacity))
@ -66,7 +73,7 @@ def parse_output(node, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse
# parse_volume_input(node.inputs[1])
# Displacement
if parse_displacement and c_state.tess_enabled() and node.inputs[2].is_linked and tese != None:
if _parse_displacement and c_state.tess_enabled() and node.inputs[2].is_linked and tese != None:
parsed = []
parents = []
normal_written = False
@ -129,6 +136,14 @@ def write_normal(inp):
curshader.write('n = {0};'.format(normal_res))
normal_written = True
def parsing_basecolor(b):
global parsing_basecol
global basecol_only
global curshader
parsing_basecol = b
if basecol_only:
curshader.lock = not b
def parse_shader(node, socket):
global parsing_basecol
out_basecol = 'vec3(0.8)'
@ -142,9 +157,9 @@ def parse_shader(node, socket):
if parse_surface:
# Base color
parsing_basecol = True
parsing_basecolor(True)
out_basecol = parse_vector_input(node.inputs[0])
parsing_basecol = False
parsing_basecolor(False)
# Occlusion TODO: deprecated, occlussion is value instead of vector now
if node.inputs[1].type == 'RGBA':
out_occlusion = '{0}.r'.format(parse_vector_input(node.inputs[1]))
@ -164,9 +179,9 @@ def parse_shader(node, socket):
parse_normal_map_color_input(node.inputs[6], node.inputs[7])
# Emission
if node.inputs[8].is_linked:
parsing_basecol = True
parsing_basecolor(True)
out_emission = parse_vector_input(node.inputs[8])
parsing_basecol = False
parsing_basecolor(False)
if node.inputs[9].is_linked or node.inputs[9].default_value != 1.0:
out_emission = '({0} * {1})'.format(out_emission, parse_value_input(node.inputs[9]))
out_basecol = '({0} + {1})'.format(out_basecol, out_emission)
@ -191,9 +206,9 @@ def parse_shader(node, socket):
bc1, rough1, met1, occ1, opac1 = parse_shader_input(node.inputs[1])
bc2, rough2, met2, occ2, opac2 = parse_shader_input(node.inputs[2])
if parse_surface:
parsing_basecol = True
parsing_basecolor(True)
out_basecol = '({0} * {3} + {1} * {2})'.format(bc1, bc2, fac_var, fac_inv_var)
parsing_basecol = False
parsing_basecolor(False)
out_roughness = '({0} * {3} + {1} * {2})'.format(rough1, rough2, fac_var, fac_inv_var)
out_metallic = '({0} * {3} + {1} * {2})'.format(met1, met2, fac_var, fac_inv_var)
out_occlusion = '({0} * {3} + {1} * {2})'.format(occ1, occ2, fac_var, fac_inv_var)
@ -204,9 +219,9 @@ def parse_shader(node, socket):
bc1, rough1, met1, occ1, opac1 = parse_shader_input(node.inputs[0])
bc2, rough2, met2, occ2, opac2 = parse_shader_input(node.inputs[1])
if parse_surface:
parsing_basecol = True
parsing_basecolor(True)
out_basecol = '({0} + {1})'.format(bc1, bc2)
parsing_basecol = False
parsing_basecolor(False)
out_roughness = '({0} * 0.5 + {1} * 0.5)'.format(rough1, rough2)
out_metallic = '({0} * 0.5 + {1} * 0.5)'.format(met1, met2)
out_occlusion = '({0} * 0.5 + {1} * 0.5)'.format(occ1, occ2)
@ -216,17 +231,17 @@ def parse_shader(node, socket):
elif node.type == 'BSDF_DIFFUSE':
if parse_surface:
write_normal(node.inputs[2])
parsing_basecol = True
parsing_basecolor(True)
out_basecol = parse_vector_input(node.inputs[0])
parsing_basecol = False
parsing_basecolor(False)
out_roughness = parse_value_input(node.inputs[1])
elif node.type == 'BSDF_GLOSSY':
if parse_surface:
write_normal(node.inputs[2])
parsing_basecol = True
parsing_basecolor(True)
out_basecol = parse_vector_input(node.inputs[0])
parsing_basecol = False
parsing_basecolor(False)
out_roughness = parse_value_input(node.inputs[1])
out_metallic = '1.0'
@ -239,18 +254,18 @@ def parse_shader(node, socket):
if parse_surface:
write_normal(node.inputs[4])
# Revert to glossy
parsing_basecol = True
parsing_basecolor(True)
out_basecol = parse_vector_input(node.inputs[0])
parsing_basecol = False
parsing_basecolor(False)
out_roughness = parse_value_input(node.inputs[1])
out_metallic = '1.0'
elif node.type == 'EMISSION':
if parse_surface:
# Multiply basecol
parsing_basecol = True
parsing_basecolor(True)
out_basecol = parse_vector_input(node.inputs[0])
parsing_basecol = False
parsing_basecolor(False)
strength = parse_value_input(node.inputs[1])
out_basecol = '({0} * {1} * 50.0)'.format(out_basecol, strength)
@ -294,9 +309,9 @@ def parse_shader(node, socket):
elif node.type == 'BSDF_VELVET':
if parse_surface:
write_normal(node.inputs[2])
parsing_basecol = True
parsing_basecolor(True)
out_basecol = parse_vector_input(node.inputs[0])
parsing_basecol = False
parsing_basecolor(False)
out_roughness = '1.0'
out_metallic = '1.0'

View file

@ -14,7 +14,10 @@ def make(context_id, rid):
con_mesh = mat_state.data.add_context({ 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' })
if rid == 'forward':
make_forward(con_mesh)
if bpy.data.cameras[0].rp_materials == 'Full':
make_forward(con_mesh)
else:
make_forward_restricted(con_mesh)
elif rid == 'deferred':
make_deferred(con_mesh)
elif rid == 'deferred_plus':
@ -273,6 +276,80 @@ def make_deferred_plus(con_mesh):
frag.write('fragColor[2] = vec4(dFdx(texCoord), dFdy(texCoord));')
# + tangent space
def make_forward_restricted(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_main_header('vec4 spos = vec4(pos, 1.0);')
frag.ins = vert.outs
vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix')
vert.write('gl_Position = WVP * spos;')
frag.add_include('../../Shaders/compiled.glsl')
frag.write('vec3 basecol;')
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, basecol_only=True, parse_opacity=False, parse_displacement=False)
if mat_state.data.is_elem('tex'):
vert.add_out('vec2 texCoord')
vert.write('texCoord = tex;')
if mat_state.data.is_elem('col'):
vert.add_out('vec3 vcolor')
vert.write('vcolor = col;')
vert.add_out('vec3 wnormal')
write_norpos(vert)
frag.write_pre = True
frag.write_main_header('vec3 n = normalize(wnormal);')
frag.write_pre = False
frag.add_uniform('vec3 lightColor', '_lampColor')
frag.add_uniform('vec3 lightDir', '_lampDirection')
frag.add_uniform('float envmapStrength', link='_envmapStrength')
if '_NoShadows' in wrd.world_defs:
is_shadows = False
else:
is_shadows = True
frag.write('float visibility = 1.0;')
frag.write('float dotNL = dot(n, lightDir);')
if is_shadows:
vert.add_out('vec4 lampPos')
vert.add_uniform('mat4 LWVP', '_biasLampWorldViewProjectionMatrix')
vert.write('lampPos = LWVP * spos;')
frag.add_include('../../Shaders/std/shadows.glsl')
frag.add_uniform('sampler2D shadowMap', included=True)
frag.add_uniform('float shadowsBias', '_lampShadowsBias')
frag.write(' if (lampPos.w > 0.0) {')
frag.write(' vec3 lpos = lampPos.xyz / lampPos.w;')
# frag.write(' visibility *= PCF(lpos.xy, lpos.z - shadowsBias);')
frag.write(' const float texelSize = 1.0 / shadowmapSize.x;')
frag.write(' visibility = 0.0;')
frag.write(' visibility += float(texture(shadowMap, lpos.xy).r + shadowsBias > lpos.z);')
frag.write(' visibility += float(texture(shadowMap, lpos.xy + vec2(texelSize, 0.0)).r + shadowsBias > lpos.z) * 0.5;')
frag.write(' visibility += float(texture(shadowMap, lpos.xy + vec2(-texelSize, 0.0)).r + shadowsBias > lpos.z) * 0.25;')
frag.write(' visibility += float(texture(shadowMap, lpos.xy + vec2(0.0, texelSize)).r + shadowsBias > lpos.z) * 0.5;')
frag.write(' visibility += float(texture(shadowMap, lpos.xy + vec2(0.0, -texelSize)).r + shadowsBias > lpos.z) * 0.25;')
frag.write(' visibility /= 2.5;')
frag.write(' visibility = max(visibility, 0.5);')
# frag.write(' visibility = max(float(texture(shadowMap, lpos.xy).r + shadowsBias > lpos.z), 0.5);')
frag.write(' }')
frag.write('vec3 direct = basecol * max(dotNL, 0.1);')
frag.add_out('vec4 fragColor')
frag.write('fragColor = vec4(direct * lightColor * visibility, 1.0);')
if '_LDR' in bpy.data.worlds['Arm'].rp_defs:
frag.write('fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));')
def make_forward(con_mesh):
make_forward_base(con_mesh)

View file

@ -15,14 +15,16 @@ def make(context_id, rpasses):
tesc = None
tese = None
if arm.utils.get_gapi() == 'direct3d9':
gapi = arm.utils.get_gapi()
if gapi == 'direct3d9':
frag.add_out('vec4 fragColor') # Definition requred for d3d9 - pixel shader must minimally write all four components of COLOR0
vert.write_main_header('vec4 spos = vec4(pos, 1.0);')
# TODO: pass vbuf with proper struct
vert.write('vec3 t1 = nor; // TODO: Temp for d3d')
if mat_state.data.is_elem('tex'):
vert.write('vec2 t2 = tex; // TODO: Temp for d3d')
if gapi.startswith('direct3d'):
vert.write('vec3 t1 = nor; // TODO: Temp for d3d')
if mat_state.data.is_elem('tex'):
vert.write('vec2 t2 = tex; // TODO: Temp for d3d')
parse_opacity = 'translucent' in rpasses
if parse_opacity:

View file

@ -18,6 +18,7 @@ class Shader:
self.write_pre = False
self.tab = 1
self.vertex_structure_as_vsinput = True
self.lock = False
def add_include(self, s):
self.includes.append(s)
@ -61,6 +62,8 @@ class Shader:
self.main_pre = s + '\n' + self.main_pre
def write(self, s):
if self.lock:
return
if self.write_pre:
self.main_pre += '\t' * 1 + s + '\n'
else:

View file

@ -18,7 +18,7 @@ except ImportError:
pass
# Armory version
arm_version = '17.04'
arm_version = '17.05'
def update_preset(self, context):
props_renderer.set_preset(self, context, self.rp_preset)
@ -298,6 +298,11 @@ def init_properties():
#('Path-Trace', 'Path-Trace', 'Path-Trace')],
],
name="Renderer", description="Renderer type", default='Deferred', update=update_renderpath)
bpy.types.Camera.rp_materials = EnumProperty(
items=[('Full', 'Full', 'Full'),
('Restricted', 'Restricted', 'Restricted'),
],
name="Materials", description="Material builder", default='Full', update=update_renderpath)
bpy.types.Camera.rp_depthprepass = bpy.props.BoolProperty(name="Depth Prepass", description="Depth Prepass for mesh context", default=False, update=update_renderpath)
bpy.types.Camera.rp_meshes = bpy.props.BoolProperty(name="Meshes", description="Render mesh objects", default=True, update=update_renderpath)
bpy.types.Camera.rp_hdr = bpy.props.BoolProperty(name="HDR", description="Render in HDR Space", default=True, update=update_renderpath)

View file

@ -18,6 +18,7 @@ def set_preset(self, context, preset):
if preset == 'Forward Low':
cam.rp_renderer = 'Forward'
cam.rp_materials = 'Full'
cam.rp_shadowmap = '1024'
cam.rp_meshes = True
cam.rp_translucency_state = 'Off'
@ -27,6 +28,7 @@ def set_preset(self, context, preset):
cam.rp_worldnodes = False
cam.rp_stereo = False
cam.rp_greasepencil = False
cam.rp_voxelgi = False
cam.rp_render_to_texture = False
cam.rp_supersampling = '1'
cam.rp_antialiasing = 'None'
@ -38,6 +40,7 @@ def set_preset(self, context, preset):
cam.rp_motionblur = 'None'
elif preset == 'Forward':
cam.rp_renderer = 'Forward'
cam.rp_materials = 'Full'
cam.rp_shadowmap = '2048'
cam.rp_meshes = True
cam.rp_translucency_state = 'Auto'
@ -47,6 +50,7 @@ def set_preset(self, context, preset):
cam.rp_worldnodes = True
cam.rp_stereo = False
cam.rp_greasepencil = False
cam.rp_voxelgi = False
cam.rp_render_to_texture = True
cam.rp_supersampling = '1'
cam.rp_antialiasing = 'FXAA'
@ -58,6 +62,7 @@ def set_preset(self, context, preset):
cam.rp_motionblur = 'None'
elif preset == 'Forward High':
cam.rp_renderer = 'Forward'
cam.rp_materials = 'Full'
cam.rp_shadowmap = '4096'
cam.rp_meshes = True
cam.rp_translucency_state = 'Auto'
@ -67,6 +72,7 @@ def set_preset(self, context, preset):
cam.rp_worldnodes = True
cam.rp_stereo = False
cam.rp_greasepencil = False
cam.rp_voxelgi = False
cam.rp_render_to_texture = True
cam.rp_supersampling = '1'
cam.rp_antialiasing = 'SMAA'
@ -87,6 +93,7 @@ def set_preset(self, context, preset):
cam.rp_worldnodes = True
cam.rp_stereo = False
cam.rp_greasepencil = False
cam.rp_voxelgi = False
cam.rp_render_to_texture = True
cam.rp_supersampling = '1'
cam.rp_antialiasing = 'FXAA'
@ -107,6 +114,7 @@ def set_preset(self, context, preset):
cam.rp_worldnodes = True
cam.rp_stereo = False
cam.rp_greasepencil = False
cam.rp_voxelgi = False
cam.rp_render_to_texture = True
cam.rp_supersampling = '1'
cam.rp_antialiasing = 'SMAA'
@ -127,6 +135,7 @@ def set_preset(self, context, preset):
cam.rp_worldnodes = True
cam.rp_stereo = False
cam.rp_greasepencil = False
cam.rp_voxelgi = False
cam.rp_render_to_texture = True
cam.rp_supersampling = '1'
cam.rp_antialiasing = 'TAA'
@ -140,15 +149,17 @@ def set_preset(self, context, preset):
pass
elif preset == 'VR Low':
cam.rp_renderer = 'Forward'
cam.rp_materials = 'Restricted'
cam.rp_shadowmap = '1024'
cam.rp_meshes = True
cam.rp_translucency_state = 'Off'
cam.rp_overlays_state = 'Off'
cam.rp_decals_state = 'Off'
cam.rp_hdr = False
cam.rp_worldnodes = True
cam.rp_worldnodes = False
cam.rp_stereo = True
cam.rp_greasepencil = False
cam.rp_voxelgi = False
cam.rp_render_to_texture = False
cam.rp_supersampling = '1'
cam.rp_antialiasing = 'None'
@ -159,7 +170,8 @@ def set_preset(self, context, preset):
cam.rp_bloom = False
cam.rp_motionblur = 'None'
elif preset == 'Grease Pencil':
cam.rp_renderer = 'Forward'
cam.rp_renderer = 'Restricted'
cam.rp_materials = 'Full'
cam.rp_shadowmap = 'None'
cam.rp_meshes = False
cam.rp_translucency_state = 'Off'
@ -212,6 +224,7 @@ class GenRPDataPropsPanel(bpy.types.Panel):
layout.prop(dat, "rp_preset")
layout.separator()
layout.prop(dat, "rp_renderer")
layout.prop(dat, "rp_materials")
layout.prop(dat, "rp_shadowmap")
layout.prop(dat, "rp_meshes")
layout.prop(dat, "rp_translucency_state")

View file

@ -233,18 +233,28 @@ def write_indexhtml(w, h):
"""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta charset="utf-8"/>""")
if bpy.data.cameras[0].rp_stereo:
f.write("""
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style>
body {
margin: 0;
}
</style>
""")
f.write("""
<title>Armory</title>
</head>
<body>
""")
if bpy.data.cameras[0].rp_stereo:
f.write("""
<canvas style="outline: none; position: absolute; left: 0; top: 0;" id='khanvas' width='""" + str(w) + """' height='""" + str(h) + """'></canvas>
<canvas style="width: 100vw; height: 100vh; display: block;" id='khanvas'></canvas>
""")
else:
f.write("""
<p align="center"><canvas style="outline: none;" id='khanvas' width='""" + str(w) + """' height='""" + str(h) + """'></canvas></p>
<p align="center"><canvas align="center" style="outline: none;" id='khanvas' width='""" + str(w) + """' height='""" + str(h) + """'></canvas></p>
""")
f.write("""
<script src='kha.js'></script>