diff --git a/Assets/hosek/hosek_radiance.hdr b/Assets/hosek/hosek_radiance.hdr new file mode 100644 index 00000000..f6a44407 Binary files /dev/null and b/Assets/hosek/hosek_radiance.hdr differ diff --git a/Assets/hosek/hosek_radiance_0.hdr b/Assets/hosek/hosek_radiance_0.hdr new file mode 100644 index 00000000..a9f3cb23 Binary files /dev/null and b/Assets/hosek/hosek_radiance_0.hdr differ diff --git a/Assets/hosek/hosek_radiance_1.hdr b/Assets/hosek/hosek_radiance_1.hdr new file mode 100644 index 00000000..44e1b7cb Binary files /dev/null and b/Assets/hosek/hosek_radiance_1.hdr differ diff --git a/Assets/hosek/hosek_radiance_2.hdr b/Assets/hosek/hosek_radiance_2.hdr new file mode 100644 index 00000000..5c5b2a0d Binary files /dev/null and b/Assets/hosek/hosek_radiance_2.hdr differ diff --git a/Assets/hosek/hosek_radiance_3.hdr b/Assets/hosek/hosek_radiance_3.hdr new file mode 100644 index 00000000..d57d6a32 Binary files /dev/null and b/Assets/hosek/hosek_radiance_3.hdr differ diff --git a/Assets/hosek/hosek_radiance_4.hdr b/Assets/hosek/hosek_radiance_4.hdr new file mode 100644 index 00000000..2be14f17 Binary files /dev/null and b/Assets/hosek/hosek_radiance_4.hdr differ diff --git a/Assets/hosek/hosek_radiance_5.hdr b/Assets/hosek/hosek_radiance_5.hdr new file mode 100644 index 00000000..76d5ee0d Binary files /dev/null and b/Assets/hosek/hosek_radiance_5.hdr differ diff --git a/Assets/hosek/hosek_radiance_6.hdr b/Assets/hosek/hosek_radiance_6.hdr new file mode 100644 index 00000000..08794116 Binary files /dev/null and b/Assets/hosek/hosek_radiance_6.hdr differ diff --git a/Assets/hosek/hosek_radiance_7.hdr b/Assets/hosek/hosek_radiance_7.hdr new file mode 100644 index 00000000..3208cd77 Binary files /dev/null and b/Assets/hosek/hosek_radiance_7.hdr differ diff --git a/Sources/armory/Root.hx b/Sources/armory/Root.hx deleted file mode 100644 index 3500a87e..00000000 --- a/Sources/armory/Root.hx +++ /dev/null @@ -1,3 +0,0 @@ -package armory; - -typedef Root = iron.Root; diff --git a/Sources/armory/Scene.hx b/Sources/armory/Scene.hx index 6c2f14bd..3a0911a0 100644 --- a/Sources/armory/Scene.hx +++ b/Sources/armory/Scene.hx @@ -1,53 +1,3 @@ package armory; -import iron.App; -import iron.Root; -import iron.object.Object; -import iron.object.CameraObject; -import iron.data.SceneFormat; -import iron.data.Data; -import armory.trait.internal.PhysicsWorld; - -class Scene { - - var cam:CameraObject; - - public static var physics:PhysicsWorld; - - public function new(sceneName:String) { - - // Startup scene - var sceneObject = Root.addScene(sceneName); - - if (Root.cameras.length == 0) { - trace('No camera found for scene "$sceneName"!'); - return; - } - cam = Root.cameras[0]; - - // Attach world to camera for now - var raw:TSceneFormat = Data.getSceneRaw(sceneName); - cam.world = Data.getWorld(sceneName, raw.world_ref); - - // Physics - physics = new PhysicsWorld(raw.gravity); - sceneObject.addTrait(physics); - - App.notifyOnRender(render); - - // Experimental scene reloading - // App.notifyOnUpdate(function() { - // if (iron.sys.Input.released) { - // // kha.Assets.loadBlob(sceneName + '_arm', function(b:kha.Blob) { - // iron.App.reset(); - // iron.data.Data.clearSceneData(); - // new iron.App(armory.Root); - // // }); - // } - // }); - } - - function render(g:kha.graphics4.Graphics) { - cam.renderFrame(g, Root.root, Root.lamps); - } -} +typedef Scene = iron.Scene; diff --git a/Sources/armory/logicnode/PickerNode.hx b/Sources/armory/logicnode/PickerNode.hx index a8f2ef96..a39fc4ab 100644 --- a/Sources/armory/logicnode/PickerNode.hx +++ b/Sources/armory/logicnode/PickerNode.hx @@ -17,7 +17,7 @@ class PickerNode extends Node { } function init() { - target = iron.Root.root.getChild(property0); + target = iron.Scene.active.getChild(property0); } public static function create(_property0:String):PickerNode { diff --git a/Sources/armory/renderpipeline/HosekWilkie.hx b/Sources/armory/renderpipeline/HosekWilkie.hx index 1054e443..27ebbe70 100644 --- a/Sources/armory/renderpipeline/HosekWilkie.hx +++ b/Sources/armory/renderpipeline/HosekWilkie.hx @@ -128,7 +128,7 @@ class HosekWilkie { // Extract direction from lamp // var mat = iron.data.Data.getMaterial("World_material", "World_material").data; - // var lamp = iron.Root.lamps[0]; + // var lamp = iron.Scene.active.lamps[0]; // var ltr = lamp.transform; // var lf = ltr.matrix.look2(); // lamp.data.data.strength = 3.3 - Math.abs(ltr.absy()) / 45; diff --git a/Sources/armory/trait/ArcBallCamera.hx b/Sources/armory/trait/ArcBallCamera.hx index 6e4b345f..5122052a 100644 --- a/Sources/armory/trait/ArcBallCamera.hx +++ b/Sources/armory/trait/ArcBallCamera.hx @@ -1,7 +1,6 @@ package armory.trait; import iron.Trait; -import iron.Root; import iron.sys.Input; import iron.object.CameraObject; import iron.math.Vec4; @@ -24,7 +23,7 @@ class ArcBallCamera extends Trait { } function init() { - camera = Root.cameras[0]; + camera = cast(object, CameraObject); var r = camera.transform.rot; var q = new Quat(r.x, r.y, r.z, r.w); diff --git a/Sources/armory/trait/FirstPersonController.hx b/Sources/armory/trait/FirstPersonController.hx index 243f2537..c860598a 100644 --- a/Sources/armory/trait/FirstPersonController.hx +++ b/Sources/armory/trait/FirstPersonController.hx @@ -36,7 +36,7 @@ class FirstPersonController extends Trait { function init() { transform = object.transform; body = object.getTrait(RigidBody); - camera = iron.Root.cameras[0]; + camera = cast(object, CameraObject); } function onDown(key: kha.Key, char: String) { diff --git a/Sources/armory/trait/MirrorTexture.hx b/Sources/armory/trait/MirrorTexture.hx new file mode 100644 index 00000000..c8be146a --- /dev/null +++ b/Sources/armory/trait/MirrorTexture.hx @@ -0,0 +1,23 @@ +package armory.trait; + +import iron.Trait; +import iron.object.MeshObject; + +class MirrorTexture extends Trait { + + var cameraName:String; + + public function new(cameraName:String) { + super(); + + this.cameraName = cameraName; + notifyOnInit(init); + } + + function init() { + var image = iron.Scene.active.getCamera(cameraName).data.mirror; + + var o = cast(object, iron.object.MeshObject); + o.materials[0].contexts[0].textures[0] = image; // Override diffuse texture + } +} diff --git a/Sources/armory/trait/PhysicsDrag.hx b/Sources/armory/trait/PhysicsDrag.hx index 48922429..1fb00e50 100644 --- a/Sources/armory/trait/PhysicsDrag.hx +++ b/Sources/armory/trait/PhysicsDrag.hx @@ -31,7 +31,7 @@ class PhysicsDrag extends Trait { } function init() { - physics = armory.Scene.physics; + physics = armory.trait.internal.PhysicsWorld.active; } function update() { diff --git a/Sources/armory/trait/SceneInstance.hx b/Sources/armory/trait/SceneInstance.hx index 4378d3e3..db0dd51b 100644 --- a/Sources/armory/trait/SceneInstance.hx +++ b/Sources/armory/trait/SceneInstance.hx @@ -1,7 +1,6 @@ package armory.trait; import iron.Trait; -import iron.Root; class SceneInstance extends Trait { @@ -9,7 +8,7 @@ class SceneInstance extends Trait { super(); notifyOnInit(function() { - Root.addScene(sceneName, object); + iron.Scene.active.addScene(sceneName, object); }); } } diff --git a/Sources/armory/trait/VehicleBody.hx b/Sources/armory/trait/VehicleBody.hx index dd0fd901..a0bf1d6d 100644 --- a/Sources/armory/trait/VehicleBody.hx +++ b/Sources/armory/trait/VehicleBody.hx @@ -67,12 +67,12 @@ class VehicleBody extends Trait { } function init() { - physics = armory.Scene.physics; + physics = armory.trait.internal.PhysicsWorld.active; transform = object.transform; - camera = iron.Root.cameras[0]; + camera = iron.Scene.active.camera; for (n in wheelNames) { - wheels.push(iron.Root.root.getChild(n)); + wheels.push(iron.Scene.active.root.getChild(n)); } var rightIndex = 0; diff --git a/Sources/armory/trait/WalkNavigation.hx b/Sources/armory/trait/WalkNavigation.hx index 30b98fe6..a0273417 100644 --- a/Sources/armory/trait/WalkNavigation.hx +++ b/Sources/armory/trait/WalkNavigation.hx @@ -2,7 +2,6 @@ package armory.trait; import kha.Key; import iron.Trait; -import iron.Root; import iron.sys.Input; import iron.sys.Time; import iron.object.CameraObject; @@ -39,7 +38,7 @@ class WalkNavigation extends Trait { } function init() { - camera = Root.cameras[0]; + camera = cast(object, CameraObject); } function update() { diff --git a/Sources/armory/trait/internal/Animation.hx b/Sources/armory/trait/internal/Animation.hx index 8185b87b..f436ef28 100644 --- a/Sources/armory/trait/internal/Animation.hx +++ b/Sources/armory/trait/internal/Animation.hx @@ -11,8 +11,9 @@ class Animation extends Trait { var speeds:Array; var loops:Array; var reflects:Array; + static var maxBones:Int; - public function new(startTrack:String, names:Array, starts:Array, ends:Array, speeds:Array, loops:Array, reflects:Array) { + public function new(startTrack:String, names:Array, starts:Array, ends:Array, speeds:Array, loops:Array, reflects:Array, _maxBones:Int) { super(); this.startTrack = startTrack; @@ -22,13 +23,14 @@ class Animation extends Trait { this.speeds = speeds; this.loops = loops; this.reflects = reflects; + maxBones = _maxBones; notifyOnAdd(add); notifyOnUpdate(update); } function add() { - object.setupAnimation(startTrack, names, starts, ends, speeds, loops, reflects); + object.setupAnimation(startTrack, names, starts, ends, speeds, loops, reflects, maxBones); } function update() { diff --git a/Sources/armory/trait/internal/Console.hx b/Sources/armory/trait/internal/Console.hx index 6a1d1093..b65364de 100644 --- a/Sources/armory/trait/internal/Console.hx +++ b/Sources/armory/trait/internal/Console.hx @@ -77,7 +77,7 @@ class Console extends Trait { } ui.separator(); if (ui.node(Id.node(), "Inspector", 0, false)) { - for (o in iron.Root.meshes) { + for (o in iron.Scene.active.meshes) { ui.text(o.name + " (" + Std.int(o.transform.absx() * 100) / 100 + ", " + Std.int(o.transform.absy() * 100) / 100 + ", " + Std.int(o.transform.absz() * 100) / 100 + ")"); } } diff --git a/Sources/armory/trait/internal/JSScriptAPI.hx b/Sources/armory/trait/internal/JSScriptAPI.hx index 13485038..18dcaf50 100644 --- a/Sources/armory/trait/internal/JSScriptAPI.hx +++ b/Sources/armory/trait/internal/JSScriptAPI.hx @@ -47,7 +47,7 @@ class JSScriptAPI { class JSScriptAPI { public static var App = iron.App; - public static var Root = iron.Root; + public static var Scene = iron.Scene; public static var Time = iron.sys.Time; public static var Object = iron.object.Object; public static var Data = iron.data.Data; diff --git a/Sources/armory/trait/internal/PathTracer.hx b/Sources/armory/trait/internal/PathTracer.hx index ddfca6e5..cba5c5de 100644 --- a/Sources/armory/trait/internal/PathTracer.hx +++ b/Sources/armory/trait/internal/PathTracer.hx @@ -3,7 +3,6 @@ package armory.trait.internal; import iron.math.Mat4; import iron.math.Vec4; import iron.Trait; -import iron.Root; import iron.object.Transform; import iron.object.MeshObject; import iron.data.Data; @@ -83,7 +82,7 @@ class PathTracer extends Trait { transformMap = new Map(); var sphereNum = 0; var cubeNum = 0; - for (n in Root.meshes) { + for (n in iron.Scene.active.meshes) { if (n.name.split(".")[0] == "Sphere") { context.raw.bind_constants.push( { @@ -144,7 +143,7 @@ class PathTracer extends Trait { } function update() { - var camera = Root.cameras[0]; + var camera = iron.Scene.active.camera; var eye = camera.transform.loc; // var jitter = Mat4.identity(); diff --git a/Sources/armory/trait/internal/PhysicsWorld.hx b/Sources/armory/trait/internal/PhysicsWorld.hx index fddb3bbe..cc51d61c 100644 --- a/Sources/armory/trait/internal/PhysicsWorld.hx +++ b/Sources/armory/trait/internal/PhysicsWorld.hx @@ -19,6 +19,8 @@ class ContactPair { class PhysicsWorld extends Trait { + public static var active:PhysicsWorld; + #if (!WITH_PHYSICS) public function new(gravity:Array = null) { super(); } #else @@ -39,6 +41,8 @@ class PhysicsWorld extends Trait { public function new(gravity:Array = null) { super(); + active = this; + rbMap = new Map(); //var min = BtVector3.create(-100, -100, -100); @@ -172,12 +176,12 @@ class PhysicsWorld extends Trait { } public function getRayFrom():BtVector3Pointer { - var camera = iron.Root.cameras[0]; + var camera = iron.Scene.active.camera; return BtVector3.create(camera.transform.loc.x, camera.transform.loc.y, camera.transform.loc.z); } public function getRayTo(inputX:Float, inputY:Float):BtVector3Pointer { - var camera = iron.Root.cameras[0]; + var camera = iron.Scene.active.camera; var start = new Vec4(); var end = new Vec4(); RayCaster.getDirection(start, end, inputX, inputY, camera); diff --git a/Sources/armory/trait/internal/RigidBody.hx b/Sources/armory/trait/internal/RigidBody.hx index 2fa90a83..aec0f82f 100644 --- a/Sources/armory/trait/internal/RigidBody.hx +++ b/Sources/armory/trait/internal/RigidBody.hx @@ -52,7 +52,7 @@ class RigidBody extends Trait { public function init() { transform = object.transform; - physics = armory.Scene.physics; + physics = armory.trait.internal.PhysicsWorld.active; if (bodyCreated) return; bodyCreated = true; diff --git a/blender/data/data.blend b/blender/data/data.blend index 210fcaf2..928f089a 100644 Binary files a/blender/data/data.blend and b/blender/data/data.blend differ diff --git a/blender/exporter.py b/blender/exporter.py index e1597801..e0bd3a52 100644 --- a/blender/exporter.py +++ b/blender/exporter.py @@ -561,7 +561,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): return unifiedVertexArray - def ExportBone(self, armature, bone, scene, o): + def ExportBone(self, armature, bone, scene, o, action): bobjectRef = self.bobjectArray.get(bone) if (bobjectRef): @@ -572,12 +572,12 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): #if (name != ""): # o.name = name - self.ExportBoneTransform(armature, bone, scene, o) + self.ExportBoneTransform(armature, bone, scene, o, action) o['objects'] = [] # TODO for subbobject in bone.children: so = {} - self.ExportBone(armature, subbobject, scene, so) + self.ExportBone(armature, subbobject, scene, so, action) o['objects'].append(so) # Export any ordinary objects that are parented to this bone @@ -634,15 +634,28 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): scene.frame_set(currentFrame, currentSubframe) - def ExportBoneSampledAnimation(self, poseBone, scene, o): + def get_action_framerange(self, action): + # TODO: experimental + begin_frame = int(action.frame_range[0]) + end_frame = int(action.frame_range[1]) + if self.beginFrame > begin_frame: # Cap frames to timeline bounds + begin_frame = self.beginFrame + if self.endFrame > end_frame: + end_frame = self.endFrame + return begin_frame, end_frame + + def ExportBoneSampledAnimation(self, poseBone, scene, o, action): # This function exports bone animation as full 4x4 matrices for each frame. currentFrame = scene.frame_current currentSubframe = scene.frame_subframe + # Frame range + begin_frame, end_frame = self.get_action_framerange(action) + animationFlag = False m1 = poseBone.matrix.copy() - for i in range(self.beginFrame, self.endFrame): + for i in range(begin_frame, end_frame): scene.frame_set(i) m2 = poseBone.matrix if (ArmoryExporter.MatricesDifferent(m1, m2)): @@ -656,28 +669,28 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): tracko['time'] = {} tracko['time']['values'] = [] - for i in range(self.beginFrame, self.endFrame): - tracko['time']['values'].append(((i - self.beginFrame) * self.frameTime)) + for i in range(begin_frame, end_frame): + tracko['time']['values'].append(((i - begin_frame) * self.frameTime)) - tracko['time']['values'].append((self.endFrame * self.frameTime)) + tracko['time']['values'].append((end_frame * self.frameTime)) tracko['value'] = {} tracko['value']['values'] = [] parent = poseBone.parent if (parent): - for i in range(self.beginFrame, self.endFrame): + for i in range(begin_frame, end_frame): scene.frame_set(i) tracko['value']['values'].append(self.WriteMatrix(parent.matrix.inverted() * poseBone.matrix)) - scene.frame_set(self.endFrame) + scene.frame_set(end_frame) tracko['value']['values'].append(self.WriteMatrix(parent.matrix.inverted() * poseBone.matrix)) else: - for i in range(self.beginFrame, self.endFrame): + for i in range(begin_frame, end_frame): scene.frame_set(i) tracko['value']['values'].append(self.WriteMatrix(poseBone.matrix)) - scene.frame_set(self.endFrame) + scene.frame_set(end_frame) tracko['value']['values'].append(self.WriteMatrix(poseBone.matrix)) o['animation']['tracks'] = [tracko] @@ -1325,7 +1338,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): # If an object is used as a bone, then we force its type to be a bone. boneRef[1]["objectType"] = kNodeTypeBone - def ExportBoneTransform(self, armature, bone, scene, o): + def ExportBoneTransform(self, armature, bone, scene, o, action): curveArray = self.CollectBoneAnimation(armature, bone.name) animation = ((len(curveArray) != 0) or (ArmoryExporter.sampleAnimationFlag)) @@ -1341,7 +1354,6 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): if (parentPoseBone): transform = parentPoseBone.matrix.inverted() * transform - o['transform'] = {} #if (animation): @@ -1350,7 +1362,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): o['transform']['values'] = self.WriteMatrix(transform) if ((animation) and (poseBone)): - self.ExportBoneSampledAnimation(poseBone, scene, o) + self.ExportBoneSampledAnimation(poseBone, scene, o, action) def ExportMaterialRef(self, material, index, o): if material == None: @@ -1475,7 +1487,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): self.ExportObjectTransform(bobject, scene, o) # Viewport Camera - overwrite active camera matrix with viewport matrix - if type == kNodeTypeCamera and bpy.data.worlds[0].ArmPlayViewportCamera: + if type == kNodeTypeCamera and bpy.data.worlds[0].ArmPlayViewportCamera and bobject.name == self.scene.camera.name: viewport_matrix = self.get_viewport_view_matrix() if viewport_matrix != None: o['transform']['values'] = self.WriteMatrix(viewport_matrix.inverted()) @@ -1483,29 +1495,41 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): o['local_transform_only'] = True if (bobject.type == "ARMATURE"): - skeleton = bobject.data # Armature data - if (skeleton): - armatureid = utils.safe_filename(skeleton.name) - o['bones_ref'] = 'bones_' + armatureid + armdata = bobject.data # Armature data + if (armdata): + # Reference start action + if bobject.edit_actions_prop: + action = bpy.data.actions[bobject.start_action_name_prop] + else: # Use default + action = bobject.animation_data.action + armatureid = utils.safe_filename(armdata.name) + o['bones_ref'] = 'bones_' + armatureid + '_' + action.name - # TODO: use option_mesh_per_file - fp = self.get_meshes_file_path(o['bones_ref']) - assets.add(fp) + # Write bones + if armdata.edit_actions: + export_actions = [] + for t in my_actiontraitlist: + export_actions.append(t.name) + else: # Use default + export_actions = [action] - if bobject.data.armature_cached == False or not os.path.exists(fp): - bones = [] - for bone in skeleton.bones: - if (not bone.parent): - boneo = {} - self.ExportBone(bobject, bone, scene, boneo) - #o.objects.append(boneo) - bones.append(boneo) - - # Save bones separately - bones_obj = {} - bones_obj['objects'] = bones - utils.write_arm(fp, bones_obj) - bobject.data.armature_cached = True + for action in export_actions: + armdata.animation_data.action = action + fp = self.get_meshes_file_path('bones_' + armatureid + '_' + action.name) + assets.add(fp) + if armdata.armature_cached == False or not os.path.exists(fp): + bones = [] + for bone in armdata.bones: + if (not bone.parent): + boneo = {} + self.ExportBone(bobject, bone, scene, boneo, action) + #o.objects.append(boneo) + bones.append(boneo) + # Save bones separately + bones_obj = {} + bones_obj['objects'] = bones + utils.write_arm(fp, bones_obj) + armdata.armature_cached = True if (parento == None): self.output['objects'].append(o) @@ -1544,9 +1568,6 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): boneArray = armature.data.bones boneCount = len(boneArray) - #self.IndentWrite(B"ref\t\t\t// ") - #self.WriteInt(boneCount) - for i in range(boneCount): boneRef = self.FindNode(boneArray[i].name) if (boneRef): @@ -1554,16 +1575,12 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): else: oskel['bone_ref_array'].append("null") - # Write the bind pose transform array. + # Write the bind pose transform array oskel['transforms'] = [] - - #self.IndentWrite(B"float[16]\t// ") - #self.WriteInt(boneCount) - for i in range(boneCount): oskel['transforms'].append(self.WriteMatrix(armature.matrix_world * boneArray[i].matrix_local)) - # Export the per-vertex bone influence data. + # Export the per-vertex bone influence data groupRemap = [] for group in bobject.vertex_groups: @@ -2149,8 +2166,23 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): o['type'] = 'perspective' else: o['type'] = 'orthographic' + + if objref.is_mirror: + o['is_mirror'] = True + o['mirror_resolution_x'] = int(objref.mirror_resolution_x) + o['mirror_resolution_y'] = int(objref.mirror_resolution_y) + + o['frustum_culling'] = objref.frustum_culling + o['pipeline'] = objref.pipeline_path + '/' + objref.pipeline_path # Same file name and id - self.cb_export_camera(objref, o) + if 'Background' in bpy.data.worlds[0].node_tree.nodes: # TODO: parse node tree + background_node = bpy.data.worlds[0].node_tree.nodes['Background'] + col = background_node.inputs[0].default_value + strength = background_node.inputs[1].default_value + o['clear_color'] = [col[0] * strength, col[1] * strength, col[2] * strength, col[3]] + else: + o['clear_color'] = [0.0, 0.0, 0.0, 1.0] + self.output['camera_datas'].append(o) def ExportSpeaker(self, objectRef): @@ -2286,14 +2318,14 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): self.output = {} - scene = context.scene - originalFrame = scene.frame_current - originalSubframe = scene.frame_subframe + self.scene = context.scene + originalFrame = self.scene.frame_current + originalSubframe = self.scene.frame_subframe self.restoreFrame = False - self.beginFrame = scene.frame_start - self.endFrame = scene.frame_end - self.frameTime = 1.0 / (scene.render.fps_base * scene.render.fps) + self.beginFrame = self.scene.frame_start + self.endFrame = self.scene.frame_end + self.frameTime = 1.0 / (self.scene.render.fps_base * self.scene.render.fps) self.bobjectArray = {} self.meshArray = {} @@ -2322,18 +2354,21 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): self.cb_preprocess() - for bobject in scene.objects: + for bobject in self.scene.objects: if (not bobject.parent): self.ProcessBObject(bobject) self.ProcessSkinnedMeshes() + self.output['name'] = self.scene.name self.output['objects'] = [] - for object in scene.objects: + for object in self.scene.objects: if (not object.parent): - self.ExportObject(object, scene) + self.ExportObject(object, self.scene) if not ArmoryExporter.option_mesh_only: + self.output['camera_ref'] = self.scene.camera.name + self.output['material_datas'] = [] self.ExportMaterials() @@ -2342,16 +2377,16 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): self.output['world_datas'] = [] self.ExportWorlds() - self.output['world_ref'] = scene.world.name + self.output['world_ref'] = self.scene.world.name - self.output['gravity'] = [scene.gravity[0], scene.gravity[1], scene.gravity[2]] + self.output['gravity'] = [self.scene.gravity[0], self.scene.gravity[1], self.scene.gravity[2]] - self.ExportObjects(scene) + self.ExportObjects(self.scene) self.cb_postprocess() if (self.restoreFrame): - scene.frame_set(originalFrame, originalSubframe) + self.scene.frame_set(originalFrame, originalSubframe) # Write .arm utils.write_arm(self.filepath, self.output) @@ -2471,7 +2506,6 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): break def cb_export_object(self, bobject, o, type): - #return # Export traits o['traits'] = [] for t in bobject.my_traitlist: @@ -2481,24 +2515,6 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): if t.type_prop == 'Logic Nodes' and t.nodes_name_prop != '': x['type'] = 'Script' x['class_name'] = bpy.data.worlds[0].ArmProjectPackage + '.node.' + utils.safe_filename(t.nodes_name_prop) - elif t.type_prop == 'Animation': - x['type'] = 'Script' - x['class_name'] = 'armory.trait.internal.Animation' - names = [] - starts = [] - ends = [] - speeds = [] - loops = [] - reflects = [] - for at in t.my_animationtraitlist: - if at.enabled_prop: - names.append(at.name) - starts.append(at.start_prop) - ends.append(at.end_prop) - speeds.append(at.speed_prop) - loops.append(at.loop_prop) - reflects.append(at.reflect_prop) - x['parameters'] = [t.start_track_name_prop, names, starts, ends, speeds, loops, reflects] elif t.type_prop == 'JS Script' or t.type_prop == 'Python Script': x['type'] = 'Script' x['class_name'] = 'armory.trait.internal.JSScript' @@ -2551,7 +2567,37 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): x['parameters'] = [] for pt in t.my_paramstraitlist: # Append parameters x['parameters'].append(ast.literal_eval(pt.name)) - + o['traits'].append(x) + + # Animation trait + if self.is_bone_animation_enabled(bobject) or self.is_object_animation_enabled(bobject): + x = {} + x['type'] = 'Script' + x['class_name'] = 'armory.trait.internal.Animation' + if len(bobject.my_cliptraitlist) > 0: + # Edit clips enabled + names = [] + starts = [] + ends = [] + speeds = [] + loops = [] + reflects = [] + for at in bobject.my_cliptraitlist: + if at.enabled_prop: + names.append(at.name) + starts.append(at.start_prop) + ends.append(at.end_prop) + speeds.append(at.speed_prop) + loops.append(at.loop_prop) + reflects.append(at.reflect_prop) + x['parameters'] = [bobject.start_track_name_prop, names, starts, ends, speeds, loops, reflects, bpy.data.worlds[0].generate_gpu_skin_max_bones] + else: + # Export default clip, taking full action + if self.is_bone_animation_enabled(bobject): + begin_frame, end_frame = self.get_action_framerange(bobject.parent.animation_data.action) + else: + begin_frame, end_frame = self.get_action_framerange(bobject.animation_data.action) + x['parameters'] = ['default', ['default'], [begin_frame], [end_frame], [1.0], [True], [False], bpy.data.worlds[0].generate_gpu_skin_max_bones] o['traits'].append(x) # Rigid body trait @@ -2592,8 +2638,8 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): console_trait['class_name'] = 'armory.trait.internal.Console' console_trait['parameters'] = [] o['traits'].append(console_trait) - # Viewport camera enabled, attach navigation if enabled - if bpy.data.worlds[0].ArmPlayViewportCamera and bpy.data.worlds[0].ArmPlayViewportNavigation == 'Walk': + # Viewport camera enabled, attach navigation to active camera if enabled + if bobject.name == self.scene.camera.name and bpy.data.worlds[0].ArmPlayViewportCamera and bpy.data.worlds[0].ArmPlayViewportNavigation == 'Walk': navigation_trait = {} navigation_trait['type'] = 'Script' navigation_trait['class_name'] = 'armory.trait.WalkNavigation' @@ -2613,23 +2659,20 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): self.materialToObjectDict[mat] = [bobject] self.materialToGameObjectDict[mat] = [o] - def cb_export_camera(self, object, o): - #return - o['frustum_culling'] = object.frustum_culling - o['pipeline'] = object.pipeline_path + '/' + object.pipeline_path # Same file name and id - - if 'Background' in bpy.data.worlds[0].node_tree.nodes: # TODO: parse node tree - background_node = bpy.data.worlds[0].node_tree.nodes['Background'] - col = background_node.inputs[0].default_value - strength = background_node.inputs[1].default_value - o['clear_color'] = [col[0] * strength, col[1] * strength, col[2] * strength, col[3]] - else: - o['clear_color'] = [0.0, 0.0, 0.0, 1.0] + def is_object_animation_enabled(self, bobject): + # Checks if animation is present and enabled + if bobject.object_animation_enabled == False or bobject.type == 'ARMATURE' or bobject.type == 'BONE': + return False + if bobject.animation_data and bobject.animation_data.action: + return True + return False - def find_anim_trait(self, ob): - # Checks if animation trait is attached - for t in ob.my_traitlist: - if t.type_prop == 'Animation' and t.enabled_prop == True: + def is_bone_animation_enabled(self, bobject): + # Checks if animation is present and enabled for parented armature + if bobject.parent and bobject.parent.type == 'ARMATURE': + if bobject.parent.bone_animation_enabled == False: + return False + if bobject.parent.animation_data and bobject.parent.animation_data.action: return True return False @@ -2733,7 +2776,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): if ob.instanced_children or len(ob.particle_systems) > 0: defs.append('_Instancing') # GPU Skinning - if ob.find_armature() and self.find_anim_trait(ob) and bpy.data.worlds[0].generate_gpu_skin == True: + if ob.find_armature() and self.is_bone_animation_enabled(ob) and bpy.data.worlds[0].generate_gpu_skin == True: defs.append('_Skinning') # Billboarding if len(ob.constraints) > 0 and ob.constraints[0].target != None and \ @@ -2762,13 +2805,20 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): # Main probe world_generate_radiance = False defs = bpy.data.worlds[0].world_defs - if '_EnvTex' in defs: # Radiance only for texture - world_generate_radiance = bpy.data.worlds[0].generate_radiance generate_irradiance = True #'_EnvTex' in defs or '_EnvSky' in defs or '_EnvCon' in defs - envtex = bpy.data.cameras[0].world_envtex_name.rsplit('.', 1)[0] + irrtex = bpy.data.cameras[0].world_envtex_name.rsplit('.', 1)[0] + radtex = irrtex + + # Radiance + if '_EnvTex' in defs: + world_generate_radiance = bpy.data.worlds[0].generate_radiance + elif '_EnvSky' in defs and bpy.data.worlds[0].generate_radiance_sky: + world_generate_radiance = bpy.data.worlds[0].generate_radiance + radtex = 'hosek' + num_mips = bpy.data.cameras[0].world_envtex_num_mips strength = bpy.data.cameras[0].world_envtex_strength - po = self.make_probe('world', envtex, num_mips, strength, 1.0, [0, 0, 0], [0, 0, 0], world_generate_radiance, generate_irradiance) + po = self.make_probe('world', irrtex, radtex, num_mips, strength, 1.0, [0, 0, 0], [0, 0, 0], world_generate_radiance, generate_irradiance) o['probes'].append(po) if '_EnvSky' in defs: @@ -2793,17 +2843,17 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper): texture_path = '//' + cam.probe_texture cam.probe_num_mips = write_probes.write_probes(texture_path, disable_hdr, cam.probe_num_mips, generate_radiance=generate_radiance) base_name = cam.probe_texture.rsplit('.', 1)[0] - po = self.make_probe(cam.name, base_name, cam.probe_num_mips, cam.probe_strength, cam.probe_blending, volume, volume_center, generate_radiance, generate_irradiance) + po = self.make_probe(cam.name, base_name, base_name, cam.probe_num_mips, cam.probe_strength, cam.probe_blending, volume, volume_center, generate_radiance, generate_irradiance) o['probes'].append(po) - def make_probe(self, id, envtex, mipmaps, strength, blending, volume, volume_center, generate_radiance, generate_irradiance): + def make_probe(self, id, irrtex, radtex, mipmaps, strength, blending, volume, volume_center, generate_radiance, generate_irradiance): po = {} po['name'] = id if generate_radiance: - po['radiance'] = envtex + '_radiance' + po['radiance'] = radtex + '_radiance' po['radiance_mipmaps'] = mipmaps if generate_irradiance: - po['irradiance'] = envtex + '_irradiance' + po['irradiance'] = irrtex + '_irradiance' else: po['irradiance'] = '' # No irradiance data, fallback to default at runtime po['strength'] = strength diff --git a/blender/nodes_renderpath.py b/blender/nodes_renderpath.py index ad480344..4de08618 100755 --- a/blender/nodes_renderpath.py +++ b/blender/nodes_renderpath.py @@ -796,13 +796,19 @@ def buildNodeTrees(shader_references, asset_references, assets_path): # Always include buildNodeTrees.linked_assets.append(buildNodeTrees.assets_path + 'brdf.png') - # Export selected pipeline - node_group = bpy.data.node_groups[bpy.data.cameras[0].pipeline_path] - buildNodeTree(node_group, shader_references, asset_references) + # Export pipeline for each camera + parsed_paths = [] + for cam in bpy.data.cameras: + # if cam.game_export + if cam.pipeline_path not in parsed_paths: + node_group = bpy.data.node_groups[cam.pipeline_path] + buildNodeTree(cam, node_group, shader_references, asset_references) + parsed_paths.append(cam.pipeline_path) return buildNodeTrees.linked_assets -def buildNodeTree(node_group, shader_references, asset_references): +def buildNodeTree(cam, node_group, shader_references, asset_references): + buildNodeTree.cam = cam output = {} dat = {} output['pipeline_datas'] = [dat] @@ -817,8 +823,8 @@ def buildNodeTree(node_group, shader_references, asset_references): dat['name'] = node_group_name # Store main context names - dat['mesh_context'] = bpy.data.cameras[0].mesh_context - dat['shadows_context'] = bpy.data.cameras[0].shadows_context + dat['mesh_context'] = buildNodeTree.cam.mesh_context + dat['shadows_context'] = buildNodeTree.cam.shadows_context dat['render_targets'], dat['depth_buffers'] = preprocess_pipeline(rn, node_group) dat['stages'] = [] @@ -878,7 +884,7 @@ def make_draw_meshes(stage, node_group, node): # Context context = node.inputs[1].default_value # Store shadowmap size - if context == bpy.data.cameras[0].shadows_context: + if context == buildNodeTree.cam.shadows_context: bpy.data.worlds[0].shadowmap_size = buildNode.last_set_target_w stage['params'].append(context) # Order @@ -889,7 +895,7 @@ def make_draw_decals(stage, node_group, node, shader_references, asset_reference stage['command'] = 'draw_decals' context = node.inputs[1].default_value stage['params'].append(context) # Context - bpy.data.cameras[0].last_decal_context = context + buildNodeTree.cam.last_decal_context = context def make_bind_target(stage, node_group, node, constant_name, currentNode=None, target_index=1): if currentNode == None: @@ -985,7 +991,7 @@ def make_draw_compositor(stage, node_group, node, shader_references, asset_refer if wrd.generate_fog: compositor_defs += '_CompoFog' compo_pos = True - if bpy.data.cameras[0].cycles.aperture_size > 0.0: + if buildNodeTree.cam.cycles.aperture_size > 0.0: compositor_defs += '_CompoDOF' compo_depth = True if compo_pos: @@ -1186,7 +1192,7 @@ def buildNode(stages, node, node_group, shader_references, asset_references): stencil_val = None if node.inputs[1].default_value == True: if node.inputs[2].is_linked: # Assume background color node is linked - color_val = bpy.data.cameras[0].world_envtex_color + color_val = buildNodeTree.cam.world_envtex_color else: color_val = node.inputs[2].default_value if node.inputs[3].default_value == True: @@ -1237,7 +1243,7 @@ def buildNode(stages, node, node_group, shader_references, asset_references): make_set_target(stage, node_group, node) stages.append(stage) # Bind targets - if node.inputs[2].is_linked or node.inputs[3].is_linked: + if node.inputs[2].is_linked or node.inputs[3].is_linked or node.inputs[4].is_linked: stage = {} stage['params'] = [] buildNode.last_bind_target = stage @@ -1390,14 +1396,14 @@ def get_root_node(node_group): for n in node_group.nodes: if n.bl_idname == 'BeginNodeType': # Store contexts - bpy.data.cameras[0].pipeline_id = n.inputs[0].default_value + buildNodeTree.cam.pipeline_id = n.inputs[0].default_value mesh_contexts = n.inputs[1].default_value.split(',') - bpy.data.cameras[0].mesh_context = mesh_contexts[0] + buildNodeTree.cam.mesh_context = mesh_contexts[0] if len(mesh_contexts) > 1: - bpy.data.cameras[0].mesh_context_empty = mesh_contexts[1] - bpy.data.cameras[0].shadows_context = n.inputs[2].default_value - bpy.data.cameras[0].translucent_context = n.inputs[3].default_value - bpy.data.cameras[0].overlay_context = n.inputs[4].default_value + buildNodeTree.cam.mesh_context_empty = mesh_contexts[1] + buildNodeTree.cam.shadows_context = n.inputs[2].default_value + buildNodeTree.cam.translucent_context = n.inputs[3].default_value + buildNodeTree.cam.overlay_context = n.inputs[4].default_value if n.inputs[5].default_value == False: # No HDR space lighting, append def bpy.data.worlds[0].world_defs += '_LDR' rn = findNodeByLinkFrom(node_group, n, n.outputs[0]) @@ -1408,16 +1414,16 @@ def preprocess_pipeline(root_node, node_group): render_targets = [] depth_buffers = [] preprocess_pipeline.velocity_def_added = False - bpy.data.cameras[0].pipeline_passes = '' + buildNodeTree.cam.pipeline_passes = '' traverse_pipeline(root_node, node_group, render_targets, depth_buffers) return render_targets, depth_buffers def traverse_pipeline(node, node_group, render_targets, depth_buffers): # Gather linked draw geometry contexts if node.bl_idname == 'DrawMeshesNodeType': - if bpy.data.cameras[0].pipeline_passes != '': - bpy.data.cameras[0].pipeline_passes += '_' # Separator - bpy.data.cameras[0].pipeline_passes += node.inputs[1].default_value + if buildNodeTree.cam.pipeline_passes != '': + buildNodeTree.cam.pipeline_passes += '_' # Separator + buildNodeTree.cam.pipeline_passes += node.inputs[1].default_value # Gather defs from linked nodes if node.bl_idname == 'TAAPassNodeType' or node.bl_idname == 'MotionBlurVelocityPassNodeType' or node.bl_idname == 'SSAOReprojectPassNodeType': diff --git a/blender/nodes_world.py b/blender/nodes_world.py index ac726577..7c2ed416 100755 --- a/blender/nodes_world.py +++ b/blender/nodes_world.py @@ -77,6 +77,10 @@ def buildNodeTree(world_name, node_group): if wrd.generate_shadows == False: wrd.world_defs += '_NoShadows' + # Percentage closer soft shadows + if wrd.generate_pcss: + wrd.world_defs += '_PCSS' + # Enable probes for cam in bpy.data.cameras: if cam.is_probe: @@ -166,7 +170,7 @@ def parse_color(node_group, node, context, envmap_strength_const): # Append LDR define if disable_hdr: bpy.data.worlds[0].world_defs += '_EnvLDR' - # Append radiance degine + # Append radiance define if generate_radiance: bpy.data.worlds[0].world_defs += '_Rad' @@ -191,5 +195,18 @@ def parse_color(node_group, node, context, envmap_strength_const): write_probes.write_sky_irradiance(base_name) + # Radiance + if bpy.data.worlds[0].generate_radiance_sky and bpy.data.worlds[0].generate_radiance: + bpy.data.worlds[0].world_defs += '_Rad' + + user_preferences = bpy.context.user_preferences + addon_prefs = user_preferences.addons['armory'].preferences + sdk_path = addon_prefs.sdk_path + assets.add(sdk_path + 'armory/Assets/hosek/hosek_radiance.hdr') + for i in range(0, 8): + assets.add(sdk_path + 'armory/Assets/hosek/hosek_radiance_' + str(i) + '.hdr') + + bpy.data.cameras[0].world_envtex_num_mips = 8 + # Adjust strength to match Cycles envmap_strength_const['float'] *= 0.25 diff --git a/blender/props.py b/blender/props.py index 2f38da9b..cbc0cf09 100755 --- a/blender/props.py +++ b/blender/props.py @@ -5,6 +5,8 @@ import json import nodes_renderpath from bpy.types import Menu, Panel, UIList from bpy.props import * +from traits_clip import * +from traits_action import * import utils def on_scene_update(context): @@ -15,10 +17,6 @@ def on_scene_update(context): elif edit_obj.type == 'ARMATURE': edit_obj.data.armature_cached = False - for text in bpy.data.texts: - if text.is_updated: - print('ASDASDASDASDASD') - def invalidate_shader_cache(self, context): # compiled.glsl changed, recompile all shaders next time fp = utils.get_fp() @@ -91,6 +89,16 @@ def initProperties(): bpy.types.Object.override_material_name = bpy.props.StringProperty(name="Name", default="") bpy.types.Object.game_export = bpy.props.BoolProperty(name="Export", default=True) bpy.types.Object.spawn = bpy.props.BoolProperty(name="Spawn", description="Auto-add this object when creating scene", default=True) + # - Clips + bpy.types.Object.bone_animation_enabled = bpy.props.BoolProperty(name="Bone Animation", default=True) + bpy.types.Object.object_animation_enabled = bpy.props.BoolProperty(name="Object Animation", default=True) + bpy.types.Object.edit_tracks_prop = bpy.props.BoolProperty(name="Edit Clips", description="A name for this item", default=False) + bpy.types.Object.start_track_name_prop = bpy.props.StringProperty(name="Start Track", description="A name for this item", default="") + bpy.types.Object.my_cliptraitlist = bpy.props.CollectionProperty(type=ListClipTraitItem) + bpy.types.Object.cliptraitlist_index = bpy.props.IntProperty(name="Index for my_list", default=0) + # - Actions + bpy.types.Object.edit_actions_prop = bpy.props.BoolProperty(name="Edit Actions", description="A name for this item", default=False) + bpy.types.Object.start_action_name_prop = bpy.props.StringProperty(name="Start Action", description="A name for this item", default="") # For mesh bpy.types.Mesh.mesh_cached = bpy.props.BoolProperty(name="Mesh Cached", default=False) bpy.types.Mesh.mesh_cached_verts = bpy.props.IntProperty(name="Last Verts", default=0) @@ -99,6 +107,10 @@ def initProperties(): bpy.types.Curve.static_usage = bpy.props.BoolProperty(name="Static Usage", default=True) # For armature bpy.types.Armature.armature_cached = bpy.props.BoolProperty(name="Armature Cached", default=False) + # Actions + bpy.types.Armature.edit_actions = bpy.props.BoolProperty(name="Edit Actions", default=False) + bpy.types.Armature.my_actiontraitlist = bpy.props.CollectionProperty(type=ListActionTraitItem) + bpy.types.Armature.actiontraitlist_index = bpy.props.IntProperty(name="Index for my_list", default=0) # For camera bpy.types.Camera.frustum_culling = bpy.props.BoolProperty(name="Frustum Culling", default=True) bpy.types.Camera.pipeline_path = bpy.props.StringProperty(name="Render Path", default="deferred_path") @@ -117,6 +129,9 @@ def initProperties(): bpy.types.Camera.probe_volume = bpy.props.StringProperty(name="Volume", default="") bpy.types.Camera.probe_strength = bpy.props.FloatProperty(name="Strength", default=1.0) bpy.types.Camera.probe_blending = bpy.props.FloatProperty(name="Blending", default=0.0) + bpy.types.Camera.is_mirror = bpy.props.BoolProperty(name="Mirror", default=False) + bpy.types.Camera.mirror_resolution_x = bpy.props.FloatProperty(name="X", default=512.0) + bpy.types.Camera.mirror_resolution_y = bpy.props.FloatProperty(name="Y", default=256.0) # TODO: move to world bpy.types.Camera.world_envtex_name = bpy.props.StringProperty(name="Environment Texture", default='') bpy.types.Camera.world_envtex_num_mips = bpy.props.IntProperty(name="Number of mips", default=0) @@ -127,7 +142,8 @@ def initProperties(): bpy.types.Camera.world_envtex_ground_albedo = bpy.props.FloatProperty(name="Ground Albedo", default=0.0) bpy.types.Camera.last_decal_context = bpy.props.StringProperty(name="Decal Context", default='') bpy.types.World.world_defs = bpy.props.StringProperty(name="World Shader Defs", default='') - bpy.types.World.generate_radiance = bpy.props.BoolProperty(name="Radiance Probes", default=True, update=invalidate_shader_cache) + bpy.types.World.generate_radiance = bpy.props.BoolProperty(name="Probe Radiance", default=True, update=invalidate_shader_cache) + bpy.types.World.generate_radiance_sky = bpy.props.BoolProperty(name="Sky Radiance", default=False, update=invalidate_shader_cache) bpy.types.World.generate_clouds = bpy.props.BoolProperty(name="Clouds", default=False, update=invalidate_shader_cache) bpy.types.World.generate_clouds_density = bpy.props.FloatProperty(name="Density", default=0.5, min=0.0, max=10.0, update=invalidate_shader_cache) bpy.types.World.generate_clouds_size = bpy.props.FloatProperty(name="Size", default=1.0, min=0.0, max=10.0, update=invalidate_shader_cache) @@ -167,6 +183,8 @@ def initProperties(): bpy.types.World.generate_ssr_falloff_exp = bpy.props.FloatProperty(name="Falloff Exp", default=5.0, update=invalidate_shader_cache) bpy.types.World.generate_ssr_jitter = bpy.props.FloatProperty(name="Jitter", default=0.6, update=invalidate_shader_cache) bpy.types.World.generate_ssr_texture_scale = bpy.props.FloatProperty(name="Texture Scale", default=0.5, min=0.0, max=1.0, update=invalidate_shader_cache) + bpy.types.World.generate_pcss = bpy.props.BoolProperty(name="PCSS", description="Percentage Closer Soft Shadows", default=False, update=invalidate_shader_cache) + # Compositor bpy.types.World.generate_letterbox = bpy.props.BoolProperty(name="Letterbox", default=False, update=invalidate_shader_cache) bpy.types.World.generate_letterbox_size = bpy.props.FloatProperty(name="Size", default=0.1, update=invalidate_shader_cache) bpy.types.World.generate_grain = bpy.props.BoolProperty(name="Film Grain", default=False, update=invalidate_shader_cache) @@ -175,6 +193,7 @@ def initProperties(): bpy.types.World.generate_fog_color = bpy.props.FloatVectorProperty(name="Color", size=3, subtype='COLOR', default=[0.5, 0.6, 0.7], update=invalidate_shader_cache) bpy.types.World.generate_fog_amounta = bpy.props.FloatProperty(name="Amount A", default=0.25, update=invalidate_shader_cache) bpy.types.World.generate_fog_amountb = bpy.props.FloatProperty(name="Amount B", default=0.5, update=invalidate_shader_cache) + # Skin bpy.types.World.generate_gpu_skin = bpy.props.BoolProperty(name="GPU Skinning", default=True, update=invalidate_shader_cache) bpy.types.World.generate_gpu_skin_max_bones = bpy.props.IntProperty(name="Max Bones", default=50, min=1, max=84, update=invalidate_shader_cache) # For material @@ -246,6 +265,47 @@ class ObjectPropsPanel(bpy.types.Panel): if obj.override_material: layout.prop(obj, 'override_material_name') + if obj.type == 'ARMATURE': + layout.prop(obj, 'bone_animation_enabled') + if obj.bone_animation_enabled: + layout.prop(obj, 'edit_actions_prop') + if obj.edit_actions_prop: + layout.prop_search(obj, "start_action_name_prop", obj.data, "my_actiontraitlist", "Start Action") + else: + layout.prop(obj, 'object_animation_enabled') + + if (obj.type == 'ARMATURE' and obj.bone_animation_enabled) or (obj.type != 'ARMATURE' and obj.object_animation_enabled): + layout.prop(obj, 'edit_tracks_prop') + if obj.edit_tracks_prop: + layout.prop_search(obj, "start_track_name_prop", obj, "my_cliptraitlist", "Start Clip") + # Tracks list + layout.label("Clips") + animrow = layout.row() + animrows = 2 + if len(obj.my_cliptraitlist) > 1: + animrows = 4 + + row = layout.row() + row.template_list("MY_UL_ClipTraitList", "The_List", obj, "my_cliptraitlist", obj, "cliptraitlist_index", rows=animrows) + + col = row.column(align=True) + col.operator("my_cliptraitlist.new_item", icon='ZOOMIN', text="") + col.operator("my_cliptraitlist.delete_item", icon='ZOOMOUT', text="") + + if len(obj.my_cliptraitlist) > 1: + col.separator() + col.operator("my_cliptraitlist.move_item", icon='TRIA_UP', text="").direction = 'UP' + col.operator("my_cliptraitlist.move_item", icon='TRIA_DOWN', text="").direction = 'DOWN' + + if obj.cliptraitlist_index >= 0 and len(obj.my_cliptraitlist) > 0: + animitem = obj.my_cliptraitlist[obj.cliptraitlist_index] + row = layout.row() + row.prop(animitem, "start_prop") + row.prop(animitem, "end_prop") + layout.prop(animitem, "speed_prop") + layout.prop(animitem, "loop_prop") + layout.prop(animitem, "reflect_prop") + # Menu in modifiers region class ModifiersPropsPanel(bpy.types.Panel): bl_label = "Armory Props" @@ -281,6 +341,11 @@ class DataPropsPanel(bpy.types.Panel): layout.prop_search(obj.data, "probe_volume", bpy.data, "objects") layout.prop(obj.data, 'probe_strength') layout.prop(obj.data, 'probe_blending') + layout.prop(obj.data, 'is_mirror') + if obj.data.is_mirror == True: + layout.label('Resolution') + layout.prop(obj.data, 'mirror_resolution_x') + layout.prop(obj.data, 'mirror_resolution_y') layout.prop(obj.data, 'frustum_culling') layout.prop_search(obj.data, "pipeline_path", bpy.data, "node_groups") layout.operator("arm.reimport_paths_menu") @@ -292,6 +357,33 @@ class DataPropsPanel(bpy.types.Panel): layout.prop(obj.data, 'lamp_clip_end') layout.prop(obj.data, 'lamp_fov') layout.prop(obj.data, 'lamp_shadows_bias') + elif obj.type == 'ARMATURE': + layout.prop(obj.data, 'edit_actions') + if obj.data.edit_actions: + # Actions list + layout.label("Actions") + animrow = layout.row() + animrows = 2 + if len(obj.data.my_actiontraitlist) > 1: + animrows = 4 + + row = layout.row() + row.template_list("MY_UL_ActionTraitList", "The_List", obj.data, "my_actiontraitlist", obj.data, "actiontraitlist_index", rows=animrows) + + col = row.column(align=True) + col.operator("my_actiontraitlist.new_item", icon='ZOOMIN', text="") + col.operator("my_actiontraitlist.delete_item", icon='ZOOMOUT', text="") + + if len(obj.data.my_actiontraitlist) > 1: + col.separator() + col.operator("my_actiontraitlist.move_item", icon='TRIA_UP', text="").direction = 'UP' + col.operator("my_actiontraitlist.move_item", icon='TRIA_DOWN', text="").direction = 'DOWN' + + if obj.data.actiontraitlist_index >= 0 and len(obj.data.my_actiontraitlist) > 0: + item = obj.data.my_actiontraitlist[obj.data.actiontraitlist_index] + item.name = item.action_name_prop + row = layout.row() + row.prop_search(item, "action_name_prop", bpy.data, "actions", "Action") class ScenePropsPanel(bpy.types.Panel): bl_label = "Armory Props" @@ -379,6 +471,8 @@ class WorldPropsPanel(bpy.types.Panel): wrd = bpy.context.world layout.prop(wrd, 'generate_shadows') layout.prop(wrd, 'generate_radiance') + if wrd.generate_radiance: + layout.prop(wrd, 'generate_radiance_sky') layout.prop(wrd, 'generate_clouds') if wrd.generate_clouds: layout.prop(wrd, 'generate_clouds_density') @@ -409,7 +503,8 @@ class WorldPropsPanel(bpy.types.Panel): layout.prop(wrd, 'generate_ssr_falloff_exp') layout.prop(wrd, 'generate_ssr_jitter') layout.prop(wrd, 'generate_ssr_texture_scale') - + layout.prop(wrd, 'generate_pcss') + layout.label('Compositor') layout.prop(wrd, 'generate_letterbox') if wrd.generate_letterbox: diff --git a/blender/start.py b/blender/start.py index 15505350..4c439e5e 100755 --- a/blender/start.py +++ b/blender/start.py @@ -3,20 +3,22 @@ import nodes_logic import nodes_renderpath import nodes_world import exporter -import traits_animation +import traits_action +import traits_clip import traits_params import traits import props import lib.drop_to_ground def register(): + traits_action.register() + traits_clip.register() props.register() project.register() nodes_logic.register() nodes_renderpath.register() nodes_world.register() exporter.register() - traits_animation.register() traits_params.register() traits.register() lib.drop_to_ground.register() @@ -27,8 +29,9 @@ def unregister(): nodes_renderpath.unregister() nodes_world.unregister() exporter.unregister() - traits_animation.unregister() traits_params.unregister() traits.unregister() props.unregister() + traits_action.unregister() + traits_clip.unregister() lib.drop_to_ground.unregister() diff --git a/blender/traits.py b/blender/traits.py index 4bcd98d4..e13c66b0 100755 --- a/blender/traits.py +++ b/blender/traits.py @@ -2,7 +2,6 @@ import shutil import bpy import os import json -from traits_animation import * from traits_params import * from bpy.types import Menu, Panel, UIList from bpy.props import * @@ -27,15 +26,14 @@ class ListTraitItem(bpy.types.PropertyGroup): ('Python Script', 'Python Script', 'Python Script'), ('JS Script', 'JS Script', 'JS Script'), ('Bundled Script', 'Bundled Script', 'Bundled Script'), - ('Logic Nodes', 'Logic Nodes', 'Logic Nodes'), - ('Animation', 'Animation', 'Animation') + ('Logic Nodes', 'Logic Nodes', 'Logic Nodes') ], name = "Type") - data_prop = bpy.props.StringProperty( - name="Data", - description="A name for this item", - default="") + # data_prop = bpy.props.StringProperty( + # name="Data", + # description="A name for this item", + # default="") class_name_prop = bpy.props.StringProperty( name="Class", @@ -52,17 +50,9 @@ class ListTraitItem(bpy.types.PropertyGroup): description="A name for this item", default="") - start_track_name_prop = bpy.props.StringProperty( - name="Start Track", - description="A name for this item", - default="") - my_paramstraitlist = bpy.props.CollectionProperty(type=ListParamsTraitItem) paramstraitlist_index = bpy.props.IntProperty(name="Index for my_list", default=0) - my_animationtraitlist = bpy.props.CollectionProperty(type=ListAnimationTraitItem) - animationtraitlist_index = bpy.props.IntProperty(name="Index for my_list", default=0) - class MY_UL_TraitList(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): # We could write some code to decide which icon to use here... @@ -71,7 +61,7 @@ class MY_UL_TraitList(bpy.types.UIList): # Make sure your code supports all 3 layout types if self.layout_type in {'DEFAULT', 'COMPACT'}: layout.prop(item, "enabled_prop") - layout.label(item.name, icon = custom_icon) + layout.label(item.name, icon=custom_icon) elif self.layout_type in {'GRID'}: layout.alignment = 'CENTER' @@ -239,7 +229,7 @@ class ToolsTraitsPanel(bpy.types.Panel): col.operator("my_traitlist.move_item", icon='TRIA_DOWN', text="").direction = 'DOWN' if obj.traitlist_index >= 0 and len(obj.my_traitlist) > 0: - item = obj.my_traitlist[obj.traitlist_index] + item = obj.my_traitlist[obj.traitlist_index] # Default props row = layout.row() row.prop(item, "type_prop") @@ -299,40 +289,6 @@ class ToolsTraitsPanel(bpy.types.Panel): row = layout.row() row.prop_search(item, "nodes_name_prop", bpy.data, "node_groups", "Tree") - # Animation - elif item.type_prop == 'Animation': - item.name = item.type_prop - row = layout.row() - row.prop_search(item, "start_track_name_prop", item, "my_animationtraitlist", "Start Track") - # Tracks list - layout.label("Tracks") - animrow = layout.row() - animrows = 2 - if len(item.my_animationtraitlist) > 1: - animrows = 4 - - row = layout.row() - row.template_list("MY_UL_AnimationTraitList", "The_List", item, "my_animationtraitlist", item, "animationtraitlist_index", rows=animrows) - - col = row.column(align=True) - col.operator("my_animationtraitlist.new_item", icon='ZOOMIN', text="") - col.operator("my_animationtraitlist.delete_item", icon='ZOOMOUT', text="") - - if len(item.my_animationtraitlist) > 1: - col.separator() - col.operator("my_animationtraitlist.move_item", icon='TRIA_UP', text="").direction = 'UP' - col.operator("my_animationtraitlist.move_item", icon='TRIA_DOWN', text="").direction = 'DOWN' - - if item.animationtraitlist_index >= 0 and len(item.my_animationtraitlist) > 0: - animitem = item.my_animationtraitlist[item.animationtraitlist_index] - - row = layout.row() - row.prop(animitem, "start_prop") - row.prop(animitem, "end_prop") - layout.prop(animitem, "speed_prop") - layout.prop(animitem, "loop_prop") - layout.prop(animitem, "reflect_prop") - # Registration def register(): bpy.utils.register_module(__name__) diff --git a/blender/traits_action.py b/blender/traits_action.py new file mode 100755 index 00000000..81d7b77f --- /dev/null +++ b/blender/traits_action.py @@ -0,0 +1,131 @@ +import shutil +import bpy +import os +import json +from bpy.types import Menu, Panel, UIList +from bpy.props import * + +class ListActionTraitItem(bpy.types.PropertyGroup): + # Group of properties representing an item in the list + name = bpy.props.StringProperty( + name="Name", + description="A name for this item", + default="") + + enabled_prop = bpy.props.BoolProperty( + name="", + description="A name for this item", + default=True) + + action_name_prop = bpy.props.StringProperty( + name="Action", + description="A name for this item", + default="") + +class MY_UL_ActionTraitList(bpy.types.UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # We could write some code to decide which icon to use here... + custom_icon = 'OBJECT_DATAMODE' + + # Make sure your code supports all 3 layout types + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.prop(item, "enabled_prop") + layout.label(item.name, icon=custom_icon) + # layout.prop(item, "name", text="", emboss=False, icon=custom_icon) + + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon = custom_icon) + +class LIST_OT_ActionTraitNewItem(bpy.types.Operator): + # Add a new item to the list + bl_idname = "my_actiontraitlist.new_item" + bl_label = "Add a new item" + + def execute(self, context): + trait = context.object.data + trait.my_actiontraitlist.add() + trait.actiontraitlist_index = len(trait.my_actiontraitlist) - 1 + return{'FINISHED'} + + +class LIST_OT_ActionTraitDeleteItem(bpy.types.Operator): + # Delete the selected item from the list + bl_idname = "my_actiontraitlist.delete_item" + bl_label = "Deletes an item" + + @classmethod + def poll(self, context): + """ Enable if there's something in the list """ + trait = context.object.data + return len(trait.my_actiontraitlist) > 0 + + def execute(self, context): + trait = context.object.data + list = trait.my_actiontraitlist + index = trait.actiontraitlist_index + + list.remove(index) + + if index > 0: + index = index - 1 + + trait.actiontraitlist_index = index + return{'FINISHED'} + + +class LIST_OT_ActionTraitMoveItem(bpy.types.Operator): + # Move an item in the list + bl_idname = "my_actiontraitlist.move_item" + bl_label = "Move an item in the list" + direction = bpy.props.EnumProperty( + items=( + ('UP', 'Up', ""), + ('DOWN', 'Down', ""),)) + + @classmethod + def poll(self, context): + """ Enable if there's something in the list. """ + trait = context.object.data + return len(trait.my_actiontraitlist) > 0 + + + def move_index(self): + # Move index of an item render queue while clamping it + trait = context.object.data + index = trait.actiontraitlist_index + list_length = len(trait.my_actiontraitlist) - 1 + new_index = 0 + + if self.direction == 'UP': + new_index = index - 1 + elif self.direction == 'DOWN': + new_index = index + 1 + + new_index = max(0, min(new_index, list_length)) + index = new_index + + + def execute(self, context): + trait = context.object.data + list = trait.my_actiontraitlist + index = trait.actiontraitlist_index + + if self.direction == 'DOWN': + neighbor = index + 1 + #queue.move(index,neighbor) + self.move_index() + + elif self.direction == 'UP': + neighbor = index - 1 + #queue.move(neighbor, index) + self.move_index() + else: + return{'CANCELLED'} + return{'FINISHED'} + +def register(): + bpy.utils.register_module(__name__) + +def unregister(): + bpy.utils.unregister_module(__name__) diff --git a/blender/traits_animation.py b/blender/traits_clip.py similarity index 70% rename from blender/traits_animation.py rename to blender/traits_clip.py index 27f39185..d84c3736 100755 --- a/blender/traits_animation.py +++ b/blender/traits_clip.py @@ -5,7 +5,7 @@ import json from bpy.types import Menu, Panel, UIList from bpy.props import * -class ListAnimationTraitItem(bpy.types.PropertyGroup): +class ListClipTraitItem(bpy.types.PropertyGroup): # Group of properties representing an item in the list name = bpy.props.StringProperty( name="Name", @@ -43,7 +43,7 @@ class ListAnimationTraitItem(bpy.types.PropertyGroup): default=False) -class MY_UL_AnimationTraitList(bpy.types.UIList): +class MY_UL_ClipTraitList(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): # We could write some code to decide which icon to use here... custom_icon = 'OBJECT_DATAMODE' @@ -58,46 +58,46 @@ class MY_UL_AnimationTraitList(bpy.types.UIList): layout.alignment = 'CENTER' layout.label("", icon = custom_icon) -class LIST_OT_AnimationTraitNewItem(bpy.types.Operator): +class LIST_OT_ClipTraitNewItem(bpy.types.Operator): # Add a new item to the list - bl_idname = "my_animationtraitlist.new_item" + bl_idname = "my_cliptraitlist.new_item" bl_label = "Add a new item" def execute(self, context): - trait = context.object.my_traitlist[context.object.traitlist_index] - trait.my_animationtraitlist.add() - trait.animationtraitlist_index = len(trait.my_animationtraitlist) - 1 + trait = context.object + trait.my_cliptraitlist.add() + trait.cliptraitlist_index = len(trait.my_cliptraitlist) - 1 return{'FINISHED'} -class LIST_OT_AnimationTraitDeleteItem(bpy.types.Operator): +class LIST_OT_ClipTraitDeleteItem(bpy.types.Operator): # Delete the selected item from the list - bl_idname = "my_animationtraitlist.delete_item" + bl_idname = "my_cliptraitlist.delete_item" bl_label = "Deletes an item" @classmethod def poll(self, context): """ Enable if there's something in the list """ - trait = context.object.my_traitlist[context.object.traitlist_index] - return len(trait.my_animationtraitlist) > 0 + trait = context.object + return len(trait.my_cliptraitlist) > 0 def execute(self, context): - trait = context.object.my_traitlist[context.object.traitlist_index] - list = trait.my_animationtraitlist - index = trait.animationtraitlist_index + trait = context.object + list = trait.my_cliptraitlist + index = trait.cliptraitlist_index list.remove(index) if index > 0: index = index - 1 - trait.animationtraitlist_index = index + trait.cliptraitlist_index = index return{'FINISHED'} -class LIST_OT_AnimationTraitMoveItem(bpy.types.Operator): +class LIST_OT_ClipTraitMoveItem(bpy.types.Operator): # Move an item in the list - bl_idname = "my_animationtraitlist.move_item" + bl_idname = "my_cliptraitlist.move_item" bl_label = "Move an item in the list" direction = bpy.props.EnumProperty( items=( @@ -107,15 +107,15 @@ class LIST_OT_AnimationTraitMoveItem(bpy.types.Operator): @classmethod def poll(self, context): """ Enable if there's something in the list. """ - trait = context.object.my_traitlist[context.object.traitlist_index] - return len(trait.my_animationtraitlist) > 0 + trait = context.object + return len(trait.my_cliptraitlist) > 0 def move_index(self): # Move index of an item render queue while clamping it - trait = context.object.my_traitlist[context.object.traitlist_index] - index = trait.animationtraitlist_index - list_length = len(trait.my_animationtraitlist) - 1 + trait = context.object + index = trait.cliptraitlist_index + list_length = len(trait.my_cliptraitlist) - 1 new_index = 0 if self.direction == 'UP': @@ -128,9 +128,9 @@ class LIST_OT_AnimationTraitMoveItem(bpy.types.Operator): def execute(self, context): - trait = context.object.my_traitlist[context.object.traitlist_index] - list = trait.my_animationtraitlist - index = trait.animationtraitlist_index + trait = context.object + list = trait.my_cliptraitlist + index = trait.cliptraitlist_index if self.direction == 'DOWN': neighbor = index + 1 diff --git a/blender/write_data.py b/blender/write_data.py index 56391b8d..2c10322f 100644 --- a/blender/write_data.py +++ b/blender/write_data.py @@ -123,7 +123,12 @@ class Main { f.write(""" kha.System.init({title: projectName, width: projectWidth, height: projectHeight, samplesPerPixel: projectSamplesPerPixel}, function() { iron.App.init(function() { - new armory.Scene(projectScene); + var raw = iron.data.Data.getSceneRaw(projectScene); + var scene = iron.Scene.create(raw); + scene.addTrait(new armory.trait.internal.PhysicsWorld(raw.gravity)); + iron.App.notifyOnRender(function(g:kha.graphics4.Graphics) { + iron.Scene.active.renderFrame(g); + }); }); }); } diff --git a/blender/write_probes.py b/blender/write_probes.py index c6041b7e..0b342d6a 100644 --- a/blender/write_probes.py +++ b/blender/write_probes.py @@ -8,240 +8,244 @@ import utils import assets def add_irr_assets(output_file_irr): - assets.add(output_file_irr + '.arm') + assets.add(output_file_irr + '.arm') def add_rad_assets(output_file_rad, rad_format, num_mips): - assets.add(output_file_rad + '.' + rad_format) - for i in range(0, num_mips): - assets.add(output_file_rad + '_' + str(i) + '.' + rad_format) + assets.add(output_file_rad + '.' + rad_format) + for i in range(0, num_mips): + assets.add(output_file_rad + '_' + str(i) + '.' + rad_format) # Generate probes from environment map def write_probes(image_filepath, disable_hdr, cached_num_mips, generate_radiance=True): - if not os.path.exists('build/compiled/Assets/envmaps'): - os.makedirs('build/compiled/Assets/envmaps') - - base_name = image_filepath.rsplit('/', 1)[1].rsplit('.', 1)[0] # Extract file name without extension - - # Assets to be generated - output_file_irr = 'build/compiled/Assets/envmaps/' + base_name + '_irradiance' - if generate_radiance: - output_file_rad = 'build/compiled/Assets/envmaps/' + base_name + '_radiance' - rad_format = 'jpg' if disable_hdr else 'hdr' + if not os.path.exists('build/compiled/Assets/envmaps'): + os.makedirs('build/compiled/Assets/envmaps') + + base_name = image_filepath.rsplit('/', 1)[1].rsplit('.', 1)[0] # Extract file name without extension + + # Assets to be generated + output_file_irr = 'build/compiled/Assets/envmaps/' + base_name + '_irradiance' + if generate_radiance: + output_file_rad = 'build/compiled/Assets/envmaps/' + base_name + '_radiance' + rad_format = 'jpg' if disable_hdr else 'hdr' - # Assume irradiance has to exist - if os.path.exists('build/compiled/Assets/envmaps/' + base_name + '_irradiance.arm'): - # Cached assets - add_irr_assets(output_file_irr) - if generate_radiance: - add_rad_assets(output_file_rad, rad_format, cached_num_mips) - return cached_num_mips - - # Get paths - user_preferences = bpy.context.user_preferences - addon_prefs = user_preferences.addons['armory'].preferences - sdk_path = addon_prefs.sdk_path + # Assume irradiance has to exist + if os.path.exists('build/compiled/Assets/envmaps/' + base_name + '_irradiance.arm'): + # Cached assets + add_irr_assets(output_file_irr) + if generate_radiance: + add_rad_assets(output_file_rad, rad_format, cached_num_mips) + return cached_num_mips + + # Get paths + user_preferences = bpy.context.user_preferences + addon_prefs = user_preferences.addons['armory'].preferences + sdk_path = addon_prefs.sdk_path - if utils.get_os() == 'win': - cmft_path = sdk_path + '/armory/tools/cmft/cmft.exe' - kraffiti_path = sdk_path + '/kode_studio/KodeStudio-win32/resources/app/extensions/kha/Kha/Kore/Tools/kraffiti/kraffiti.exe' - elif utils.get_os() == 'mac': - cmft_path = sdk_path + '/armory/tools/cmft/cmft-osx' - kraffiti_path = sdk_path + '/kode_studio/"Kode Studio.app"/Contents/Resources/app/extensions/kha/Kha/Kore/Tools/kraffiti/kraffiti-osx' - else: - cmft_path = sdk_path + '/armory/tools/cmft/cmft-linux64' - kraffiti_path = sdk_path + '/kode_studio/KodeStudio-linux64/resources/app/extensions/kha/Kha/Kore/Tools/kraffiti/kraffiti-linux64' - - generated_files = [] - output_gama_numerator = '1.0' if disable_hdr else '2.2' - input_file = utils.get_fp() + image_filepath #'Assets/' + image_name - - # Get input size - output = subprocess.check_output([ \ - kraffiti_path + \ - ' from=' + input_file + \ - ' donothing'], shell=True) - # #%ix%i - image_w = str(output).split("'")[1] - image_w = image_w[1:] - image_w = image_w.split('x')[0] - image_w = int(image_w) - image_h = image_w / 2 - - # 4096 = 256 face - 6 mips - 1024 latlong - # 2048 = 128 face - 5 mips - 512 latlong - # 1024 = 64 face - 4 mips - # 512 = 32 face - 3 mips - # 256 = 16 face - 2 mips - # 128 = 8 face - 1 mip - mip_count = 1 - num = 128 - while num < image_w: - num *= 2 - mip_count += 1 + if utils.get_os() == 'win': + cmft_path = sdk_path + '/armory/tools/cmft/cmft.exe' + kraffiti_path = sdk_path + '/kode_studio/KodeStudio-win32/resources/app/extensions/kha/Kha/Kore/Tools/kraffiti/kraffiti.exe' + elif utils.get_os() == 'mac': + cmft_path = sdk_path + '/armory/tools/cmft/cmft-osx' + kraffiti_path = sdk_path + '/kode_studio/"Kode Studio.app"/Contents/Resources/app/extensions/kha/Kha/Kore/Tools/kraffiti/kraffiti-osx' + else: + cmft_path = sdk_path + '/armory/tools/cmft/cmft-linux64' + kraffiti_path = sdk_path + '/kode_studio/KodeStudio-linux64/resources/app/extensions/kha/Kha/Kore/Tools/kraffiti/kraffiti-linux64' + + generated_files = [] + output_gama_numerator = '1.0' if disable_hdr else '2.2' + input_file = utils.get_fp() + image_filepath #'Assets/' + image_name + + # Get input size + output = subprocess.check_output([ \ + kraffiti_path + \ + ' from=' + input_file + \ + ' donothing'], shell=True) + # #%ix%i + image_w = str(output).split("'")[1] + image_w = image_w[1:] + image_w = image_w.split('x')[0] + image_w = int(image_w) + image_h = image_w / 2 + + # 4096 = 256 face - 6 mips - 1024 latlong + # 2048 = 128 face - 5 mips - 512 latlong + # 1024 = 64 face - 4 mips + # 512 = 32 face - 3 mips + # 256 = 16 face - 2 mips + # 128 = 8 face - 1 mip + mip_count = 1 + num = 128 + while num < image_w: + num *= 2 + mip_count += 1 - face_size = image_w / 16 - src_face_size = str(face_size) - dst_face_size = str(face_size) - - # Generate irradiance - gama_options = '' - if disable_hdr: - gama_options = \ - ' --inputGammaNumerator 2.2' + \ - ' --inputGammaDenominator 1.0' + \ - ' --outputGammaNumerator 1.0' + \ - ' --outputGammaDenominator ' + output_gama_numerator - - # Irradiance spherical harmonics - subprocess.call([ \ - cmft_path + \ - ' --input ' + input_file + \ - ' --filter shcoeffs' + \ - #gama_options + \ - ' --outputNum 1' + \ - ' --output0 ' + output_file_irr], shell=True) - - sh_to_json(output_file_irr) - # Non cached assets - add_irr_assets(output_file_irr) - - # Mip-mapped radiance image - if generate_radiance == False: - return cached_num_mips + face_size = image_w / 16 + src_face_size = str(face_size) + dst_face_size = str(face_size) + + # Generate irradiance + gama_options = '' + if disable_hdr: + gama_options = \ + ' --inputGammaNumerator 2.2' + \ + ' --inputGammaDenominator 1.0' + \ + ' --outputGammaNumerator 1.0' + \ + ' --outputGammaDenominator ' + output_gama_numerator + + # Irradiance spherical harmonics + subprocess.call([ \ + cmft_path + \ + ' --input ' + input_file + \ + ' --filter shcoeffs' + \ + #gama_options + \ + ' --outputNum 1' + \ + ' --output0 ' + output_file_irr], shell=True) + + sh_to_json(output_file_irr) + # Non cached assets + add_irr_assets(output_file_irr) + + # Mip-mapped radiance image + if generate_radiance == False: + return cached_num_mips - output = subprocess.check_output([ \ - kraffiti_path + \ - ' from=' + input_file + \ - ' to=' + output_file_rad + '.' + rad_format + \ - ' format=' + rad_format + \ - ' scale=0.5'], shell=True) + output = subprocess.check_output([ \ + kraffiti_path + \ + ' from=' + input_file + \ + ' to=' + output_file_rad + '.' + rad_format + \ + ' format=' + rad_format + \ + ' scale=0.5'], shell=True) - subprocess.call([ \ - cmft_path + \ - ' --input ' + input_file + \ - ' --filter radiance' + \ - ' --dstFaceSize ' + dst_face_size + \ - ' --srcFaceSize ' + src_face_size + \ - ' --excludeBase false' + \ - ' --mipCount ' + str(mip_count) + \ - ' --glossScale 7' + \ - ' --glossBias 3' + \ - ' --lightingModel blinnbrdf' + \ - ' --edgeFixup none' + \ - ' --numCpuProcessingThreads 4' + \ - ' --useOpenCL true' + \ - ' --clVendor anyGpuVendor' + \ - ' --deviceType gpu' + \ - ' --deviceIndex 0' + \ - ' --generateMipChain false' + \ - ' --inputGammaNumerator 2.2' + \ - ' --inputGammaDenominator 1.0' + \ - ' --outputGammaNumerator 1.0' + \ - ' --outputGammaDenominator ' + output_gama_numerator + \ - ' --outputNum 1' + \ - ' --output0 ' + output_file_rad + \ - ' --output0params hdr,rgbe,latlong'], shell=True) - - # Remove size extensions in file name - mip_w = int(face_size * 4) - mip_h = int(face_size * 2) - mip_base = output_file_rad + '_' - mip_num = 0 - while mip_w >= 32: - mip_name = mip_base + str(mip_num) - os.rename( - mip_name + '_' + str(mip_w) + 'x' + str(mip_h) + '.hdr', - mip_name + '.hdr') - mip_w = int(mip_w / 2) - mip_h = int(mip_h / 2) - mip_num += 1 + subprocess.call([ \ + cmft_path + \ + ' --input ' + input_file + \ + ' --filter radiance' + \ + ' --dstFaceSize ' + dst_face_size + \ + ' --srcFaceSize ' + src_face_size + \ + ' --excludeBase false' + \ + ' --mipCount ' + str(mip_count) + \ + ' --glossScale 7' + \ + ' --glossBias 3' + \ + ' --lightingModel blinnbrdf' + \ + ' --edgeFixup none' + \ + ' --numCpuProcessingThreads 4' + \ + ' --useOpenCL true' + \ + ' --clVendor anyGpuVendor' + \ + ' --deviceType gpu' + \ + ' --deviceIndex 0' + \ + ' --generateMipChain false' + \ + ' --inputGammaNumerator 2.2' + \ + ' --inputGammaDenominator 1.0' + \ + ' --outputGammaNumerator 1.0' + \ + ' --outputGammaDenominator ' + output_gama_numerator + \ + ' --outputNum 1' + \ + ' --output0 ' + output_file_rad + \ + ' --output0params hdr,rgbe,latlong'], shell=True) + + # Remove size extensions in file name + mip_w = int(face_size * 4) + mip_h = int(face_size * 2) + mip_base = output_file_rad + '_' + mip_num = 0 + while mip_w >= 32: + mip_name = mip_base + str(mip_num) + os.rename( + mip_name + '_' + str(mip_w) + 'x' + str(mip_h) + '.hdr', + mip_name + '.hdr') + mip_w = int(mip_w / 2) + mip_h = int(mip_h / 2) + mip_num += 1 - # Append mips - for i in range(0, mip_count): - generated_files.append(output_file_rad + '_' + str(i)) - - # Convert to jpgs - if disable_hdr is True: - for f in generated_files: - subprocess.call([ \ - kraffiti_path + \ - ' from=' + f + '.hdr' + \ - ' to=' + f + '.jpg' + \ - ' format=jpg'], shell=True) - os.remove(f + '.hdr') - - # Scale from (32x16 to 1x1> - for i in range (0, 5): - last = generated_files[-1] - out = output_file_rad + '_' + str(mip_count + i) - subprocess.call([ \ - kraffiti_path + \ - ' from=' + last + '.' + rad_format + \ - ' to=' + out + '.' + rad_format + \ - ' scale=0.5' + \ - ' format=' + rad_format], shell=True) - generated_files.append(out) - - mip_count += 5 + # Append mips + for i in range(0, mip_count): + generated_files.append(output_file_rad + '_' + str(i)) + + # Convert to jpgs + if disable_hdr is True: + for f in generated_files: + subprocess.call([ \ + kraffiti_path + \ + ' from=' + f + '.hdr' + \ + ' to=' + f + '.jpg' + \ + ' format=jpg'], shell=True) + os.remove(f + '.hdr') + + # Scale from (32x16 to 1x1> + for i in range (0, 5): + last = generated_files[-1] + out = output_file_rad + '_' + str(mip_count + i) + subprocess.call([ \ + kraffiti_path + \ + ' from=' + last + '.' + rad_format + \ + ' to=' + out + '.' + rad_format + \ + ' scale=0.5' + \ + ' format=' + rad_format], shell=True) + generated_files.append(out) + + mip_count += 5 - # Non cached assets - add_rad_assets(output_file_rad, rad_format, mip_count) + # Non cached assets + add_rad_assets(output_file_rad, rad_format, mip_count) - return mip_count + return mip_count # Parse sh coefs produced by cmft into json array def sh_to_json(sh_file): - sh_lines = open(sh_file + '.c').read().splitlines() - band0_line = sh_lines[5] - band1_line = sh_lines[6] - band2_line = sh_lines[7] - - irradiance_floats = [] - parse_band_floats(irradiance_floats, band0_line) - parse_band_floats(irradiance_floats, band1_line) - parse_band_floats(irradiance_floats, band2_line) - - sh_json = {} - sh_json['irradiance'] = irradiance_floats - utils.write_arm(sh_file + '.arm', sh_json) - - # Clean up .c - os.remove(sh_file + '.c') + sh_lines = open(sh_file + '.c').read().splitlines() + band0_line = sh_lines[5] + band1_line = sh_lines[6] + band2_line = sh_lines[7] + + irradiance_floats = [] + parse_band_floats(irradiance_floats, band0_line) + parse_band_floats(irradiance_floats, band1_line) + parse_band_floats(irradiance_floats, band2_line) + + sh_json = {} + sh_json['irradiance'] = irradiance_floats + utils.write_arm(sh_file + '.arm', sh_json) + + # Clean up .c + os.remove(sh_file + '.c') def parse_band_floats(irradiance_floats, band_line): - string_floats = re.findall(r'[-+]?\d*\.\d+|\d+', band_line) - string_floats = string_floats[1:] # Remove 'Band 0/1/2' number - for s in string_floats: - irradiance_floats.append(float(s)) + string_floats = re.findall(r'[-+]?\d*\.\d+|\d+', band_line) + string_floats = string_floats[1:] # Remove 'Band 0/1/2' number + for s in string_floats: + irradiance_floats.append(float(s)) def write_sky_irradiance(base_name): - # Predefined fake spherical harmonics for now - irradiance_floats = [1.0281457342829743,1.1617608778901902,1.3886220898440544,-0.13044863139637752,-0.2794659158733846,-0.5736106907295643,0.04065421813873111,0.0434367391348577,0.03567450494792305,0.10964557605577738,0.1129839085793664,0.11261660812141877,-0.08271974283263238,-0.08068091195339556,-0.06432614970480094,-0.12517787967665814,-0.11638582546310804,-0.09743696224655113,0.20068697715947176,0.2158788783296805,0.2109374396869599,0.19636637427150455,0.19445523113118082,0.17825330699680575,0.31440860839538637,0.33041120060402407,0.30867788630062676] - - if not os.path.exists('build/compiled/Assets/envmaps'): - os.makedirs('build/compiled/Assets/envmaps') - - output_file = 'build/compiled/Assets/envmaps/' + base_name + '_irradiance' - - sh_json = {} - sh_json['irradiance'] = irradiance_floats - utils.write_arm(output_file + '.arm', sh_json) + # Predefined fake spherical harmonics for now + irradiance_floats = [1.0281457342829743,1.1617608778901902,1.3886220898440544,-0.13044863139637752,-0.2794659158733846,-0.5736106907295643,0.04065421813873111,0.0434367391348577,0.03567450494792305,0.10964557605577738,0.1129839085793664,0.11261660812141877,-0.08271974283263238,-0.08068091195339556,-0.06432614970480094,-0.12517787967665814,-0.11638582546310804,-0.09743696224655113,0.20068697715947176,0.2158788783296805,0.2109374396869599,0.19636637427150455,0.19445523113118082,0.17825330699680575,0.31440860839538637,0.33041120060402407,0.30867788630062676] + # Hosek + # irradiance_floats = [1.5519331988822218,2.3352207154503266,2.997277451988076,0.2673894962434794,0.4305630474135794,0.11331825259716752,-0.04453633521758638,-0.038753175134160295,-0.021302768541875794,0.00055858020486499,0.000371654770334503,0.000126606145406403,-0.000135708721978705,-0.000787399554583089,-0.001550090690860059,0.021947399048903773,0.05453650591711572,0.08783641266630278,0.17053593578630663,0.14734127083304463,0.07775404698816404,-2.6924363189795e-05,-7.9350169701934e-05,-7.559914435231e-05,0.27035455385870993,0.23122918445556914,0.12158817295211832] + # for i in range(0, len(irradiance_floats)): + # irradiance_floats[i] /= 2; - assets.add(output_file + '.arm') + if not os.path.exists('build/compiled/Assets/envmaps'): + os.makedirs('build/compiled/Assets/envmaps') + + output_file = 'build/compiled/Assets/envmaps/' + base_name + '_irradiance' + + sh_json = {} + sh_json['irradiance'] = irradiance_floats + utils.write_arm(output_file + '.arm', sh_json) + + assets.add(output_file + '.arm') def write_color_irradiance(base_name, col): - # Constant color - irradiance_floats = [col[0], col[1], col[2]] - for i in range(0, 24): - irradiance_floats.append(0.0) - - if not os.path.exists('build/compiled/Assets/envmaps'): - os.makedirs('build/compiled/Assets/envmaps') - - output_file = 'build/compiled/Assets/envmaps/' + base_name + '_irradiance' - - sh_json = {} - sh_json['irradiance'] = irradiance_floats - utils.write_arm(output_file + '.arm', sh_json) + # Constant color + irradiance_floats = [col[0], col[1], col[2]] + for i in range(0, 24): + irradiance_floats.append(0.0) + + if not os.path.exists('build/compiled/Assets/envmaps'): + os.makedirs('build/compiled/Assets/envmaps') + + output_file = 'build/compiled/Assets/envmaps/' + base_name + '_irradiance' + + sh_json = {} + sh_json['irradiance'] = irradiance_floats + utils.write_arm(output_file + '.arm', sh_json) - assets.add(output_file + '.arm') + assets.add(output_file + '.arm') diff --git a/raw/blur_adaptive_pass/blur_adaptive_pass.frag.glsl b/raw/blur_adaptive_pass/blur_adaptive_pass.frag.glsl index 0d07f7da..a2674a72 100644 --- a/raw/blur_adaptive_pass/blur_adaptive_pass.frag.glsl +++ b/raw/blur_adaptive_pass/blur_adaptive_pass.frag.glsl @@ -22,7 +22,7 @@ vec2 unpackFloat(float f) { void main() { vec2 tc = texCoord * ssrTextureScale; - float roughness = unpackFloat(texture(gbuffer0, texCoord).b).x; + float roughness = unpackFloat(texture(gbuffer0, texCoord).b).y; if (roughness == 0.0) { outColor = texture(tex, tc); // outColor = vec4(0.0, 0.0, 0.0, 1.0); diff --git a/raw/compositor_pass/compositor_pass.frag.glsl b/raw/compositor_pass/compositor_pass.frag.glsl index 812e7c99..11893c18 100644 --- a/raw/compositor_pass/compositor_pass.frag.glsl +++ b/raw/compositor_pass/compositor_pass.frag.glsl @@ -60,17 +60,19 @@ vec3 getPos(float depth) { // const vec3 compoFogColor = vec3(0.5, 0.6, 0.7); // const float compoFogAmountA = 1.0; // b = 0.01 // const float compoFogAmountB = 1.0; // c = 0.1 -vec3 applyFog(vec3 rgb, // original color of the pixel - float distance, // camera to point distance - vec3 rayOri, // camera position - vec3 rayDir) { // camera to point vector - float fogAmount = compoFogAmountB * exp(-rayOri.y * compoFogAmountA) * (1.0 - exp(-distance * rayDir.y * compoFogAmountA)) / rayDir.y; - return mix(rgb, compoFogColor, fogAmount); -} -// vec3 applyFog(vec3 rgb, float distance) { -// float fogAmount = 1.0 - exp(-distance * compoFogAmountA); -// return mix(rgb, compoFogColor, fogAmount); +// vec3 applyFog(vec3 rgb, // original color of the pixel + // float distance, // camera to point distance + // vec3 rayOri, // camera position + // vec3 rayDir) { // camera to point vector + // float fogAmount = compoFogAmountB * exp(-rayOri.y * compoFogAmountA) * (1.0 - exp(-distance * rayDir.y * compoFogAmountA)) / rayDir.y; + // return mix(rgb, compoFogColor, fogAmount); // } +vec3 applyFog(vec3 rgb, float distance) { + // float fogAmount = 1.0 - exp(-distance * compoFogAmountA); + float fogAmount = 1.0 - exp(-distance * 0.0055); + return mix(rgb, vec3(0.4, 0.7, 0.2), fogAmount); + // return mix(rgb, compoFogColor, fogAmount); +} #endif float vignette() { @@ -78,10 +80,11 @@ float vignette() { // dist = smoothstep(vignout + (fstop / vignfade), vignin + (fstop / vignfade), dist); // return clamp(dist, 0.0, 1.0); // vignetting from iq - return 0.4 + 0.6 * pow(16.0 * texCoord.x * texCoord.y * (1.0 - texCoord.x) * (1.0 - texCoord.y), 0.2); + // return 0.4 + 0.6 * pow(16.0 * texCoord.x * texCoord.y * (1.0 - texCoord.x) * (1.0 - texCoord.y), 0.2); + return 0.3 + 0.7 * pow(16.0 * texCoord.x * texCoord.y * (1.0 - texCoord.x) * (1.0 - texCoord.y), 0.2); } -#ifdef _CompoDOF +// #ifdef _CompoDOF vec3 sampleBox(float size) { vec3 color = vec3(texture(tex, vec2(texCoord.x - size, texCoord.y - size)).rgb) * 0.075; color += texture(tex, vec2(texCoord.x, texCoord.y - size)).rgb * 0.1; @@ -94,7 +97,7 @@ vec3 sampleBox(float size) { color += texture(tex, vec2(texCoord.x + size, texCoord.y + size)).rgb * 0.075; return color; } -#endif +// #endif float linearize(float depth) { return -cameraPlane.y * cameraPlane.x / (depth * (cameraPlane.y - cameraPlane.x) - cameraPlane.y); @@ -232,19 +235,25 @@ void main() { #endif #ifdef _CompoDOF - float linDepth = linearize(depth); - float blur_amount = abs(linDepth - compoDOFDistance) / cameraPlane.y; - blur_amount = clamp(blur_amount, 0.0, 1.0); - float blurSize = compoDOFSize * 10000.0 * blur_amount; - vec3 blurredColor = 0.75 * sampleBox(blurSize * 0.5) + 0.25 * sampleBox(blurSize * 1.0); - col.rgb *= (1.0 - blur_amount) + blurredColor * blur_amount; + if (depth < 1.0) { + float linDepth = linearize(depth); + float blur_amount = abs(linDepth - compoDOFDistance) / cameraPlane.y; + // float blur_amount = abs(linDepth - 4.0); + float blurSize = compoDOFSize * blur_amount; + // float blurSize = 0.0005 * blur_amount; + col.rgb = 0.75 * sampleBox(blurSize * 0.5) + 0.25 * sampleBox(blurSize * 1.0); + } #endif #ifdef _CompoFog - vec3 pos = getPos(depth); - float dist = distance(pos, eye); - vec3 eyedir = eyeLook;// normalize(eye + pos); - col.rgb = applyFog(col.rgb, dist, eye, eyedir); + // if (depth < 1.0) { + // vec3 pos = getPos(depth); + // float dist = distance(pos, eye); + float dist = linearize(depth); + // vec3 eyedir = eyeLook;// normalize(eye + pos); + // col.rgb = applyFog(col.rgb, dist, eye, eyedir); + col.rgb = applyFog(col.rgb, dist); + // } #endif #ifdef _CompoGlare diff --git a/raw/debug_normals/debug_normals.frag.glsl b/raw/debug_normals/debug_normals.frag.glsl index 8b826c99..30d9256d 100644 --- a/raw/debug_normals/debug_normals.frag.glsl +++ b/raw/debug_normals/debug_normals.frag.glsl @@ -48,7 +48,7 @@ void main() { // vec3 p = getPos(depth); // vec3 baseColor = g1.rgb; - // vec2 roughmet = unpackFloat(g1.a); - // float roughness = roughmet.x; - // float metalness = roughmet.y; + // vec2 metrough = unpackFloat(g1.a); + // float metalness = metrough.x; + // float roughness = metrough.y; } diff --git a/raw/deferred/depthwrite.vert.glsl b/raw/deferred/depthwrite.vert.glsl index 958ef6db..7281cc5d 100644 --- a/raw/deferred/depthwrite.vert.glsl +++ b/raw/deferred/depthwrite.vert.glsl @@ -31,54 +31,73 @@ in vec3 nor; uniform mat4 LWVP; #ifdef _Skinning - uniform float skinBones[skinMaxBones * 12]; + uniform float skinBones[skinMaxBones * 8]; #endif // out vec4 position; #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif void main() { - #ifdef _Instancing +#ifdef _Instancing vec4 sPos = (vec4(pos + off, 1.0)); #else vec4 sPos = (vec4(pos, 1.0)); #endif #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate #endif gl_Position = LWVP * sPos; diff --git a/raw/deferred/mesh.frag.glsl b/raw/deferred/mesh.frag.glsl index d3f1e9b9..45ac5565 100644 --- a/raw/deferred/mesh.frag.glsl +++ b/raw/deferred/mesh.frag.glsl @@ -77,8 +77,8 @@ in vec4 matColor; #endif float packFloat(float f1, float f2) { - int index = int(f1 * 1000); - float alpha = f2 == 0.0 ? f2 : (f2 - 0.0001); + float index = floor(f1 * 1000.0); // Temporary + float alpha = clamp(f2, 0.0, 1.0 - 0.001); return index + alpha; } @@ -179,7 +179,7 @@ float parallaxShadow(vec3 L, vec2 initialTexCoord, float initialHeight) { // ... // Shadowing factor should be 1 if there were no points under the surface - if(numSamplesUnderSurface < 1) shadowMultiplier = 1; + if (numSamplesUnderSurface < 1) shadowMultiplier = 1; else shadowMultiplier = 1.0 - shadowMultiplier; } return shadowMultiplier; @@ -259,9 +259,9 @@ void main() { } if (dist > 0) mask_probe = 0; } - outColor[0] = vec4(n.xy, packFloat(roughness, metalness), mask_probe); + outColor[0] = vec4(n.xy, packFloat(metalness, roughness), mask_probe); #else - outColor[0] = vec4(n.xy, packFloat(roughness, metalness), mask); + outColor[0] = vec4(n.xy, packFloat(metalness, roughness), mask); #endif outColor[1] = vec4(baseColor.rgb, occ); diff --git a/raw/deferred/mesh.vert.glsl b/raw/deferred/mesh.vert.glsl index e50bec41..0fbd1ea6 100644 --- a/raw/deferred/mesh.vert.glsl +++ b/raw/deferred/mesh.vert.glsl @@ -45,7 +45,8 @@ uniform vec4 albedo_color; uniform mat4 W; #endif #ifdef _Skinning - uniform float skinBones[skinMaxBones * 12]; // Default to 50 + // uniform float skinBones[skinMaxBones * 12]; // Defaults to 50 + uniform float skinBones[skinMaxBones * 8]; // Dual quat #endif #ifdef _Probes uniform mat4 W; // TODO: Conflicts with _HeightTex @@ -78,60 +79,79 @@ out vec4 matColor; #ifdef _Skinning // Geometric Skinning with Approximate Dual Quaternion Blending, Kavan // Based on https://github.com/tcoppex/aer-engine/blob/master/demos/aura/data/shaders/Skinning.glsl -// void getSkinningDualQuat(vec4 weights, inout vec3 v, inout vec3 n) { -// // Retrieve the real and dual part of the dual-quaternions -// mat4 matA, matB; -// vec4 indices = vec4(2.0) * bone; -// matA[0] = skinBones[int(indices.x) + 0]; -// matB[0] = skinBones[int(indices.x) + 1]; -// matA[1] = skinBones[int(indices.y) + 0]; -// matB[1] = skinBones[int(indices.y) + 1]; -// matA[2] = skinBones[int(indices.z) + 0]; -// matB[2] = skinBones[int(indices.z) + 1]; -// matA[3] = skinBones[int(indices.w) + 0]; -// matB[3] = skinBones[int(indices.w) + 1]; -// // Handles antipodality by sticking joints in the same neighbourhood -// weights.xyz *= sign(matA[3] * mat3x4(matA)); -// // Apply weights -// vec4 A = matA * weights; // Real part -// vec4 B = matB * weights; // Dual part -// // Normalize -// float invNormA = 1.0 / length(A); -// A *= invNormA; -// B *= invNormA; -// // Position -// v += 2.0 * cross(A.xyz, cross(A.xyz, v) + A.w * v); // Rotate -// v += 2.0 * (A.w * B.xyz - B.w * A.xyz + cross(A.xyz, B.xyz)); // Translate -// // Normal -// n += 2.0 * cross(A.xyz, cross(A.xyz, n) + A.w * n); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; +} +// mat4 getBoneMat(const int boneIndex) { +// vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], +// skinBones[boneIndex * 12 + 1], +// skinBones[boneIndex * 12 + 2], +// skinBones[boneIndex * 12 + 3]); +// vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], +// skinBones[boneIndex * 12 + 5], +// skinBones[boneIndex * 12 + 6], +// skinBones[boneIndex * 12 + 7]); +// vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], +// skinBones[boneIndex * 12 + 9], +// skinBones[boneIndex * 12 + 10], +// skinBones[boneIndex * 12 + 11]); +// return mat4(v0.x, v0.y, v0.z, v0.w, +// v1.x, v1.y, v1.z, v1.w, +// v2.x, v2.y, v2.z, v2.w, +// 0, 0, 0, 1); +// } +// mat4 getSkinningMat() { +// return weight.x * getBoneMat(int(bone.x)) + +// weight.y * getBoneMat(int(bone.y)) + +// weight.z * getBoneMat(int(bone.z)) + +// weight.w * getBoneMat(int(bone.w)); +// } +// mat3 getSkinningMatVec(const mat4 skinningMat) { +// return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); // } -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); -} #endif void main() { @@ -142,9 +162,19 @@ void main() { vec4 sPos = (vec4(pos, 1.0)); #endif #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + // mat4 skinningMat = getSkinningMat(); + // mat3 skinningMatVec = getSkinningMatVec(skinningMat); + // sPos = sPos * skinningMat; + // vec3 _normal = normalize(mat3(N) * (nor * skinningMatVec)); + + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate + vec3 _normal = normalize(mat3(N) * (nor + 2.0 * cross(skinA.xyz, cross(skinA.xyz, nor) + skinA.w * nor))); +#else + vec3 _normal = normalize(mat3(N) * nor); #endif #ifdef _Probes @@ -173,12 +203,6 @@ void main() { texCoord = tex; #endif -#ifdef _Skinning - vec3 _normal = normalize(mat3(N) * (nor * skinningMatVec)); -#else - vec3 _normal = normalize(mat3(N) * nor); -#endif - matColor = albedo_color; #ifdef _VCols diff --git a/raw/deferred/overlay.vert.glsl b/raw/deferred/overlay.vert.glsl index 5e85ed9c..d2d29f0e 100644 --- a/raw/deferred/overlay.vert.glsl +++ b/raw/deferred/overlay.vert.glsl @@ -54,34 +54,51 @@ out vec3 eyeDir; #endif #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif @@ -92,11 +109,18 @@ void main() { #else vec4 sPos = (vec4(pos, 1.0)); #endif + #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate + vec3 _normal = normalize(mat3(N) * (nor + 2.0 * cross(skinA.xyz, cross(skinA.xyz, nor) + skinA.w * nor))); +#else + vec3 _normal = normalize(mat3(N) * nor); #endif + lPos = LWVP * sPos; mat4 WV = V * W; @@ -117,12 +141,6 @@ void main() { texCoord = tex; #endif -#ifdef _Skinning - vec3 _normal = normalize(mat3(N) * (nor * skinningMatVec)); -#else - vec3 _normal = normalize(mat3(N) * nor); -#endif - matColor = albedo_color; #ifdef _VCols diff --git a/raw/deferred/shadowmap.vert.glsl b/raw/deferred/shadowmap.vert.glsl index a2377afd..6df56803 100644 --- a/raw/deferred/shadowmap.vert.glsl +++ b/raw/deferred/shadowmap.vert.glsl @@ -38,34 +38,51 @@ uniform mat4 LWVP; // out vec4 position; #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif @@ -77,9 +94,11 @@ void main() { #endif #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate #endif gl_Position = LWVP * sPos; diff --git a/raw/deferred/translucent.vert.glsl b/raw/deferred/translucent.vert.glsl index 943c0e0e..e2b7d776 100644 --- a/raw/deferred/translucent.vert.glsl +++ b/raw/deferred/translucent.vert.glsl @@ -53,34 +53,51 @@ out vec4 matColor; #endif #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif @@ -91,11 +108,18 @@ void main() { #else vec4 sPos = (vec4(pos, 1.0)); #endif + #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate + vec3 _normal = normalize(mat3(N) * (nor + 2.0 * cross(skinA.xyz, cross(skinA.xyz, nor) + skinA.w * nor))); +#else + vec3 _normal = normalize(mat3(N) * nor); #endif + lPos = LWVP * sPos; #ifdef _Billboard @@ -115,12 +139,6 @@ void main() { texCoord = tex; #endif -#ifdef _Skinning - vec3 _normal = normalize(mat3(N) * (nor * skinningMatVec)); -#else - vec3 _normal = normalize(mat3(N) * nor); -#endif - matColor = albedo_color; #ifdef _VCols diff --git a/raw/deferred_indirect/deferred_indirect.frag.glsl b/raw/deferred_indirect/deferred_indirect.frag.glsl index 7967b43f..69fdfa43 100644 --- a/raw/deferred_indirect/deferred_indirect.frag.glsl +++ b/raw/deferred_indirect/deferred_indirect.frag.glsl @@ -133,14 +133,14 @@ vec3 shIrradiance(vec3 nor, float scale) { } void main() { - vec4 g0 = texture(gbuffer0, texCoord); // Normal.xy, roughness/metallic, mask + vec4 g0 = texture(gbuffer0, texCoord); // Normal.xy, metallic/roughness, mask vec3 n; n.z = 1.0 - abs(g0.x) - abs(g0.y); n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy); n = normalize(n); - vec2 roughmet = unpackFloat(g0.b); + vec2 metrough = unpackFloat(g0.b); #ifdef _Rad float depth = texture(gbufferD, texCoord).r * 2.0 - 1.0; @@ -155,7 +155,7 @@ void main() { float probeFract = fract(probeFactor); vec3 indirect; #ifdef _Rad - float lod = getMipLevelFromRoughness(roughmet.x); + float lod = getMipLevelFromRoughness(metrough.y); vec3 reflectionWorld = reflect(-v, n); vec2 envCoordRefl = envMapEquirect(reflectionWorld); vec3 prefilteredColor = textureLod(senvmapRadiance, envCoordRefl, lod).rgb; @@ -178,7 +178,7 @@ void main() { vec3 indirect = shIrradiance(n, 2.2) / PI; #ifdef _Rad vec3 reflectionWorld = reflect(-v, n); - float lod = getMipLevelFromRoughness(roughmet.x); + float lod = getMipLevelFromRoughness(metrough.y); vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb; #endif #endif @@ -191,16 +191,16 @@ void main() { #endif vec4 g1 = texture(gbuffer1, texCoord); // Basecolor.rgb, occlusion - vec3 albedo = surfaceAlbedo(g1.rgb, roughmet.y); // g1.rgb - basecolor + vec3 albedo = surfaceAlbedo(g1.rgb, metrough.x); // g1.rgb - basecolor indirect *= albedo; #ifdef _Rad // Indirect specular float dotNV = max(dot(n, v), 0.0); - vec3 f0 = surfaceF0(g1.rgb, roughmet.y); + vec3 f0 = surfaceF0(g1.rgb, metrough.x); - vec2 envBRDF = texture(senvmapBrdf, vec2(roughmet.x, 1.0 - dotNV)).xy; + vec2 envBRDF = texture(senvmapBrdf, vec2(metrough.y, 1.0 - dotNV)).xy; indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y);; #endif diff --git a/raw/deferred_light/deferred_light.frag.glsl b/raw/deferred_light/deferred_light.frag.glsl index fb2cbfee..163e441f 100644 --- a/raw/deferred_light/deferred_light.frag.glsl +++ b/raw/deferred_light/deferred_light.frag.glsl @@ -131,7 +131,24 @@ vec3 specularBRDF(vec3 f0, float roughness, float nl, float nh, float nv, float float a = roughness * roughness; return d_ggx(nh, a) * clamp(v_smithschlick(nl, nv, a), 0.0, 1.0) * f_schlick(f0, vh) / 4.0; } - +// vec3 burleyDiffuseBRDF(vec3 albedo, float roughness, float nv, float nl, float vh) { +// float FD90 = 0.5 + 2.0 * vh * vh * roughness; +// float FdV = 1.0 + (FD90 - 1.0) * pow(1.0 - nv, 5.0); +// float FdL = 1.0 + (FD90 - 1.0) * pow(1.0 - nl, 5.0); +// return albedo * ((1.0 / 3.1415926535) * FdV * FdL); +// } +// vec3 orenNayarDiffuseBRDF(vec3 albedo, float roughness, float nv, float nl, float vh) { +// float a = roughness * roughness; +// float s = a;// / (1.29 + 0.5 * a); +// float s2 = s * s; +// float vl = 2.0 * vh * vh - 1.0; // double angle identity +// float Cosri = vl - nv * nl; +// float C1 = 1.0 - 0.5 * s2 / (s2 + 0.33); +// float test = 1.0; +// if (Cosri >= 0.0) test = (1.0 / (max(nl, nv))); +// float C2 = 0.45 * s2 / (s2 + 0.09) * Cosri * test; +// return albedo / PI * (C1 + C2) * (1.0 + roughness * 0.5); +// } vec3 diffuseBRDF(vec3 albedo, float nl) { // lambert return albedo * nl; // // albedo * max(0.0, nl); @@ -684,7 +701,7 @@ void main() { texCoord += vec2(0.5 / screenSize); // Half pixel offset float depth = texture(gbufferD, texCoord).r * 2.0 - 1.0; - vec4 g0 = texture(gbuffer0, texCoord); // Normal.xy, roughness/metallic, mask + vec4 g0 = texture(gbuffer0, texCoord); // Normal.xy, metallic/roughness, mask vec4 g1 = texture(gbuffer1, texCoord); // Basecolor.rgb, occlusion vec3 n; @@ -694,13 +711,13 @@ void main() { vec3 p = getPos(depth, texCoord); // vec3 p = getPos(depth); - vec2 roughmet = unpackFloat(g0.b); + vec2 metrough = unpackFloat(g0.b); vec3 v = normalize(eye - p.xyz); float dotNV = max(dot(n, v), 0.0); - vec3 albedo = surfaceAlbedo(g1.rgb, roughmet.y); // g1.rgb - basecolor - vec3 f0 = surfaceF0(g1.rgb, roughmet.y); + vec3 albedo = surfaceAlbedo(g1.rgb, metrough.x); // g1.rgb - basecolor + vec3 f0 = surfaceF0(g1.rgb, metrough.x); // Per-light vec3 l; @@ -727,8 +744,10 @@ void main() { #endif // Direct - vec3 direct = diffuseBRDF(albedo, dotNL) + specularBRDF(f0, roughmet.x, dotNL, dotNH, dotNV, dotVH); - + vec3 direct = diffuseBRDF(albedo, dotNL) + specularBRDF(f0, metrough.y, dotNL, dotNH, dotNV, dotVH); + // vec3 direct = orenNayarDiffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH) + specularBRDF(f0, metrough.y, dotNL, dotNH, dotNV, dotVH); + // vec3 direct = burleyDiffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH) + specularBRDF(f0, metrough.y, dotNL, dotNH, dotNV, dotVH); + if (lightType == 2) { // Spot float spotEffect = dot(lightDir, l); if (spotEffect < spotlightCutoff) { @@ -738,10 +757,10 @@ void main() { } // Aniso spec - // float shinyParallel = roughmet.x; + // float shinyParallel = metrough.y; // float shinyPerpendicular = 0.08; // vec3 fiberDirection = vec3(0.0, 1.0, 8.0); - // vec3 direct = diffuseBRDF(albedo, roughmet.x, dotNV, dotNL, dotVH, dotLV) + wardSpecular(n, h, dotNL, dotNV, dotNH, fiberDirection, shinyParallel, shinyPerpendicular); + // vec3 direct = diffuseBRDF(albedo, metrough.y, dotNV, dotNL, dotVH, dotLV) + wardSpecular(n, h, dotNL, dotNV, dotNH, fiberDirection, shinyParallel, shinyPerpendicular); direct = direct * lightColor * lightStrength; @@ -763,7 +782,7 @@ void main() { // float probeFract = fract(probeFactor); // vec3 indirect; // #ifdef _Rad -// float lod = getMipLevelFromRoughness(roughmet.x); +// float lod = getMipLevelFromRoughness(metrough.y); // vec3 reflectionWorld = reflect(-v, n); // vec2 envCoordRefl = envMapEquirect(reflectionWorld); // vec3 prefilteredColor = textureLod(senvmapRadiance, envCoordRefl, lod).rgb; @@ -786,7 +805,7 @@ void main() { // vec3 indirect = shIrradiance(n, 2.2) / PI; // #ifdef _Rad // vec3 reflectionWorld = reflect(-v, n); -// float lod = getMipLevelFromRoughness(roughmet.x); +// float lod = getMipLevelFromRoughness(metrough.y); // vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb; // #endif // #endif @@ -801,7 +820,7 @@ void main() { // #ifdef _Rad // // Indirect specular -// vec2 envBRDF = texture(senvmapBrdf, vec2(roughmet.x, 1.0 - dotNV)).xy; +// vec2 envBRDF = texture(senvmapBrdf, vec2(metrough.y, 1.0 - dotNV)).xy; // indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y);; // #endif // indirect = indirect * envmapStrength;// * lightColor * lightStrength; @@ -832,7 +851,7 @@ void main() { // vec3 p3 = lightPos + ex - ey; // vec3 p4 = lightPos - ex - ey; // float theta = acos(dotNV); - // vec2 tuv = vec2(roughmet.x, theta/(0.5*PI)); + // vec2 tuv = vec2(metrough.y, theta/(0.5*PI)); // tuv = tuv*LUT_SCALE + LUT_BIAS; // vec4 t = texture(sltcMat, tuv); diff --git a/raw/forward/mesh.vert.glsl b/raw/forward/mesh.vert.glsl index fc5c1d42..c7a9597b 100644 --- a/raw/forward/mesh.vert.glsl +++ b/raw/forward/mesh.vert.glsl @@ -6,10 +6,6 @@ precision highp float; #include "../compiled.glsl" -#ifdef _NorTex -#define _Tex -#endif - in vec3 pos; in vec3 nor; #ifdef _BaseTex @@ -37,7 +33,7 @@ uniform mat4 LWVP; uniform vec4 albedo_color; uniform vec3 eye; #ifdef _Skinning - uniform float skinBones[skinMaxBones * 12]; + uniform float skinBones[skinMaxBones * 8]; #endif #ifdef _VR uniform mat4 U; // Undistortion @@ -58,34 +54,51 @@ out vec3 eyeDir; #endif #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif @@ -103,15 +116,15 @@ float distortionFactor(float rSquared) { } // Convert point from world space to undistorted camera space vec4 undistort(mat4 WV, vec4 pos) { - // Go to camera space - pos = WV * pos; - const float nearClip = 0.1; - if (pos.z <= -nearClip) { // Reminder: Forward is -Z - // Undistort the point's coordinates in XY - float r2 = clamp(dot(pos.xy, pos.xy) / (pos.z * pos.z), 0.0, maxRadSq); - pos.xy *= distortionFactor(r2); - } - return pos; + // Go to camera space + pos = WV * pos; + const float nearClip = 0.1; + if (pos.z <= -nearClip) { // Reminder: Forward is -Z + // Undistort the point's coordinates in XY + float r2 = clamp(dot(pos.xy, pos.xy) / (pos.z * pos.z), 0.0, maxRadSq); + pos.xy *= distortionFactor(r2); + } + return pos; } #endif @@ -122,11 +135,18 @@ void main() { #else vec4 sPos = (vec4(pos, 1.0)); #endif + #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate + vec3 _normal = normalize(mat3(N) * (nor + 2.0 * cross(skinA.xyz, cross(skinA.xyz, nor) + skinA.w * nor))); +#else + vec3 _normal = normalize(mat3(N) * nor); #endif + lPos = LWVP * sPos; mat4 WV = V * W; @@ -151,12 +171,6 @@ void main() { texCoord = tex; #endif -#ifdef _Skinning - vec3 _normal = normalize(mat3(N) * (nor * skinningMatVec)); -#else - vec3 _normal = normalize(mat3(N) * nor); -#endif - matColor = albedo_color; #ifdef _VCols diff --git a/raw/forward/overlay.vert.glsl b/raw/forward/overlay.vert.glsl index 5e85ed9c..d2d29f0e 100644 --- a/raw/forward/overlay.vert.glsl +++ b/raw/forward/overlay.vert.glsl @@ -54,34 +54,51 @@ out vec3 eyeDir; #endif #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif @@ -92,11 +109,18 @@ void main() { #else vec4 sPos = (vec4(pos, 1.0)); #endif + #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate + vec3 _normal = normalize(mat3(N) * (nor + 2.0 * cross(skinA.xyz, cross(skinA.xyz, nor) + skinA.w * nor))); +#else + vec3 _normal = normalize(mat3(N) * nor); #endif + lPos = LWVP * sPos; mat4 WV = V * W; @@ -117,12 +141,6 @@ void main() { texCoord = tex; #endif -#ifdef _Skinning - vec3 _normal = normalize(mat3(N) * (nor * skinningMatVec)); -#else - vec3 _normal = normalize(mat3(N) * nor); -#endif - matColor = albedo_color; #ifdef _VCols diff --git a/raw/forward/shadowmap.vert.glsl b/raw/forward/shadowmap.vert.glsl index a2377afd..6df56803 100644 --- a/raw/forward/shadowmap.vert.glsl +++ b/raw/forward/shadowmap.vert.glsl @@ -38,34 +38,51 @@ uniform mat4 LWVP; // out vec4 position; #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif @@ -77,9 +94,11 @@ void main() { #endif #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate #endif gl_Position = LWVP * sPos; diff --git a/raw/hybrid/depthwrite.vert.glsl b/raw/hybrid/depthwrite.vert.glsl index 3a3851d7..2b794b86 100644 --- a/raw/hybrid/depthwrite.vert.glsl +++ b/raw/hybrid/depthwrite.vert.glsl @@ -27,38 +27,55 @@ in vec3 nor; uniform mat4 WVP; #ifdef _Skinning - uniform float skinBones[skinMaxBones * 12]; + uniform float skinBones[skinMaxBones * 8]; #endif #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif @@ -70,9 +87,11 @@ void main() { #endif #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate #endif gl_Position = WVP * sPos; diff --git a/raw/hybrid/mesh.vert.glsl b/raw/hybrid/mesh.vert.glsl index 8a66534c..9c96286f 100644 --- a/raw/hybrid/mesh.vert.glsl +++ b/raw/hybrid/mesh.vert.glsl @@ -34,7 +34,7 @@ uniform mat4 LWVP; uniform vec4 albedo_color; uniform vec3 eye; #ifdef _Skinning - uniform float skinBones[skinMaxBones * 12]; + uniform float skinBones[skinMaxBones * 8]; #endif out vec3 position; @@ -51,34 +51,51 @@ out vec3 eyeDir; #endif #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif @@ -89,11 +106,18 @@ void main() { #else vec4 sPos = (vec4(pos, 1.0)); #endif + #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate + vec3 _normal = normalize(mat3(N) * (nor + 2.0 * cross(skinA.xyz, cross(skinA.xyz, nor) + skinA.w * nor))); +#else + vec3 _normal = normalize(mat3(N) * nor); #endif + lPos = LWVP * sPos; mat4 WV = V * W; @@ -115,12 +139,6 @@ void main() { texCoord = tex; #endif -#ifdef _Skinning - vec3 _normal = normalize(mat3(N) * (nor * skinningMatVec)); -#else - vec3 _normal = normalize(mat3(N) * nor); -#endif - matColor = albedo_color; #ifdef _VCols diff --git a/raw/hybrid/overlay.vert.glsl b/raw/hybrid/overlay.vert.glsl index 5e85ed9c..4f1c3c5d 100644 --- a/raw/hybrid/overlay.vert.glsl +++ b/raw/hybrid/overlay.vert.glsl @@ -37,7 +37,7 @@ uniform mat4 LWVP; uniform vec4 albedo_color; uniform vec3 eye; #ifdef _Skinning - uniform float skinBones[skinMaxBones * 12]; + uniform float skinBones[skinMaxBones * 8]; #endif out vec3 position; @@ -54,34 +54,51 @@ out vec3 eyeDir; #endif #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif @@ -92,11 +109,18 @@ void main() { #else vec4 sPos = (vec4(pos, 1.0)); #endif + #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate + vec3 _normal = normalize(mat3(N) * (nor + 2.0 * cross(skinA.xyz, cross(skinA.xyz, nor) + skinA.w * nor))); +#else + vec3 _normal = normalize(mat3(N) * nor); #endif + lPos = LWVP * sPos; mat4 WV = V * W; @@ -117,12 +141,6 @@ void main() { texCoord = tex; #endif -#ifdef _Skinning - vec3 _normal = normalize(mat3(N) * (nor * skinningMatVec)); -#else - vec3 _normal = normalize(mat3(N) * nor); -#endif - matColor = albedo_color; #ifdef _VCols diff --git a/raw/hybrid/shadowmap.vert.glsl b/raw/hybrid/shadowmap.vert.glsl index 8810d7e0..0527094a 100644 --- a/raw/hybrid/shadowmap.vert.glsl +++ b/raw/hybrid/shadowmap.vert.glsl @@ -28,38 +28,55 @@ in vec3 nor; uniform mat4 LWVP; #ifdef _Skinning - uniform float skinBones[skinMaxBones * 12]; + uniform float skinBones[skinMaxBones * 8]; #endif #ifdef _Skinning -mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 12 + 0], - skinBones[boneIndex * 12 + 1], - skinBones[boneIndex * 12 + 2], - skinBones[boneIndex * 12 + 3]); - vec4 v1 = vec4(skinBones[boneIndex * 12 + 4], - skinBones[boneIndex * 12 + 5], - skinBones[boneIndex * 12 + 6], - skinBones[boneIndex * 12 + 7]); - vec4 v2 = vec4(skinBones[boneIndex * 12 + 8], - skinBones[boneIndex * 12 + 9], - skinBones[boneIndex * 12 + 10], - skinBones[boneIndex * 12 + 11]); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, - 0, 0, 0, 1); -} - -mat4 getSkinningMat() { - return weight.x * getBoneMat(int(bone.x)) + - weight.y * getBoneMat(int(bone.y)) + - weight.z * getBoneMat(int(bone.z)) + - weight.w * getBoneMat(int(bone.w)); -} - -mat3 getSkinningMatVec(const mat4 skinningMat) { - return mat3(skinningMat[0].xyz, skinningMat[1].xyz, skinningMat[2].xyz); +void getSkinningDualQuat(vec4 weights, out vec4 A, inout vec4 B) { + // Retrieve the real and dual part of the dual-quaternions + mat4 matA, matB; + matA[0][0] = skinBones[int(bone.x) * 8 + 0]; + matA[0][1] = skinBones[int(bone.x) * 8 + 1]; + matA[0][2] = skinBones[int(bone.x) * 8 + 2]; + matA[0][3] = skinBones[int(bone.x) * 8 + 3]; + matB[0][0] = skinBones[int(bone.x) * 8 + 4]; + matB[0][1] = skinBones[int(bone.x) * 8 + 5]; + matB[0][2] = skinBones[int(bone.x) * 8 + 6]; + matB[0][3] = skinBones[int(bone.x) * 8 + 7]; + matA[1][0] = skinBones[int(bone.y) * 8 + 0]; + matA[1][1] = skinBones[int(bone.y) * 8 + 1]; + matA[1][2] = skinBones[int(bone.y) * 8 + 2]; + matA[1][3] = skinBones[int(bone.y) * 8 + 3]; + matB[1][0] = skinBones[int(bone.y) * 8 + 4]; + matB[1][1] = skinBones[int(bone.y) * 8 + 5]; + matB[1][2] = skinBones[int(bone.y) * 8 + 6]; + matB[1][3] = skinBones[int(bone.y) * 8 + 7]; + matA[2][0] = skinBones[int(bone.z) * 8 + 0]; + matA[2][1] = skinBones[int(bone.z) * 8 + 1]; + matA[2][2] = skinBones[int(bone.z) * 8 + 2]; + matA[2][3] = skinBones[int(bone.z) * 8 + 3]; + matB[2][0] = skinBones[int(bone.z) * 8 + 4]; + matB[2][1] = skinBones[int(bone.z) * 8 + 5]; + matB[2][2] = skinBones[int(bone.z) * 8 + 6]; + matB[2][3] = skinBones[int(bone.z) * 8 + 7]; + matA[3][0] = skinBones[int(bone.w) * 8 + 0]; + matA[3][1] = skinBones[int(bone.w) * 8 + 1]; + matA[3][2] = skinBones[int(bone.w) * 8 + 2]; + matA[3][3] = skinBones[int(bone.w) * 8 + 3]; + matB[3][0] = skinBones[int(bone.w) * 8 + 4]; + matB[3][1] = skinBones[int(bone.w) * 8 + 5]; + matB[3][2] = skinBones[int(bone.w) * 8 + 6]; + matB[3][3] = skinBones[int(bone.w) * 8 + 7]; + // Handles antipodality by sticking joints in the same neighbourhood + // weights.xyz *= sign(matA[3] * mat3x4(matA)).xyz; + weights.xyz *= sign(matA[3] * matA).xyz; + // Apply weights + A = matA * weights; // Real part + B = matB * weights; // Dual part + // Normalize + float invNormA = 1.0 / length(A); + A *= invNormA; + B *= invNormA; } #endif @@ -71,9 +88,11 @@ void main() { #endif #ifdef _Skinning - mat4 skinningMat = getSkinningMat(); - mat3 skinningMatVec = getSkinningMatVec(skinningMat); - sPos = sPos * skinningMat; + vec4 skinA; + vec4 skinB; + getSkinningDualQuat(weight, skinA, skinB); + sPos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, sPos.xyz) + skinA.w * sPos.xyz); // Rotate + sPos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz)); // Translate #endif gl_Position = LWVP * sPos; diff --git a/raw/ssr_pass/ssr_pass.frag.glsl b/raw/ssr_pass/ssr_pass.frag.glsl index 18cac288..612d02da 100644 --- a/raw/ssr_pass/ssr_pass.frag.glsl +++ b/raw/ssr_pass/ssr_pass.frag.glsl @@ -187,7 +187,7 @@ vec2 unpackFloat(float f) { void main() { vec4 g0 = texture(gbuffer0, texCoord); - float roughness = unpackFloat(g0.b).x; + float roughness = unpackFloat(g0.b).y; if (roughness == 1.0) { outColor = vec4(0.0);