Voxel cone tracing.

This commit is contained in:
Lubos Lenco 2016-10-09 16:06:18 +02:00
parent ddb83de3b8
commit 0bbd0a59a3
31 changed files with 1312 additions and 592 deletions

View file

@ -52,7 +52,7 @@ class FirstPersonController extends CameraController {
if (!body.bodyReady) return;
if (jump) {
body.applyImpulse(new Vec4(0, 0, 15));
body.applyImpulse(new Vec4(0, 0, 16));
jump = false;
}
@ -68,14 +68,14 @@ class FirstPersonController extends CameraController {
body.setLinearVelocity(0.0, 0.0, btvec.z() - 1.0);
if (moveForward || moveBackward || moveLeft || moveRight) {
dir.mult(8);
dir.mult(6);
body.activate();
body.setLinearVelocity(dir.x, dir.y, btvec.z() - 1.0);
}
// Keep vertical
body.setAngularFactor(0, 0, 0);
camera.updateMatrix();
camera.buildMatrix();
}
#end
}

View file

@ -3,7 +3,7 @@ package armory.trait;
import iron.math.Vec4;
import armory.trait.internal.CameraController;
class PlatformerController extends CameraController {
class SidescrollerController extends CameraController {
#if (!WITH_PHYSICS)
public function new() { super(); }
@ -37,15 +37,20 @@ class PlatformerController extends CameraController {
var btvec = body.getLinearVelocity();
body.setLinearVelocity(0.0, 0.0, btvec.z() - 1.0);
if (moveLeft || moveRight) {
dir.mult(-2);
var arm = object.getChild("Ballie");
arm.animation.player.paused = true;
if (moveLeft || moveRight) {
arm.animation.player.paused = false;
arm.animation.player.dir = moveLeft ? -1 : 1;
dir.mult(-4 * 0.7);
body.activate();
body.setLinearVelocity(dir.x, dir.y, btvec.z() - 1.0);
}
// Keep vertical
body.setAngularFactor(0, 0, 0);
camera.updateMatrix();
camera.buildMatrix();
}
#end
}

View file

@ -34,6 +34,7 @@ class ThirdPersonController extends CameraController {
// kha.SystemImpl.lockMouse();
camera.transform.rotate(xVec, Input.deltaY / 250 * rotationSpeed);
transform.rotate(zVec, -Input.deltaX / 250 * rotationSpeed);
camera.buildMatrix();
body.syncTransform();
}
}
@ -62,15 +63,20 @@ class ThirdPersonController extends CameraController {
var btvec = body.getLinearVelocity();
body.setLinearVelocity(0.0, 0.0, btvec.z() - 1.0);
var arm = object.getChild("Ballie");
arm.animation.player.paused = true;
if (moveForward || moveBackward || moveLeft || moveRight) {
dir.mult(-2);
arm.animation.player.paused = false;
arm.animation.player.dir = moveBackward ? -1 : 1;
dir.mult(-4 * 0.7);
body.activate();
body.setLinearVelocity(dir.x, dir.y, btvec.z() - 1.0);
}
// Keep vertical
body.setAngularFactor(0, 0, 0);
camera.updateMatrix();
camera.buildMatrix();
}
#end
}

View file

