Voxel cone tracing.
This commit is contained in:
parent
ddb83de3b8
commit
0bbd0a59a3
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
@ -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')
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
55
raw/deferred/voxel.frag.glsl
Executable 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
56
raw/deferred/voxel.geom.glsl
Executable 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
38
raw/deferred/voxel.vert.glsl
Executable 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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -158,6 +158,11 @@
|
|||
"name": "lampSizeUV",
|
||||
"link": "_lampSizeUV",
|
||||
"ifdef": ["_PCSS"]
|
||||
},
|
||||
{
|
||||
"name": "senvmapBrdf",
|
||||
"link": "_envmapBrdf",
|
||||
"ifdef": ["_VoxelGI"]
|
||||
}
|
||||
],
|
||||
"vertex_shader": "deferred_light.vert.glsl",
|
||||
|
|
|
@ -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
|
@ -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));
|
||||
|
|
|
@ -12,7 +12,7 @@ precision highp float;
|
|||
|
||||
in vec3 pos;
|
||||
in vec3 nor;
|
||||
#ifdef _BaseTex
|
||||
#ifdef _Tex
|
||||
in vec2 tex;
|
||||
#endif
|
||||
#ifdef _VCols
|
||||
|
|
|
@ -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
55
raw/forward/voxel.frag.glsl
Executable 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
56
raw/forward/voxel.geom.glsl
Executable 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
38
raw/forward/voxel.vert.glsl
Executable 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);
|
||||
}
|
Loading…
Reference in a new issue