Dual quaternion skinning, mirrors.

This commit is contained in:
Lubos Lenco 2016-08-29 09:56:34 +02:00
parent 8e3c2e0c74
commit f3554b4de8
56 changed files with 1508 additions and 1018 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,3 +0,0 @@
package armory;
typedef Root = iron.Root;

View file

@ -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;

View file

@ -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 {

View file

@ -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;

View file

@ -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);

View file

@ -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) {

View file

@ -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
}
}

View file

@ -31,7 +31,7 @@ class PhysicsDrag extends Trait {
}
function init() {
physics = armory.Scene.physics;
physics = armory.trait.internal.PhysicsWorld.active;
}
function update() {

View file

@ -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);
});
}
}

View file

@ -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;

View file

@ -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() {

View file

@ -11,8 +11,9 @@ class Animation extends Trait {
var speeds:Array<Float>;
var loops:Array<Bool>;
var reflects:Array<Bool>;
static var maxBones:Int;
public function new(startTrack:String, names:Array<String>, starts:Array<Int>, ends:Array<Int>, speeds:Array<Float>, loops:Array<Bool>, reflects:Array<Bool>) {
public function new(startTrack:String, names:Array<String>, starts:Array<Int>, ends:Array<Int>, speeds:Array<Float>, loops:Array<Bool>, reflects:Array<Bool>, _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() {

View file

@ -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 + ")");
}
}

View file

@ -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;

View file

@ -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();

View file

@ -19,6 +19,8 @@ class ContactPair {
class PhysicsWorld extends Trait {
public static var active:PhysicsWorld;
#if (!WITH_PHYSICS)
public function new(gravity:Array<Float> = null) { super(); }
#else
@ -39,6 +41,8 @@ class PhysicsWorld extends Trait {
public function new(gravity:Array<Float> = 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);

View file

@ -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;

Binary file not shown.

View file

@ -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

View file

@ -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':

View file

@ -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

View file

@ -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:

View file

@ -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()

View file

@ -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__)

131
blender/traits_action.py Executable file
View file

@ -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__)

View file

@ -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

View file

@ -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);
});
});
});
}

View file

@ -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')

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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);