@ -207,7 +207,7 @@ class VehicleBody extends Trait {
// TODO: fix parent matrix update
if (camera.parent != null) camera.parent.transform.buildMatrix();
camera.updateMatrix();
camera.buildMatrix();
}
function createRigidBody(mass:Float, shape:BtCompoundShapePointer):BtRigidBodyPointer {

View file

@ -157,10 +157,10 @@ class PathTracer extends Trait {
// jitter.multiplyScalar(1 / iron.App.w);
// jitter.multiplyScalar(1 / 400);
var mvp = Mat4.identity();
mvp.mult2(camera.V);
mvp.mult2(camera.P);
mvp.multmat2(camera.V);
mvp.multmat2(camera.P);
var inverse = Mat4.identity();
// jitter.mult2(mvp);
// jitter.multmat2(mvp);
inverse.inverse2(mvp);
var matrix = inverse;

View file

@ -16,9 +16,10 @@ class RigidBody extends Trait {
#else
var shape:Shape;
var _motionState:BtMotionState;
public var physics:PhysicsWorld;
public var transform:Transform;
public var transform:Transform = null;
public var mass:Float;
public var friction:Float;
@ -122,7 +123,7 @@ class RigidBody extends Trait {
var _centerOfMassOffset = BtTransform.create();
_centerOfMassOffset.value.setIdentity();
var _motionState = BtDefaultMotionState.create(_transform.value, _centerOfMassOffset.value);
_motionState = BtDefaultMotionState.create(_transform.value, _centerOfMassOffset.value);
if (!shapeConvexCreated) {
if (shape != Shape.StaticMesh && shape != Shape.Terrain) {
@ -155,13 +156,18 @@ class RigidBody extends Trait {
}
function lateUpdate() {
var trans = body.ptr.getWorldTransform();
var p = trans.getOrigin();
var q = trans.getRotation();
transform.loc.set(p.x(), p.y(), p.z());
transform.rot.set(q.x(), q.y(), q.z(), q.w());
transform.dirty = true;
transform.update();
if (object.animation != null) {
syncTransform();
}
else {
var trans = body.ptr.getWorldTransform();
var p = trans.getOrigin();
var q = trans.getRotation();
transform.loc.set(p.x(), p.y(), p.z());
transform.rot.set(q.x(), q.y(), q.z(), q.w());
transform.dirty = true;
transform.update();
}
}
public function removeFromWorld() {
@ -225,6 +231,9 @@ class RigidBody extends Trait {
trans.value.setOrigin(BtVector3.create(transform.loc.x, transform.loc.y, transform.loc.z).value);
trans.value.setRotation(BtQuaternion.create(transform.rot.x, transform.rot.y, transform.rot.z, transform.rot.w).value);
body.ptr.setCenterOfMassTransform(trans.value);
// _motionState.getWorldTransform(trans);
// trans.setOrigin(BtVector3.create(transform.loc.x, transform.loc.y, transform.loc.z).value);
// _motionState.setWorldTransform(trans);
}
function addPointsToConvexHull(shape:BtConvexHullShapePointer, scale:Vec4, margin:Float) {

Binary file not shown.

View file

@ -2300,19 +2300,32 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
c['bind_textures'] = []
cont = {}
o['contexts'].append(c)
if bpy.data.worlds['Arm'].generate_shadows == True:
c = {}
c['name'] = ArmoryExporter.shadows_context
o['contexts'].append(c)
wrd = bpy.data.worlds['Arm']
if wrd.generate_shadows == True:
c2 = {}
c2['name'] = ArmoryExporter.shadows_context
o['contexts'].append(c2)
if ArmoryExporter.mesh_context_empty != '':
c = {}
c['name'] = ArmoryExporter.mesh_context_empty
o['contexts'].append(c)
if bpy.data.worlds['Arm'].force_no_culling:
c2 = {}
c2['name'] = ArmoryExporter.mesh_context_empty
o['contexts'].append(c2)
if wrd.force_no_culling:
o['override_context'] = {}
o['override_context']['cull_mode'] = 'none'
defs = []
self.finalize_shader(o, defs, ArmoryExporter.renderpath_passes)
# TODO: duplicate
geom_context = None
if wrd.voxelgi:
#defs.append('_VoxelGI')
c2 = {}
c2['name'] = 'voxel'
for bc in c['bind_constants']:
if bc['name'] == 'baseCol':
c2['bind_constants'] = [bc]
break
o['contexts'].append(c2)
geom_context = 'voxel'
self.finalize_shader(o, defs, ArmoryExporter.renderpath_passes, geom_context=geom_context)
self.output['material_datas'].append(o)
def export_particle_systems(self):
@ -2742,6 +2755,8 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
if len(bobject.constraints) > 0:
o['constraints'] = []
for constr in bobject.constraints:
if constr.mute:
continue
co = {}
co['name'] = constr.name
co['type'] = constr.type
@ -2866,7 +2881,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
const['float'] = material.height_tess_outer
c['bind_constants'].append(const)
# Append shadows height context
if bpy.data.worlds['Arm'].generate_shadows == True:
if wrd.generate_shadows == True:
if material.height_tess_shadows:
c2 = {}
c2['name'] = ArmoryExporter.shadows_context + 'height'
@ -2891,25 +2906,40 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
o['contexts'].append(c2)
else:
# Non-tessellated shadow context
c = {}
c['name'] = ArmoryExporter.shadows_context
o['contexts'].append(c)
c2 = {}
c2['name'] = ArmoryExporter.shadows_context
o['contexts'].append(c2)
# X-Ray enabled
elif material.overlay:
# Change to overlay context
c['name'] = ArmoryExporter.overlay_context
# Otherwise add shadows context
else:
if bpy.data.worlds['Arm'].generate_shadows == True:
c = {}
c['name'] = ArmoryExporter.shadows_context
o['contexts'].append(c)
if wrd.generate_shadows == True:
c2 = {}
c2['name'] = ArmoryExporter.shadows_context
o['contexts'].append(c2)
# VGI Voxels enabled, append context
if wrd.voxelgi:
#defs.append('_VoxelGI')
c2 = {}
c2['name'] = 'voxel' # TODO: Hard-coded context name for now
for bc in c['bind_constants']:
if bc['name'] == 'baseCol':
c2['bind_constants'] = [bc]
break
for bt in c['bind_textures']:
if bt['name'] == 'sbase':
c2['bind_textures'] = [bt]
break
o['contexts'].append(c2)
# Additional geometry contexts, useful for depth-prepass
if ArmoryExporter.mesh_context_empty != '':
c = {}
c['name'] = ArmoryExporter.mesh_context_empty
o['contexts'].append(c)
c2 = {}
c2['name'] = ArmoryExporter.mesh_context_empty
o['contexts'].append(c2)
# Material users
for ob in mat_users:
@ -2936,10 +2966,13 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
# Process defs and append datas
if material.override_shader == False:
with_tess = False
geom_context = None
# TODO: auto-detect tessellation shaders
if '_HeightTex' in defs:
with_tess = True
self.finalize_shader(o, defs, ArmoryExporter.renderpath_passes, with_tess=with_tess)
if wrd.voxelgi:
geom_context = 'voxel'
self.finalize_shader(o, defs, ArmoryExporter.renderpath_passes, with_tess=with_tess, geom_context=geom_context)
else:
# TODO: gather defs from vertex data when custom shader is used
o['shader'] = material.override_shader_name
@ -3124,7 +3157,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
po['volume_center'] = volume_center
return po
def finalize_shader(self, o, defs, renderpath_passes, with_tess=False, with_geom=False):
def finalize_shader(self, o, defs, renderpath_passes, with_tess=False, geom_context=None):
# Merge duplicates and sort
defs = sorted(list(set(defs)))
# Select correct shader variant
@ -3171,7 +3204,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
full_name = 'build/compiled/Shaders/' + ArmoryExporter.renderpath_id + '/' + shader_name
assets.add_shader(full_name + '.vert.glsl')
assets.add_shader(full_name + '.frag.glsl')
if with_geom:
if geom_context == ren_pass:
assets.add_shader(full_name + '.geom.glsl')
if with_tess:
assets.add_shader(full_name + '.tesc.glsl')

View file

@ -175,17 +175,27 @@ def parse_shader(sres, c, con, defs, lines, parse_attributes):
if line.startswith('uniform '):
s = line.split(' ')
ctype = s[1]
cid = s[2][:-1]
# uniform sampler2D myname;
# uniform layout(RGBA8) image3D myname;
if s[1].startswith('layout'):
ctype = s[2]
cid = s[3][:-1]
else:
ctype = s[1]
cid = s[2][:-1]
found = False # Unique check
if ctype == 'sampler2D' or ctype == 'sampler2DShadow': # Texture unit
for tu in con['texture_units']:
if ctype == 'sampler2D' or ctype == 'sampler2DShadow' or ctype == 'sampler3D' or ctype == 'image2D' or ctype == 'image3D': # Texture unit
for tu in con['texture_units']: # Texture already present
if tu['name'] == cid:
found = True
break
if found == False:
tu = {}
tu['name'] = cid
# sampler2D / image2D
if ctype == 'image2D' or ctype == 'image3D':
tu['is_image'] = True
# Check for link
for l in c['links']:
if l['name'] == cid:

View file

@ -84,7 +84,7 @@ def def_strings_to_array(strdefs):
defs = ['_' + d for d in defs] # Restore _
return defs
def export_data(fp, sdk_path, is_play=False):
def export_data(fp, sdk_path, is_play=False, is_publish=False):
raw_path = sdk_path + 'armory/raw/'
assets_path = sdk_path + 'armory/Assets/'
export_physics = bpy.data.worlds['Arm'].ArmPhysics != 'Disabled'
@ -151,7 +151,7 @@ def export_data(fp, sdk_path, is_play=False):
write_data.write_compiledglsl()
# Write khafile.js
write_data.write_khafilejs(is_play, export_physics)
write_data.write_khafilejs(is_play, export_physics, dce_full=is_publish)
# Write Main.hx
write_data.write_main(is_play, play_project.in_viewport)
@ -215,6 +215,10 @@ def compile_project(target_name=None, is_publish=False, watch=False):
cmd.append('--ffmpeg')
cmd.append('"' + ffmpeg_path + '"')
if utils.get_os() == 'win': # OpenGL for now
cmd.append('-g')
cmd.append('opengl2')
# armory_log("Building, see console...")
if make.play_project.chromium_running:
@ -244,7 +248,7 @@ def patch_project():
os.chdir(fp)
export_data(fp, sdk_path, is_play=True)
def build_project(is_play=False):
def build_project(is_play=False, is_publish=False):
# Clear flag
play_project.in_viewport = False
@ -310,7 +314,7 @@ def build_project(is_play=False):
# Save internal assets
# Export data
export_data(fp, sdk_path, is_play=is_play)
export_data(fp, sdk_path, is_play=is_play, is_publish=is_publish)
if play_project.playproc == None:
armory_progress(50)
@ -367,8 +371,10 @@ def play_project(self, in_viewport):
wrd = bpy.data.worlds['Arm']
if wrd.ArmPlayRuntime == 'Native':
compile_project(target_name='--run')
if in_viewport == False and wrd.ArmPlayRuntime == 'Native':
play_project.compileproc = compile_project(target_name='--run')
mode = 'play'
threading.Timer(0.1, watch_compile, [mode]).start()
else: # Electron, Browser
if in_viewport == False:
# Windowed player
@ -513,7 +519,7 @@ def publish_project():
minimize = bpy.data.worlds['Arm'].ArmMinimize
bpy.data.worlds['Arm'].ArmMinimize = True
clean_project()
build_project()
build_project(is_publish=True)
play_project.compileproc = compile_project(target_name=bpy.data.worlds['Arm'].ArmPublishTarget, is_publish=True)
threading.Timer(0.1, watch_compile, ['publish']).start()
bpy.data.worlds['Arm'].ArmMinimize = minimize

View file

@ -457,27 +457,29 @@ def parse_pbr_group(self, material, c, defs, tree, node, factor):
parse_base_color_socket(self, base_color_input, material, c, defs, tree, node, factor)
# Occlusion Map
occlusion_input = node.inputs[1]
# occlusion_strength_input = node.inputs[2]
# occlusion_strength = occlusion_strength_input.default_value
parse_occlusion_socket(self, occlusion_input, material, c, defs, tree, node, factor)
# Roughness Map
roughness_input = node.inputs[2]
roughness_input = node.inputs[3]
parse_roughness_socket(self, roughness_input, material, c, defs, tree, node, factor)
roughness_strength_input = node.inputs[3]
roughness_strength_input = node.inputs[4]
roughness_strength = roughness_strength_input.default_value
if roughness_strength != 1.0:
add_roughness_strength(self, c, defs, roughness_strength)
# Metalness Map
metalness_input = node.inputs[4]
metalness_input = node.inputs[5]
parse_metalness_socket(self, metalness_input, material, c, defs, tree, node, factor)
# Normal Map
normal_map_input = node.inputs[5]
normal_map_input = node.inputs[6]
parse_normal_map_socket(self, normal_map_input, material, c, defs, tree, node, factor)
normal_strength_input = node.inputs[6]
normal_strength_input = node.inputs[7]
normal_strength = normal_strength_input.default_value
if normal_strength != 1.0:
add_normal_strength(self, c, defs, normal_strength)
# Emission
emission_input = node.inputs[7]
emission_strength_input = node.inputs[8]
emission_input = node.inputs[8]
emission_strength_input = node.inputs[9]
emission_strength = emission_strength_input.default_value
if emission_strength != 1.0: # Just multiply base color for now
if parse.const_color == None:
@ -488,16 +490,16 @@ def parse_pbr_group(self, material, c, defs, tree, node, factor):
col[2] *= emission_strength
parse.const_color['vec4'] = [col[0], col[1], col[2], col[3]]
# Height Map
height_input = node.inputs[9]
height_input = node.inputs[10]
parse_height_socket(self, height_input, material, c, defs, tree, node, factor)
# Height Strength
if height_input.is_linked:
height_strength_input = node.inputs[10]
height_strength_input = node.inputs[11]
add_height_strength(self, c, height_strength_input.default_value)
# Opacity
opacity_input = node.inputs[11]
opacity_input = node.inputs[12]
opacity = opacity_input.default_value
opacity_strength_input = node.inputs[12]
opacity_strength_input = node.inputs[13]
opacity_strength = opacity_strength_input.default_value
opacity_val = opacity * opacity_strength
if opacity_val != 1.0:
@ -510,4 +512,3 @@ def parse_pbr_group(self, material, c, defs, tree, node, factor):
parse.const_color['vec4'] = [col[0], col[1], col[2], opacity_val]
# Append translucent
defs.append('_Translucent')
ior_input = node.inputs[13]

View file

@ -133,6 +133,15 @@ def make_clear_target(stage, color_val=None, depth_val=None, stencil_val=None):
stage['params'].append('stencil')
stage['params'].append(str(stencil_val))
def make_generate_mipmaps(stage, node_group, node):
stage['command'] = 'generate_mipmaps'
# TODO: support reroutes
link = findLink(node_group, node, node.inputs[1])
targetNode = link.from_node
stage['params'].append(targetNode.inputs[0].default_value)
def make_draw_meshes(stage, node_group, node):
stage['command'] = 'draw_meshes'
# Context
@ -177,10 +186,12 @@ def make_bind_target(stage, node_group, node, constant_name, currentNode=None, t
stage['params'].append(targetId) # Color buffer
stage['params'].append(constant_name + str(i))
elif currentNode.bl_idname == 'TargetNodeType':
elif currentNode.bl_idname == 'TargetNodeType' or currentNode.bl_idname == 'ImageNodeType' or currentNode.bl_idname == 'Image3DNodeType':
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
@ -448,6 +459,8 @@ def make_volumetric_light_pass(stages, node_group, node):
def make_deferred_indirect_pass(stages, node_group, node):
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2, 3], bind_target_constants=['gbuffer', 'ssaotex'], shader_context='deferred_indirect/deferred_indirect/deferred_indirect')
# Testing voxels
# make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2, 3, 4], bind_target_constants=['gbuffer', 'ssaotex', 'voxels'], shader_context='deferred_indirect/deferred_indirect/deferred_indirect')
def make_translucent_resolve_pass(stages, node_group, node):
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2], bind_target_constants=['gbuffer'], shader_context='translucent_resolve/translucent_resolve/translucent_resolve')
@ -480,7 +493,10 @@ def buildNode(stages, node, node_group):
if node.inputs[5].default_value == True:
stencil_val = node.inputs[6].default_value
make_clear_target(stage, color_val=color_val, depth_val=depth_val, stencil_val=stencil_val)
elif node.bl_idname == 'GenerateMipmapsNodeType':
make_generate_mipmaps(stage, node_group, node)
elif node.bl_idname == 'DrawMeshesNodeType':
make_draw_meshes(stage, node_group, node)
@ -700,6 +716,7 @@ def get_root_node(node_group):
def preprocess_renderpath(root_node, node_group):
render_targets = []
render_targets3D = []
depth_buffers = []
preprocess_renderpath.velocity_def_added = False
buildNodeTree.cam.renderpath_passes = ''
@ -734,11 +751,11 @@ def traverse_renderpath(node, node_group, render_targets, depth_buffers):
bpy.data.worlds['Arm'].world_defs += '_VR'
# Collect render targets
if node.bl_idname == 'SetTargetNodeType' or node.bl_idname == 'QuadPassNodeType' or node.bl_idname == 'DrawCompositorNodeType' or node.bl_idname == 'DrawCompositorWithFXAANodeType':
if node.bl_idname == 'SetTargetNodeType' or node.bl_idname == 'BindTargetNodeType' or node.bl_idname == 'QuadPassNodeType' or node.bl_idname == 'DrawCompositorNodeType' or node.bl_idname == 'DrawCompositorWithFXAANodeType':
if node.inputs[1].is_linked:
tnode = findNodeByLink(node_group, node, node.inputs[1])
parse_render_target(tnode, node_group, render_targets, depth_buffers)
# Traverse loops
elif node.bl_idname == 'LoopStagesNodeType' or node.bl_idname == 'LoopLampsNodeType' or node.bl_idname == 'DrawStereoNodeType':
if node.outputs[1].is_linked:
@ -805,7 +822,28 @@ def parse_render_target(node, node_group, render_targets, depth_buffers):
# Append target
target = make_render_target(node, scale, depth_buffer_id=depth_buffer_id)
render_targets.append(target)
elif node.bl_idname == 'ImageNodeType' or node.bl_idname == 'Image3DNodeType':
# Target already exists
id = node.inputs[0].default_value
for t in render_targets:
if t['name'] == id:
return
# Get scale
scale = 1.0
if node.inputs[1].is_linked:
size_node = findNodeByLink(node_group, node, node.inputs[1])
while size_node.bl_idname == 'NodeReroute': # Step through reroutes
size_node = findNodeByLink(node_group, size_node, size_node.inputs[0])
scale = size_node.inputs[0].default_value
if node.bl_idname == 'ImageNodeType':
target = make_image_target(node, scale)
else:
target = make_image3d_target(node, scale)
render_targets.append(target)
elif node.bl_idname == 'GBufferNodeType':
for i in range(0, 5):
if node.inputs[i].is_linked:
@ -825,3 +863,26 @@ def make_render_target(n, scale, depth_buffer_id=None):
if depth_buffer_id != None:
target['depth_buffer'] = depth_buffer_id
return target
def make_image_target(n, scale):
target = {}
target['is_image'] = True
target['name'] = n.inputs[0].default_value
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_image3d_target(n, scale):
target = {}
target['is_image'] = True
target['name'] = n.inputs[0].default_value
target['width'] = n.inputs[1].default_value
target['height'] = n.inputs[2].default_value
target['depth'] = n.inputs[3].default_value
target['format'] = n.inputs[4].default_value
if scale != 1.0:
target['scale'] = scale
return target

View file

@ -76,9 +76,14 @@ def buildNodeTree(world):
assets.add(sdk_path + 'armory/Assets/noise64.png')
assets.add_embedded_data('noise64.png')
# Alternative models
if wrd.diffuse_oren_nayar:
wrd.world_defs += '_OrenNayar'
if wrd.voxelgi:
wrd.world_defs += '_VoxelGI'
wrd.world_defs += '_Rad' # Always do radiance for voxels
# Enable probes
for cam in bpy.data.cameras:
if cam.is_probe:

View file

@ -316,6 +316,8 @@ class DeferredIndirectPassNode(Node, CGPipelineTreeNode):
self.inputs.new('NodeSocketShader', "Target")
self.inputs.new('NodeSocketShader', "GBuffer")
self.inputs.new('NodeSocketShader', "SSAO")
# Testing voxels
# self.inputs.new('NodeSocketShader', "Voxels")
self.outputs.new('NodeSocketShader', "Stage")
@ -394,6 +396,18 @@ class ClearTargetNode(Node, CGPipelineTreeNode):
self.outputs.new('NodeSocketShader', "Stage")
class GenerateMipmapsNode(Node, CGPipelineTreeNode):
'''Generate mipmaps node'''
bl_idname = 'GenerateMipmapsNodeType'
bl_label = 'Generate Mipmaps'
bl_icon = 'SOUND'
def init(self, context):
self.inputs.new('NodeSocketShader', "Stage")
self.inputs.new('NodeSocketShader', "Target")
self.outputs.new('NodeSocketShader', "Stage")
class BeginNode(Node, CGPipelineTreeNode):
'''Start render path node'''
bl_idname = 'BeginNodeType'
@ -421,7 +435,20 @@ class SetTargetNode(Node, CGPipelineTreeNode):
self.inputs.new('NodeSocketShader', "Target")
self.outputs.new('NodeSocketShader', "Stage")
class SetViewportNode(Node, CGPipelineTreeNode):
'''Set viewport size node'''
bl_idname = 'SetViewportNodeType'
bl_label = 'Set Viewport'
bl_icon = 'SOUND'
def init(self, context):
self.inputs.new('NodeSocketShader', "Stage")
self.inputs.new('NodeSocketInt', "Width")
self.inputs.new('NodeSocketInt', "Height")
self.outputs.new('NodeSocketShader', "Stage")
class TargetNode(Node, CGPipelineTreeNode):
'''Create new render target node'''
bl_idname = 'TargetNodeType'
@ -438,6 +465,35 @@ class TargetNode(Node, CGPipelineTreeNode):
self.outputs.new('NodeSocketShader', "Target")
class ImageNode(Node, CGPipelineTreeNode):
'''Create new image node'''
bl_idname = 'ImageNodeType'
bl_label = 'Image'
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 Image3DNode(Node, CGPipelineTreeNode):
'''Create new 3D image node'''
bl_idname = 'Image3DNodeType'
bl_label = 'Image 3D'
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('NodeSocketInt', "Depth")
self.inputs.new('NodeSocketString', "Format")
self.outputs.new('NodeSocketShader', "Target")
class TargetArrayNode(Node, CGPipelineTreeNode):
'''Create target array node'''
bl_idname = 'TargetArrayNodeType'
@ -718,7 +774,9 @@ node_categories = [
NodeItem("DrawMeshesNodeType"),
NodeItem("DrawDecalsNodeType"),
NodeItem("ClearTargetNodeType"),
NodeItem("GenerateMipmapsNodeType"),
NodeItem("SetTargetNodeType"),
NodeItem("SetViewportNodeType"),
NodeItem("BindTargetNodeType"),
NodeItem("DrawMaterialQuadNodeType"),
NodeItem("DrawQuadNodeType"),
@ -729,6 +787,8 @@ node_categories = [
]),
MyTargetNodeCategory("TARGETNODES", "Target", items=[
NodeItem("TargetNodeType"),
NodeItem("ImageNodeType"),
NodeItem("Image3DNodeType"),
NodeItem("TargetArrayNodeType"),
NodeItem("DepthBufferNodeType"),
NodeItem("GBufferNodeType"),

View file

@ -130,6 +130,9 @@ def on_scene_update_post(context):
# Or switch to armory space
elif utils.with_chromium() and make.play_project.in_viewport:
make.play_project.play_area.type = 'VIEW_GAME'
# Prevent immediate operator patch
if len(ops) > 0:
on_scene_update_post.last_operator = ops[-1]
edit_obj = bpy.context.edit_object
if edit_obj != None and edit_obj.is_updated_data:
@ -219,7 +222,8 @@ def initProperties():
bpy.types.World.ArmPlayDeveloperTools = BoolProperty(name="Developer Tools", description="Show chromium developer tools in player", default=False)
bpy.types.World.ArmPlayRuntime = EnumProperty(
items=[('Electron', 'Electron', 'Electron'),
('Browser', 'Browser', 'Browser')],
('Browser', 'Browser', 'Browser'),
('Native', 'Native', 'Native')],
name="Runtime", description="Player runtime used when launching in new window", default='Electron')
# For object
@ -364,6 +368,7 @@ def initProperties():
bpy.types.World.npot_texture_repeat = bpy.props.BoolProperty(name="NPoT Texture Repeat", description="Enable texture repeat mode for non-power of two textures", default=False)
# Lighting flags
bpy.types.World.diffuse_oren_nayar = bpy.props.BoolProperty(name="Oren Nayar Diffuse", default=False, update=invalidate_shader_cache)
bpy.types.World.voxelgi = bpy.props.BoolProperty(name="VGI", description="Voxel-based Global Illumination", default=False, update=invalidate_shader_cache)
# For material
bpy.types.Material.receive_shadow = bpy.props.BoolProperty(name="Receive Shadow", default=True)
bpy.types.Material.override_shader = bpy.props.BoolProperty(name="Override Shader", default=False)
@ -772,6 +777,7 @@ class WorldPropsPanel(bpy.types.Panel):
layout.prop(wrd, 'force_anisotropic_filtering')
layout.prop(wrd, 'npot_texture_repeat')
layout.prop(wrd, 'diffuse_oren_nayar')
layout.prop(wrd, 'voxelgi')
# Menu in render region
class ArmoryPlayPanel(bpy.types.Panel):

View file

@ -7,7 +7,7 @@ def add_armory_library(sdk_path, name):
return ('project.addLibrary("../' + bpy.path.relpath(sdk_path + '/' + name)[2:] + '");\n').replace('\\', '/')
# Write khafile.js
def write_khafilejs(is_play, export_physics):
def write_khafilejs(is_play, export_physics, dce_full=False):
sdk_path = utils.get_sdk_path()
@ -22,7 +22,6 @@ def write_khafilejs(is_play, export_physics):
let project = new Project('""" + bpy.data.worlds['Arm'].ArmProjectName + """');
project.addSources('Sources');
project.addShaders('Sources/Shaders/**');
""")
f.write(add_armory_library(sdk_path, 'armory'))
@ -32,6 +31,9 @@ project.addShaders('Sources/Shaders/**');
f.write("project.addDefine('WITH_PHYSICS');\n")
f.write(add_armory_library(sdk_path + '/lib/', 'haxebullet'))
if dce_full:
f.write("project.addParameter('-dce full');")
# Electron live patching
# if is_play and bpy.data.worlds['Arm'].ArmPlayLivePatch == True and bpy.data.worlds['Arm'].ArmPlayRuntime == 'Electron':
# f.write("project.addDefine('WITH_PATCH_ELECTRON');\n")

View file

@ -562,6 +562,49 @@
"texture_params": [],
"vertex_shader": "translucent.vert.glsl",
"fragment_shader": "translucent.frag.glsl"
},
{
"name": "voxel",
"params": [
{
"name": "depth_write",
"value": "false"
},
{
"name": "compare_mode",
"value": "always"
},
{
"name": "cull_mode",
"value": "none"
}
],
"links": [
{
"name": "W",
"link": "_worldMatrix"
},
{
"name": "LWVP",
"link": "_lampWorldViewProjectionMatrix"
},
{
"name": "PX",
"link": "_projectionXMatrix"
},
{
"name": "PY",
"link": "_projectionYMatrix"
},
{
"name": "PZ",
"link": "_projectionZMatrix"
}
],
"texture_params": [],
"vertex_shader": "voxel.vert.glsl",
"fragment_shader": "voxel.frag.glsl",
"geometry_shader": "voxel.geom.glsl"
}
]
}

55
raw/deferred/voxel.frag.glsl Executable file
View file

@ -0,0 +1,55 @@
// http://simonstechblog.blogspot.sk/2013/01/implementing-voxel-cone-tracing.html
// http://leifnode.com/2015/05/voxel-cone-traced-global-illumination/
// http://www.seas.upenn.edu/%7Epcozzi/OpenGLInsights/OpenGLInsights-SparseVoxelization.pdf
// https://github.com/Cigg/Voxel-Cone-Tracing
// https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf
#version 450
#extension GL_ARB_shader_image_load_store : enable
in fragData {
#ifdef _Tex
vec2 texuv;
#endif
flat int axis;
vec4 lPos;
} frag;
uniform layout(RGBA8) image3D voxels;
#ifdef _BaseTex
uniform sampler2D sbase;
#endif
uniform vec4 baseCol;
uniform sampler2D shadowMap;
const int voxelDimensions = 512;
void main() {
#ifdef _BaseTex
vec4 matCol = texture(sbase, frag.texuv);
#else
vec4 matCol = baseCol;
#endif
// vec4 lPosH = frag.lPos / frag.lPos.w;
// float distanceFromLight = texture(shadowMap, lPosH.xy).r * 2.0 - 1.0;
// const float shadowsBias = 0.0001;
// float visibility = float(distanceFromLight > lPosH.z - shadowsBias);
float visibility = 1.0;
ivec3 camPos = ivec3(gl_FragCoord.x, gl_FragCoord.y, voxelDimensions * gl_FragCoord.z);
ivec3 texPos;
if (frag.axis == 1) {
texPos.x = voxelDimensions - camPos.z;
texPos.z = camPos.x;
texPos.y = camPos.y;
}
else if (frag.axis == 2) {
texPos.z = camPos.y;
texPos.y = voxelDimensions - camPos.z;
texPos.x = camPos.x;
}
else {
texPos = camPos;
}
texPos.z = voxelDimensions - texPos.z - 1;
imageStore(voxels, texPos, vec4(matCol.rgb * visibility, 1.0));
}

56
raw/deferred/voxel.geom.glsl Executable file
View file

@ -0,0 +1,56 @@
#version 450
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vertData {
#ifdef _Tex
vec2 texuv;
#endif
vec4 lPos;
} vertices[];
out fragData {
#ifdef _Tex
vec2 texuv;
#endif
flat int axis;
vec4 lPos;
} frag;
uniform mat4 PX;
uniform mat4 PY;
uniform mat4 PZ;
void main() {
vec3 p1 = gl_in[1].gl_Position.xyz - gl_in[0].gl_Position.xyz;
vec3 p2 = gl_in[2].gl_Position.xyz - gl_in[0].gl_Position.xyz;
vec3 absnor = abs(normalize(cross(p1, p2)));
mat4 P;
// Dominant axis
if (absnor.x >= absnor.y && absnor.x >= absnor.z) {
frag.axis = 1;
P = PX;
}
else if (absnor.y >= absnor.x && absnor.y >= absnor.z) {
frag.axis = 2;
P = PY;
}
else {
frag.axis = 3;
P = PZ;
}
for (int i = 0; i < gl_in.length(); i++) {
vec3 middlePos = gl_in[0].gl_Position.xyz / 3.0 + gl_in[1].gl_Position.xyz / 3.0 + gl_in[2].gl_Position.xyz / 3.0;
#ifdef _Tex
frag.texuv = vertices[i].texuv;
#endif
frag.lPos = vertices[i].lPos;
gl_Position = P * gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
}

38
raw/deferred/voxel.vert.glsl Executable file
View file

@ -0,0 +1,38 @@
#version 450
in vec3 pos;
// in vec3 nor;
#ifdef _Tex
in vec2 tex;
#endif
#ifdef _VCols
in vec3 col;
#endif
#ifdef _NorTex
in vec3 tan;
#endif
#ifdef _Skinning
in vec4 bone;
in vec4 weight;
#endif
#ifdef _Instancing
in vec3 off;
#endif
uniform mat4 LWVP;
uniform mat4 W;
out vertData {
#ifdef _BaseTex
vec2 texuv;
#endif
vec4 lPos;
} vert;
void main() {
#ifdef _Tex
vert.texuv = tex;
#endif
vert.lPos = LWVP * vec4(pos, 1.0);
gl_Position = W * vec4(pos, 1.0);
}

View file

@ -22,8 +22,6 @@ uniform float envmapStrength;
uniform int envmapNumMipmaps;
#endif
// uniform sampler2D giblur; // Path-traced
#ifdef _SSAO
uniform sampler2D ssaotex;
#endif
@ -171,7 +169,7 @@ void main() {
vec3 p = getPos(depth);
vec3 v = normalize(eye - p.xyz);
#endif
// Indirect
#ifdef _Probes
float probeFactor = g0.a; // mask_probe
@ -225,7 +223,7 @@ void main() {
vec3 f0 = surfaceF0(g1.rgb, metrough.x);
vec2 envBRDF = texture(senvmapBrdf, vec2(metrough.y, 1.0 - dotNV)).xy;
indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y);;
indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y);
#endif
indirect = indirect * envmapStrength;// * lightColor * lightStrength;

View file

@ -36,6 +36,25 @@ uniform sampler2D gbuffer1;
#endif
#endif
#ifdef _VoxelGI
uniform sampler2D ssaotex;
uniform sampler2D senvmapBrdf;
uniform sampler3D voxels;
const float voxelGridWorldSize = 150.0;
const int voxelDimensions = 512;
const float maxDist = 30.0;
const float alphaTreshold = 0.95;
const int numCones = 6;
vec3 coneDirections[6] = vec3[](
vec3(0, 1, 0),
vec3(0, 0.5, 0.866025),
vec3(0.823639, 0.5, 0.267617),
vec3(0.509037, 0.5, -0.700629),
vec3(-0.509037, 0.5, -0.700629),
vec3(-0.823639, 0.5, 0.267617));
float coneWeights[6] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
#endif
// #ifdef _LTC
// uniform sampler2D sltcMat;
// uniform sampler2D sltcMag;
@ -652,6 +671,50 @@ float wardSpecular(vec3 N, vec3 H, float dotNL, float dotNV, float dotNH, vec3 f
// ) * scale;
// }
#ifdef _VoxelGI
vec4 sampleVoxels(vec3 worldPosition, float lod) {
vec3 offset = vec3(1.0 / voxelDimensions, 1.0 / voxelDimensions, 0);
vec3 texco = worldPosition / (voxelGridWorldSize * 0.5);
texco = texco * 0.5 + 0.5 + offset;
return textureLod(voxels, texco, lod);
}
vec4 coneTrace(vec3 posWorld, vec3 direction, vec3 norWorld, float tanHalfAngle, out float occlusion) {
const float voxelWorldSize = voxelGridWorldSize / voxelDimensions;
float dist = voxelWorldSize; // Start one voxel away to avoid self occlusion
vec3 startPos = posWorld + norWorld * voxelWorldSize;
vec3 color = vec3(0.0);
float alpha = 0.0;
occlusion = 0.0;
while (dist < maxDist && alpha < alphaTreshold) {
// Smallest sample diameter possible is the voxel size
float diameter = max(voxelWorldSize, 2.0 * tanHalfAngle * dist);
float lodLevel = log2(diameter / voxelWorldSize);
vec4 voxelColor = sampleVoxels(startPos + dist * direction, lodLevel);
// Front-to-back compositing
float a = (1.0 - alpha);
color += a * voxelColor.rgb;
alpha += a * voxelColor.a;
occlusion += (a * voxelColor.a) / (1.0 + 0.03 * diameter);
dist += diameter * 0.5; // * 2.0
}
return vec4(color, alpha);
}
vec4 indirectLight(vec3 posWorld, mat3 tanToWorld, vec3 norWorld, out float occlusion) {
vec4 color = vec4(0);
occlusion = 0.0;
for (int i = 0; i < numCones; i++) {
float coneOcclusion;
const float tanangle = tan(30):
color += coneWeights[i] * coneTrace(posWorld, tanToWorld * coneDirections[i], norWorld, tanangle, coneOcclusion);
occlusion += coneWeights[i] * coneOcclusion;
}
occlusion = 1.0 - occlusion;
return color;
}
#endif
void main() {
vec2 screenPosition = wvpposition.xy / wvpposition.w;
vec2 texCoord = screenPosition * 0.5 + 0.5;
@ -734,70 +797,40 @@ void main() {
// Direct
outColor = vec4(vec3(direct * visibility), 1.0);
// Indirect
// if (lightIndex == 0) {
// #ifdef _Probes
// float probeFactor = mask;
// float probeID = floor(probeFactor);
// float probeFract = fract(probeFactor);
// vec3 indirect;
// #ifdef _Rad
// float lod = getMipLevelFromRoughness(metrough.y);
// vec3 reflectionWorld = reflect(-v, n);
// vec2 envCoordRefl = envMapEquirect(reflectionWorld);
// vec3 prefilteredColor = textureLod(senvmapRadiance, envCoordRefl, lod).rgb;
// #endif
// // Global probe only
// if (probeID == 0.0) {
// indirect = shIrradiance(n, 2.2, 0) / PI;
// }
// // fract 0 = local probe, 1 = global probe
// else if (probeID == 1.0) {
// indirect = (shIrradiance(n, 2.2, 1) / PI) * (1.0 - probeFract);
// //prefilteredColor /= 4.0;
// if (probeFract > 0.0) {
// indirect += (shIrradiance(n, 2.2, 0) / PI) * (probeFract);
// }
// }
// #else // No probes
// // vec3 indirect = texture(shirr, envMapEquirect(n)).rgb;
// vec3 indirect = shIrradiance(n, 2.2) / PI;
// #ifdef _Rad
// vec3 reflectionWorld = reflect(-v, n);
// float lod = getMipLevelFromRoughness(metrough.y);
// vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
// #endif
// #endif
// Voxels test..
#ifdef _VoxelGI
vec4 g1a = texture(gbuffer1, texCoord); // Basecolor.rgb, occlusion
vec3 albedoa = surfaceAlbedo(g1a.rgb, metrough.x); // g1a.rgb - basecolor
// #ifdef _EnvLDR
// indirect = pow(indirect, vec3(2.2));
// #ifdef _Rad
// prefilteredColor = pow(prefilteredColor, vec3(2.2));
// #endif
// #endif
// indirect *= albedo;
// #ifdef _Rad
// // Indirect specular
// vec2 envBRDF = texture(senvmapBrdf, vec2(metrough.y, 1.0 - dotNV)).xy;
// indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y);;
// #endif
// indirect = indirect * envmapStrength;// * lightColor * lightStrength;
// indirect = indirect * g1.a; // Occlusion
// #ifdef _SSAO
// indirect *= texture(ssaotex, texCoord).r; // SSAO
// #endif
// gl_FragColor.rgb += indirect;
// }
// vec4 outColor = vec4(vec3(direct * visibility + indirect), 1.0);
vec3 tangent = normalize(cross(n, vec3(0.0, 1.0, 0.0)));
if (length(tangent) == 0.0) {
tangent = normalize(cross(n, vec3(0.0, 0.0, 1.0)));
}
vec3 bitangent = normalize(cross(n, tangent));
mat3 tanToWorld = inverse(transpose(mat3(tangent, bitangent, n)));
float diffOcclusion = 0.0;
vec3 indirectDiffusea = indirectLight(p, tanToWorld, n, diffOcclusion).rgb * 4.0;
indirectDiffusea *= albedoa;
diffOcclusion = min(1.0, 1.5 * diffOcclusion);
vec3 reflectWorld = reflect(-v, n);
float specularOcclusion;
float lodOffset = 0.0;//getMipLevelFromRoughness(roughness);
vec3 indirectSpecular = coneTrace(p, reflectWorld, n, 0.07 + lodOffset, specularOcclusion).rgb;
if (metrough.y > 0.0) { // Temp..
float dotNVa = max(dot(n, v), 0.0);
vec3 f0a = surfaceF0(g1a.rgb, metrough.x);
vec2 envBRDFa = texture(senvmapBrdf, vec2(metrough.y, 1.0 - dotNVa)).xy;
indirectSpecular *= (f0a * envBRDFa.x + envBRDFa.y);
}
vec3 indirect1 = indirectDiffusea * diffOcclusion + indirectSpecular;
indirect1 *= texture(ssaotex, texCoord).r;
outColor.rgb += indirect1;
#endif
// Path-traced
// vec4 nois = texture(giblur, texCoord);
// nois.rgb = pow(nois.rgb, vec3(1.0 / 2.2));
// indirect = nois.rgb;
// vec4 outColor = vec4(vec3(direct * visibility + indirect * 3.0 * ao * occlusion), 1.0);
// LTC
// float sinval = (sin(time) * 0.5 + 0.5);

View file

@ -158,6 +158,11 @@
"name": "lampSizeUV",
"link": "_lampSizeUV",
"ifdef": ["_PCSS"]
},
{
"name": "senvmapBrdf",
"link": "_envmapBrdf",
"ifdef": ["_VoxelGI"]
}
],
"vertex_shader": "deferred_light.vert.glsl",

View file

@ -264,6 +264,49 @@
],
"vertex_shader": "shadowmap.vert.glsl",
"fragment_shader": "shadowmap.frag.glsl"
},
{
"name": "voxel",
"params": [
{
"name": "depth_write",
"value": "false"
},
{
"name": "compare_mode",
"value": "always"
},
{
"name": "cull_mode",
"value": "none"
}
],
"links": [
{
"name": "W",
"link": "_worldMatrix"
},
{
"name": "LWVP",
"link": "_lampWorldViewProjectionMatrix"
},
{
"name": "PX",
"link": "_projectionXMatrix"
},
{
"name": "PY",
"link": "_projectionYMatrix"
},
{
"name": "PZ",
"link": "_projectionZMatrix"
}
],
"texture_params": [],
"vertex_shader": "voxel.vert.glsl",
"fragment_shader": "voxel.frag.glsl",
"geometry_shader": "voxel.geom.glsl"
}
]
}

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@ precision highp float;
in vec3 pos;
in vec3 nor;
#ifdef _BaseTex
#ifdef _Tex
in vec2 tex;
#endif
#ifdef _VCols
@ -177,9 +177,8 @@ void main() {
matColor.rgb *= col;
#endif
vec3 mPos = vec4(W * sPos).xyz;
position = mPos;
eyeDir = eye - mPos;
position = vec4(W * sPos).xyz;
eyeDir = eye - position;
#ifdef _NorTex
vec3 tangent = (mat3(N) * (tan));

View file

@ -12,7 +12,7 @@ precision highp float;
in vec3 pos;
in vec3 nor;
#ifdef _BaseTex
#ifdef _Tex
in vec2 tex;
#endif
#ifdef _VCols

View file

@ -12,7 +12,7 @@ precision highp float;
in vec3 pos;
in vec3 nor;
#ifdef _BaseTex
#ifdef _Tex
in vec2 tex;
#endif
#ifdef _VCols

55
raw/forward/voxel.frag.glsl Executable file
View file

@ -0,0 +1,55 @@
// http://simonstechblog.blogspot.sk/2013/01/implementing-voxel-cone-tracing.html
// http://leifnode.com/2015/05/voxel-cone-traced-global-illumination/
// http://www.seas.upenn.edu/%7Epcozzi/OpenGLInsights/OpenGLInsights-SparseVoxelization.pdf
// https://github.com/Cigg/Voxel-Cone-Tracing
// https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf
#version 450
#extension GL_ARB_shader_image_load_store : enable
in fragData {
#ifdef _Tex
vec2 texuv;
#endif
flat int axis;
vec4 lPos;
} frag;
uniform layout(RGBA8) image3D voxels;
#ifdef _BaseTex
uniform sampler2D sbase;
#endif
uniform vec4 baseCol;
uniform sampler2D shadowMap;
const int voxelDimensions = 512;
void main() {
#ifdef _BaseTex
vec4 matCol = texture(sbase, frag.texuv);
#else
vec4 matCol = baseCol;
#endif
// vec4 lPosH = frag.lPos / frag.lPos.w;
// float distanceFromLight = texture(shadowMap, lPosH.xy).r * 2.0 - 1.0;
// const float shadowsBias = 0.0001;
// float visibility = float(distanceFromLight > lPosH.z - shadowsBias);
float visibility = 1.0;
ivec3 camPos = ivec3(gl_FragCoord.x, gl_FragCoord.y, voxelDimensions * gl_FragCoord.z);
ivec3 texPos;
if (frag.axis == 1) {
texPos.x = voxelDimensions - camPos.z;
texPos.z = camPos.x;
texPos.y = camPos.y;
}
else if (frag.axis == 2) {
texPos.z = camPos.y;
texPos.y = voxelDimensions - camPos.z;
texPos.x = camPos.x;
}
else {
texPos = camPos;
}
texPos.z = voxelDimensions - texPos.z - 1;
imageStore(voxels, texPos, vec4(matCol.rgb * visibility, 1.0));
}

56
raw/forward/voxel.geom.glsl Executable file
View file

@ -0,0 +1,56 @@
#version 450
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vertData {
#ifdef _Tex
vec2 texuv;
#endif
vec4 lPos;
} vertices[];
out fragData {
#ifdef _Tex
vec2 texuv;
#endif
flat int axis;
vec4 lPos;
} frag;
uniform mat4 PX;
uniform mat4 PY;
uniform mat4 PZ;
void main() {
vec3 p1 = gl_in[1].gl_Position.xyz - gl_in[0].gl_Position.xyz;
vec3 p2 = gl_in[2].gl_Position.xyz - gl_in[0].gl_Position.xyz;
vec3 absnor = abs(normalize(cross(p1, p2)));
mat4 P;
// Dominant axis
if (absnor.x >= absnor.y && absnor.x >= absnor.z) {
frag.axis = 1;
P = PX;
}
else if (absnor.y >= absnor.x && absnor.y >= absnor.z) {
frag.axis = 2;
P = PY;
}
else {
frag.axis = 3;
P = PZ;
}
for (int i = 0; i < gl_in.length(); i++) {
vec3 middlePos = gl_in[0].gl_Position.xyz / 3.0 + gl_in[1].gl_Position.xyz / 3.0 + gl_in[2].gl_Position.xyz / 3.0;
#ifdef _Tex
frag.texuv = vertices[i].texuv;
#endif
frag.lPos = vertices[i].lPos;
gl_Position = P * gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
}

38
raw/forward/voxel.vert.glsl Executable file
View file

@ -0,0 +1,38 @@
#version 450
in vec3 pos;
// in vec3 nor;
#ifdef _Tex
in vec2 tex;
#endif
#ifdef _VCols
in vec3 col;
#endif
#ifdef _NorTex
in vec3 tan;
#endif
#ifdef _Skinning
in vec4 bone;
in vec4 weight;
#endif
#ifdef _Instancing
in vec3 off;
#endif
uniform mat4 LWVP;
uniform mat4 W;
out vertData {
#ifdef _BaseTex
vec2 texuv;
#endif
vec4 lPos;
} vert;
void main() {
#ifdef _Tex
vert.texuv = tex;
#endif
vert.lPos = LWVP * vec4(pos, 1.0);
gl_Position = W * vec4(pos, 1.0);
}