Point shadows placeholder.

This commit is contained in:
Lubos Lenco 2016-11-07 16:11:35 +01:00
parent 8acd7bad43
commit c4e3c144e0
6 changed files with 122 additions and 29 deletions

View file

@ -106,6 +106,15 @@ vec3 SSSSTransmittance(float translucency, float sssWidth, vec3 worldPosition, v
float shadowTest(vec4 lPos) {
lPos.xyz /= lPos.w;
lPos.xy = lPos.xy * 0.5 + 0.5;
#ifdef _Clampstc
// Filtering out of bounds, remove
if (lPos.x < 0.0) return 1.0;
if (lPos.y < 0.0) return 1.0;
if (lPos.x > 1.0) return 1.0;
if (lPos.y > 1.0) return 1.0;
#endif
#ifdef _PCSS
return PCSS(lPos.xy, lPos.z - shadowsBias);
#else

View file

@ -778,7 +778,7 @@ class ArmoryExporter:
if (action):
for fcurve in action.fcurves:
kind = ArmoryExporter.classify_animation_curve(fcurve)
if (kind != kAnimationSampled):
if kind != kAnimationSampled:
if (fcurve.data_path == "location"):
for i in range(3):
if ((fcurve.array_index == i) and (not locAnimCurve[i])):
@ -786,35 +786,35 @@ class ArmoryExporter:
locAnimKind[i] = kind
if (ArmoryExporter.animation_present(fcurve, kind)):
locAnimated[i] = True
elif (fcurve.data_path == "delta_location"):
elif fcurve.data_path == "delta_location":
for i in range(3):
if ((fcurve.array_index == i) and (not deltaPosAnimCurve[i])):
deltaPosAnimCurve[i] = fcurve
deltaPosAnimKind[i] = kind
if (ArmoryExporter.animation_present(fcurve, kind)):
deltaPosAnimated[i] = True
elif (fcurve.data_path == "rotation_euler"):
elif fcurve.data_path == "rotation_euler":
for i in range(3):
if ((fcurve.array_index == i) and (not rotAnimCurve[i])):
rotAnimCurve[i] = fcurve
rotAnimKind[i] = kind
if (ArmoryExporter.animation_present(fcurve, kind)):
rotAnimated[i] = True
elif (fcurve.data_path == "delta_rotation_euler"):
elif fcurve.data_path == "delta_rotation_euler":
for i in range(3):
if ((fcurve.array_index == i) and (not deltaRotAnimCurve[i])):
deltaRotAnimCurve[i] = fcurve
deltaRotAnimKind[i] = kind
if (ArmoryExporter.animation_present(fcurve, kind)):
deltaRotAnimated[i] = True
elif (fcurve.data_path == "scale"):
elif fcurve.data_path == "scale":
for i in range(3):
if ((fcurve.array_index == i) and (not sclAnimCurve[i])):
sclAnimCurve[i] = fcurve
sclAnimKind[i] = kind
if (ArmoryExporter.animation_present(fcurve, kind)):
sclAnimated[i] = True
elif (fcurve.data_path == "delta_scale"):
elif fcurve.data_path == "delta_scale":
for i in range(3):
if ((fcurve.array_index == i) and (not deltaSclAnimCurve[i])):
deltaSclAnimCurve[i] = fcurve
@ -846,7 +846,7 @@ class ArmoryExporter:
o['transform']['values'] = self.write_matrix(bobject.matrix_local)
if (sampledAnimation):
if sampledAnimation:
self.export_object_sampled_animation(bobject, scene, o)
else:
structFlag = False
@ -857,7 +857,7 @@ class ArmoryExporter:
o['animation_transforms'] = []
deltaTranslation = bobject.delta_location
if (deltaPositionAnimated):
if deltaPositionAnimated:
# When the delta location is animated, write the x, y, and z components separately
# so they can be targeted by different tracks having different sets of keys.
for i in range(3):
@ -888,7 +888,7 @@ class ArmoryExporter:
structFlag = True
translation = bobject.location
if (locationAnimated):
if locationAnimated:
# When the location is animated, write the x, y, and z components separately
# so they can be targeted by different tracks having different sets of keys.
for i in range(3):
@ -908,7 +908,7 @@ class ArmoryExporter:
animo['values'] = self.write_vector3d(translation)
structFlag = True
if (deltaRotationAnimated):
if deltaRotationAnimated:
# When the delta rotation is animated, write three separate Euler angle rotations
# so they can be targeted by different tracks having different sets of keys.
for i in range(3):
@ -925,7 +925,7 @@ class ArmoryExporter:
else:
# When the delta rotation is not animated, write it in the representation given by
# the object's current rotation mode. (There is no axis-angle delta rotation.)
if (mode == "QUATERNION"):
if mode == "QUATERNION":
quaternion = bobject.delta_rotation_quaternion
if ((math.fabs(quaternion[0] - 1.0) > kExportEpsilon) or (math.fabs(quaternion[1]) > kExportEpsilon) or (math.fabs(quaternion[2]) > kExportEpsilon) or (math.fabs(quaternion[3]) > kExportEpsilon)):
animo = {}
@ -945,7 +945,7 @@ class ArmoryExporter:
animo['value'] = angle
structFlag = True
if (rotationAnimated):
if rotationAnimated:
# When the rotation is animated, write three separate Euler angle rotations
# so they can be targeted by different tracks having different sets of keys.
for i in range(3):
@ -1182,6 +1182,31 @@ class ArmoryExporter:
return space.region_3d.perspective_matrix
return None
def make_fake_omni_lamps(self, o, bobject):
# Look down
o['transform']['values'] = [1.0, 0.0, 0.0, bobject.location.x, 0.0, 1.0, 0.0, bobject.location.y, 0.0, 0.0, 1.0, bobject.location.z, 0.0, 0.0, 0.0, 1.0]
if not hasattr(o, 'children'):
o['children'] = []
# Make child lamps
for i in range(0, 5):
child_lamp = {}
child_lamp['name'] = o['name'] + '__' + str(i)
child_lamp['data_ref'] = o['data_ref']
child_lamp['type'] = 'lamp_object'
if i == 0:
mat = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
elif i == 1:
mat = [0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
elif i == 2:
mat = [0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
elif i == 3:
mat = [0.0, -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
elif i == 4:
mat = [-1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0]
child_lamp['transform'] = {}
child_lamp['transform']['values'] = mat
o['children'].append(child_lamp)
def export_object(self, bobject, scene, poseBone = None, parento = None):
# This function exports a single object in the scene and includes its name,
# object reference, material references (for meshes), and transform.
@ -1190,7 +1215,7 @@ class ArmoryExporter:
return
bobjectRef = self.bobjectArray.get(bobject)
if (bobjectRef):
if bobjectRef:
type = bobjectRef["objectType"]
o = {}
@ -1218,8 +1243,8 @@ class ArmoryExporter:
# Export the object reference and material references.
objref = bobject.data
if (type == kNodeTypeMesh):
if (not objref in self.meshArray):
if type == kNodeTypeMesh:
if not objref in self.meshArray:
self.meshArray[objref] = {"structName" : objref.name, "objectTable" : [bobject]}
else:
self.meshArray[objref]["objectTable"].append(bobject)
@ -1257,28 +1282,28 @@ class ArmoryExporter:
# self.ExportMorphWeights(bobject, shapeKeys, scene, o)
# TODO
elif (type == kNodeTypeLamp):
if (not objref in self.lampArray):
elif type == kNodeTypeLamp:
if not objref in self.lampArray:
self.lampArray[objref] = {"structName" : objref.name, "objectTable" : [bobject]}
else:
self.lampArray[objref]["objectTable"].append(bobject)
o['data_ref'] = self.lampArray[objref]["structName"]
elif (type == kNodeTypeCamera):
if (not objref in self.cameraArray):
elif type == kNodeTypeCamera:
if not objref in self.cameraArray:
self.cameraArray[objref] = {"structName" : objref.name, "objectTable" : [bobject]}
else:
self.cameraArray[objref]["objectTable"].append(bobject)
o['data_ref'] = self.cameraArray[objref]["structName"]
elif (type == kNodeTypeSpeaker):
if (not objref in self.speakerArray):
elif type == kNodeTypeSpeaker:
if not objref in self.speakerArray:
self.speakerArray[objref] = {"structName" : objref.name, "objectTable" : [bobject]}
else:
self.speakerArray[objref]["objectTable"].append(bobject)
o['data_ref'] = self.speakerArray[objref]["structName"]
if (poseBone):
if poseBone:
# If the object is parented to a bone and is not relative, then undo the bone's transform
o['transform'] = {}
o['transform']['values'] = self.write_matrix(poseBone.matrix.inverted())
@ -1286,6 +1311,10 @@ class ArmoryExporter:
# Export the transform. If object is animated, then animation tracks are exported here
self.export_object_transform(bobject, scene, o)
# 6 directional lamps
if type == kNodeTypeLamp and objref.lamp_omni_shadows:
self.make_fake_omni_lamps(o, bobject)
# Viewport Camera - overwrite active camera matrix with viewport matrix
if type == kNodeTypeCamera and bpy.data.worlds['Arm'].arm_play_viewport_camera and self.scene.camera != None and bobject.name == self.scene.camera.name:
viewport_matrix = self.get_viewport_view_matrix()
@ -1336,7 +1365,7 @@ class ArmoryExporter:
armutils.write_arm(fp, bones_obj)
armdata.data_cached = True
if (parento == None):
if parento == None:
self.output['objects'].append(o)
else:
parento['children'].append(o)
@ -1943,6 +1972,12 @@ class ArmoryExporter:
# Parse nodes
make_material.parse_lamp(objref.node_tree, o)
# Fake omni shadows
if objref.lamp_omni_shadows:
o['fov'] = 1.57
o['strength'] /= 6
self.output['lamp_datas'].append(o)
def export_camera(self, objectRef):

View file

@ -74,7 +74,7 @@ def make_set_target(stage, node_group, node, currentNode=None, target_index=1, v
currentNode = nodes.find_node_by_link(node_group, currentNode, currentNode.inputs[target_index])
if currentNode.bl_idname == 'TargetNodeType':
if currentNode.bl_idname == 'TargetNodeType' or currentNode.bl_idname == 'ShadowMapNodeType':
targetId = currentNode.inputs[0].default_value
stage['params'].append(targetId)
# Store current target size
@ -172,7 +172,10 @@ def make_bind_target(stage, node_group, node, constant_name, currentNode=None, t
stage['params'].append(targetId)
stage['params'].append(constant_name)
elif currentNode.bl_idname == 'ShadowMapNodeType':
targetId = currentNode.inputs[0].default_value
stage['params'].append(targetId)
stage['params'].append(constant_name)
elif currentNode.bl_idname == 'DepthBufferNodeType':
targetId = '_' + currentNode.inputs[0].default_value
@ -758,7 +761,7 @@ def parse_render_target(node, node_group, render_targets, depth_buffers):
tnode = nodes.find_node_by_link(node_group, node, node.inputs[0])
parse_render_target(tnode, node_group, render_targets, depth_buffers)
elif node.bl_idname == 'TargetNodeType':
elif node.bl_idname == 'TargetNodeType' or node.bl_idname == 'ShadowMapNodeType':
# Target already exists
id = node.inputs[0].default_value
for t in render_targets:
@ -766,7 +769,7 @@ def parse_render_target(node, node_group, render_targets, depth_buffers):
return
depth_buffer_id = None
if node.inputs[3].is_linked:
if node.bl_idname == 'TargetNodeType' and node.inputs[3].is_linked:
# Find depth buffer
depth_node = nodes.find_node_by_link(node_group, node, node.inputs[3])
depth_buffer_id = depth_node.inputs[0].default_value
@ -790,8 +793,23 @@ def parse_render_target(node, node_group, render_targets, depth_buffers):
scale = size_node.inputs[0].default_value
# Append target
target = make_render_target(node, scale, depth_buffer_id=depth_buffer_id)
render_targets.append(target)
if node.bl_idname == 'TargetNodeType':
target = make_render_target(node, scale, depth_buffer_id=depth_buffer_id)
render_targets.append(target)
else: # ShadowMapNodeType
target = make_shadowmap_target(node, scale)
render_targets.append(target)
# Second shadowmap for point lamps
# TODO: check if lamp users are visible
for lamp in bpy.data.lamps:
if lamp.type == 'POINT':
# target = make_shadowmap_target(node, scale, '2')
# render_targets.append(target)
# break
# Clamp omni-shadows, remove
if lamp.lamp_omni_shadows:
bpy.data.worlds['Arm'].world_defs += '_Clampstc'
elif node.bl_idname == 'ImageNodeType' or node.bl_idname == 'Image3DNodeType':
# Target already exists
@ -834,6 +852,17 @@ def make_render_target(n, scale, depth_buffer_id=None):
target['depth_buffer'] = depth_buffer_id
return target
def make_shadowmap_target(n, scale, postfix=''):
target = {}
# target['name'] = '_shadow_' + n.inputs[0].default_value + postfix
target['name'] = n.inputs[0].default_value + postfix
target['width'] = n.inputs[1].default_value
target['height'] = n.inputs[2].default_value
target['format'] = n.inputs[3].default_value
if scale != 1.0:
target['scale'] = scale
return target
def make_image_target(n, scale):
target = {}
target['is_image'] = True

View file

@ -457,6 +457,20 @@ class TargetNode(Node, CGPipelineTreeNode):
self.outputs.new('NodeSocketShader', "Target")
class ShadowMapNode(Node, CGPipelineTreeNode):
'''Create new shadow map target node'''
bl_idname = 'ShadowMapNodeType'
bl_label = 'Shadow Map'
bl_icon = 'SOUND'
def init(self, context):
self.inputs.new('NodeSocketString', "ID")
self.inputs.new('NodeSocketInt', "Width")
self.inputs.new('NodeSocketInt', "Height")
self.inputs.new('NodeSocketString', "Format")
self.outputs.new('NodeSocketShader', "Target")
class ImageNode(Node, CGPipelineTreeNode):
'''Create new image node'''
bl_idname = 'ImageNodeType'
@ -779,6 +793,7 @@ node_categories = [
]),
MyTargetNodeCategory("TARGETNODES", "Target", items=[
NodeItem("TargetNodeType"),
NodeItem("ShadowMapNodeType"),
NodeItem("ImageNodeType"),
NodeItem("Image3DNodeType"),
NodeItem("TargetArrayNodeType"),

View file

@ -260,6 +260,7 @@ def init_properties():
bpy.types.Lamp.lamp_clip_end = bpy.props.FloatProperty(name="Clip End", default=50.0)
bpy.types.Lamp.lamp_fov = bpy.props.FloatProperty(name="Field of View", default=0.84)
bpy.types.Lamp.lamp_shadows_bias = bpy.props.FloatProperty(name="Shadows Bias", description="Depth offset for shadow acne", default=0.0002)
bpy.types.Lamp.lamp_omni_shadows = bpy.props.BoolProperty(name="Omnidirectional Shadows", description="Fakes omnidirectional shadows by creating 6 directional lights. Will result in preformance loss. Usable for deferred renderers only.", default=False)
if not 'Arm' in bpy.data.worlds:
wrd = bpy.data.worlds.new('Arm')

View file

@ -163,6 +163,10 @@ class DataPropsPanel(bpy.types.Panel):
layout.prop(obj.data, 'lamp_clip_end')
layout.prop(obj.data, 'lamp_fov')
layout.prop(obj.data, 'lamp_shadows_bias')
layout.prop(obj.data, 'lamp_omni_shadows')
if obj.data.lamp_omni_shadows:
layout.label('Warning: Will result in performance loss.')
layout.label('Temporary implementation.')
elif obj.type == 'SPEAKER':
layout.prop(obj.data, 'loop')
layout.prop(obj.data, 'stream')