Commit for 2022.05.29 22-44-19.7z

This commit is contained in:
mrq 2022-05-29 22:44:00 -05:00
parent cf3d1eebc1
commit 22d18c953c
57 changed files with 1570 additions and 270 deletions

View File

@ -1,16 +1,16 @@
{
"engine": {
"scenes": {
"start": "SS2",
"meshes": { "interleave": false },
"start": "McDonalds",
"meshes": { "interleave": true },
"matrix": { "reverseInfinite": true },
"lights": {
"max": 12,
"max": 16,
"enabled": true
},
"shadows": {
"enabled": true,
"update": 4,
"update": 3,
"max": 6,
"samples": 2,
"experimental mode": 1
@ -48,18 +48,19 @@
"validation": {
"enabled": false,
"filters": [
"MessageID = 0x124ffb34", // VUID-VkImageMemoryBarrier-oldLayout-01197
"MessageID = 0x8ab1932c", // VUID-VkImageViewCreateInfo-imageViewType-04973
"MessageID = 0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps)
"MessageID = 0x609a13b", // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls)
"MessageID = 0x23e43bb7" // UNASSIGNED-CoreValidation-Shader-InputNotProduced (from depth-only calls)
// "MessageID = 0xe91b58a0" // VUID-vkCmdDrawIndexed-None-02686 (?)
// "MessageID = 0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup)
// "MessageID = 0x124ffb34", // VUID-VkImageMemoryBarrier-oldLayout-01197 (hacky bloom-shit)
// "MessageID = 0x8ab1932c", // VUID-VkImageViewCreateInfo-imageViewType-04973 (hacky bloom-shit)
// "MessageID = 0x8e1000ad", // VUID-vkCmdDrawIndexedIndirect-None-04008 (bitches without nullDescriptor)
// "MessageID = 0x9dd97212", // VUID-vkCmdDrawIndexedIndirect-None-02721 (bitches without nullDescriptor)
// "MessageID = 0x36481fcb", // VUID-vkCmdBindVertexBuffers-pBuffers-04001 (bitches without nullDescriptor)
"MessageID = 0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps)
// "MessageID = 0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup)
"MessageID = 0x609a13b", // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls)
"MessageID = 0x23e43bb7" // UNASSIGNED-CoreValidation-Shader-InputNotProduced (from depth-only calls)
// "MessageID = 0xe91b58a0" // VUID-vkCmdDrawIndexed-None-02686 (?)
]
},
"framebuffer": {
@ -237,6 +238,9 @@
"entity": {
"delete children on destroy": true,
"delete components on destroy": true
},
"loader": {
"assert": true
}
}
},

View File

@ -30,10 +30,11 @@
"resolution": 8192,
"shadows": 1024,
"layers": 1,
"trigger": { "mode": "rendered" },
"trigger": { "mode": "rendered", "quit": true },
// "trigger": { "mode": "key", "value": "B" },
"output": "./lightmap.%i.png"
},
"grid": {
"-grid": {
"/^worldspawn/": {
"size": [6,6,6],
// "epsilon": 0.01,

View File

@ -0,0 +1,16 @@
{
"name": "Craeture",
"behaviors": [ "CraetureBehavior" ],
"assets": [
"./textures/craeture.jpg"
],
"transform": {
"position": [9.62326, 1.1872, -40.8126],
"scale": [8, 8, 8]
},
"metadata": {
"model": {
"cull mode": "none"
}
}
}

View File

@ -0,0 +1,9 @@
{
"assets": ["./scripts/door.lua"],
"system": {
"physics": {
"type": "bounding box",
"recenter": true
}
}
}

View File

@ -0,0 +1,32 @@
{
"name": "Gui: Loading",
"type": "Object",
"behaviors": [
// "GuiBehavior"
],
"assets": [
{ "filename": "./mcdonalds.json", "delay": 0 }
],
"ignore": false,
"transform": {
"position": [ -0.830591, -0.699509, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 0.258737, 0.115371, 1 ]
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 0.1 ],
"location": "",
"scaling": "relative",
"text settings": {
"stroke": [ 1, 0.749, 0.368, 1 ],
"color": [ 1, 0.749, 0.368, 1 ],
"string": "Loading...",
"string1": "コマンド"
}
}
}

View File

@ -0,0 +1,24 @@
{
"name": "Marker",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 0.8 ],
"location": "",
"scaling": [ 1, 1 ],
"world": true,
"gui layer": false
},
"assets": [
"https://cdn..xyz//unity/Android/sprite/sprite_magiccircle_in2.png"
]
}

View File

@ -0,0 +1,47 @@
{
"import": "/model.json",
"assets": [
// { "filename": "./static.json", "delay": 8 },
// { "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false }
// { "filename": "./models/mcdonalds/graph.json", "delay": 0, "single threaded": false, "category": "models" }
{ "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/mini_mcd.glb", "delay": 0, "single threaded": false }
// { "filename": "./models/mini_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
],
"metadata": {
"model": {
"lightmap": true,
"baking": {
"enabled": true,
"resolution": 2048
},
"cull mode": "none",
"tags": {
"/^worldspawn/": {
"physics": { "type": "mesh", "static": true },
"grid": { "size": [3,2,3], "epsilon": 1.0, "cleanup": true, "print": true }
},
"info_player_spawn": { "action": "attach", "filename": "./player.json", "preserve orientation": true },
"func_door_rotating_5409": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5487": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } },
"func_door_rotating_5495": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } },
"func_door_rotating_5568": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5568": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5576": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5584": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5656": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } },
"func_door_rotating_5664": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5689": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5698": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5712": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_physbox_5212": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_physbox_5548": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_physbox_5931": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }
}
}
}
}

View File

@ -0,0 +1,19 @@
{
"import": "/player.json",
"assets": [
// { "filename": "/gui/hud/hud.json", "delay": 0 }
],
"metadata": {
"overlay": {
"floating": true
},
"collider": true,
"light": {
"should": false,
"color": [1, 1, 1],
"position": [ 0, 2.5, 0 ],
"power": 1,
"radius": [0.001, 32]
}
}
}

View File

@ -0,0 +1,60 @@
{
"import": "/scene.json",
"assets": [
"./audio/soundscape/ambience.ogg",
"./loading.json",
"./static.json"
],
"system": {
"hot reload": {
"enabled": true
},
"renderer": {
"shader": {
"mode": 1,
"scalar": 16,
"parameters": [ 0, 0, 0, "time" ]
},
"clear values": [
[ 1, 1, 1, 0 ]
]
}
},
"metadata": {
"menus": {
"pause": "/gui/pause/menu.json"
},
"bloom": {
"scale": 6.0,
"strength": 0.125,
"sigma": 0.125,
"samples": 8
},
"light": {
"exposure": 1.0,
"gamma": 1.0,
"brightnessThreshold": 1.2,
// "ambient": [ 0.1, 0.1, 0.1 ],
"ambient": [ 0, 0, 0 ],
"fog-": {
"color": [ 0.5, 0.5, 0.5 ],
"range": [ 16, 32 ],
"step scale": 2,
"absorbtion": 0.07,
"density": {
"threshold": 0.35,
"multiplier": 5.0,
"scale": 25.0,
"offset": [0, -1, 1],
"timescale": 8
}
},
"should": true,
"shadows": true
},
"noise": {
"size": [ 64, 64, 64 ]
}
}
}

View File

@ -0,0 +1,110 @@
local scene = entities.currentScene()
local controller = entities.controller()
local timer = Timer.new()
if not timer:running() then
timer:start();
end
local polarity = 1
local state = 0
local targetAlpha = 1
local alpha = 0
local target = Vector3f(0,0,0)
local transform = ent:getComponent("Transform")
local metadata = ent:getComponent("Metadata")
local speed = metadata["speed"] or 1.0
local normal = Vector3f(0,0,-1)
if metadata["normal"] ~= nil then
local sign = -1
if metadata["angle"] < 0 then sign = 1 end
normal = Vector3f( metadata["normal"][1] * sign, metadata["normal"][2] * sign, metadata["normal"][3] * sign ):normalize()
end
local starting = Quaternion(transform.orientation)
local ending = transform.orientation:multiply(Quaternion.axisAngle( Vector3f(0,1,0), metadata["angle"] ))
local soundEmitter = ent:loadChild("./sound.json",true)
local playSound = function( key, loop )
if not loop then loop = false end
local url = "/door/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Emit.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"]),
spatial = true,
streamed = true,
volume = "sfx",
loop = loop
}, 0)
end
local stopSound = function( key )
local url = "/door/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Stop.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"])
}, 0)
end
local playSoundscape = function( key )
local url = "/soundscape/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Emit.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"]),
spatial = false,
volume = "sfx",
loop = true,
streamed = true
}, 0)
end
local stopSoundscape = function( key )
local url = "/soundscape/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Stop.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"])
}, 0)
end
soundEmitter:getComponent("Transform"):setReference( transform )
-- on tick
ent:bind( "tick", function(self)
-- transform.orientation = starting:slerp( ending, math.cos(time.current() * speed) * 0.5 + 0.5 )
if state == 1 then
alpha = alpha + time.delta() * speed
if alpha > targetAlpha then
state = 2
alpha = targetAlpha
playSound("default_stop")
end
end
if state == 3 then
alpha = alpha - time.delta() * speed
if alpha < 0 then
state = 0
alpha = 0
playSound("default_stop")
end
end
if state > 0 then
transform.orientation = starting:slerp( ending, alpha * polarity )
end
end )
-- on use
ent:addHook( "entity:Use.%UID%", function( payload )
if state == 0 then
state = 1
playSound("default_move")
if payload.uid ~= nil then
local player = entities.get( payload.uid )
local pTransform = player:getComponent("Transform")
local delta = transform.position - pTransform.position
local side = normal:dot(delta)
if side > 0 then
polarity = 1
elseif side < 0 then
polarity = -1
end
end
io.print(ent:name())
end
if state == 2 then
state = 3
playSound("default_move")
end
io.print( state, json.encode( payload ) )
end )

View File

@ -0,0 +1,22 @@
local scene = entities.currentScene()
local controller = entities.controller()
local timer = Timer.new()
if not timer:running() then
timer:start();
end
local transform = ent:getComponent("Transform")
-- on tick
ent:bind( "tick", function(self)
local offset = Vector3f(0,0,0)
if window.keyPressed("J") then offset.x = offset.x - time.delta() end
if window.keyPressed("L") then offset.x = offset.x + time.delta() end
if window.keyPressed("N") then offset.y = offset.y - time.delta() end
if window.keyPressed("M") then offset.y = offset.y + time.delta() end
if window.keyPressed("I") then offset.z = offset.z - time.delta() end
if window.keyPressed("K") then offset.z = offset.z + time.delta() end
if offset:magnitude() > 0.0001 then
transform.position = transform.position + offset
end
end )

View File

@ -0,0 +1,90 @@
local scene = entities.currentScene()
local controller = entities.controller()
local timer = Timer.new()
if not timer:running() then
timer:start();
end
-- release control
--[[
hooks.call("window:Mouse.CursorVisibility", { state = true })
hooks.call("window:Mouse.Lock", {});
]]
-- on tick
ent:bind( "tick", function(self)
-- update static effect
local metadatas = {
ent = ent:getComponent("Metadata"),
scene = scene:getComponent("Metadata")
}
local transforms = {
ent = ent:getComponent("Transform"),
controller = controller:getComponent("Transform")
}
local distanceSquared = transforms.controller.position:distance( transforms.ent.position )
distanceSquared = distanceSquared * distanceSquared
if type(metadatas.ent["static"]["scale"]) == "number" then
distanceSquared = distanceSquared * metadatas.ent["static"]["scale"]
end
local lo = type(metadatas.ent["static"]["range"][1]) == "number" and metadatas.ent["static"]["range"][1] or 0.1
local hi = type(metadatas.ent["static"]["range"][2]) == "number" and metadatas.ent["static"]["range"][2] or 0.5
local staticBlend = distanceSquared > 1 and 1.0 / distanceSquared or 1.0
staticBlend = math.clamp( staticBlend, lo, hi )
local flicker = type(metadatas.ent["static"]["flicker"]) == "number" and metadatas.ent["static"]["flicker"] or 0.001
local pieces = type(metadatas.ent["static"]["pieces"]) == "number" and metadatas.ent["static"]["pieces"] or 1000
local payload = {
mode = 2,
parameters = {
[1] = flicker,
[2] = pieces,
[3] = staticBlend,
[4] = "time"
}
}
scene:callHook("shader:Update.%UID%", payload)
end )
--[[
local hud = ent:loadChild("/hud.json", true)
hud:bind( "tick", function(self)
-- update distance HUD element
if timer:elapsed() <= 0.0125 then return end
timer:reset()
local metadata = self:getComponent("Metadata")
local transforms = {
controller = controller:getComponent("Transform"),
source = ent:getComponent("Transform")
}
local distance = transforms.controller.position:distance( transforms.source.position )
--distance = string.si( distance, "m" )
local maximum = 40
local value = math.floor(distance/maximum * 100)
if value >= 100 then value = 100 end
distance = "Sanity: " .. value .. "%"
--distance = math.floor((15-distance)/15 * 100) .. "%"
if metadata["text settings"]["string"] ~= distance then
self:callHook( "gui:UpdateString.%UID%", {
string = distance
} )
end
end )
]]
--[[
local marker = ent:loadChild("./marker.json", true)
marker:bind( "tick", function(self)
local transform = marker:getComponent("Transform")
local parentTransform = ent:getComponent("Transform")
local controllerTransform = controller:getComponent("Transform")
local controllerCamera = controller:getComponent("Camera")
local controllerCameraTransform = controllerCamera:getTransform()
transform.position = parentTransform.position + Vector3f(0,3,0)
transform.orientation = Quaternion.lookAt( transform.position - controllerTransform.position, Vector3f(0,1,0) )
-- transform.orientation = transform.orientation:normalize()
-- transform.model = controllerCamera:getProjection() * controllerCamera:getView() * Matrix4f.translate( transform.position ) * transform.orientation:matrix()
end )
]]

View File

@ -0,0 +1,34 @@
{
"type": "Object",
"name": "Sound Emitter",
"ignore": false,
"assets": [
],
"behaviors": [
"SoundEmitterBehavior"
],
"transform": {
"reference": true
},
"system": {
"hot reload": {
"enabled": true
},
"defaults": {
"render": true,
"asset load": true
},
"load": {
"ignore": true
}
},
"metadata": {
"audio": {
"spatial": true,
"loop": false,
"volume": 1,
"rolloffFactor": 0.5,
"epsilon": 0.5
}
}
}

View File

@ -0,0 +1,48 @@
{
"type": "Object",
"name": "Static Emitter",
"ignore": false,
"assets": [
"/overworld/static.ogg",
"./scripts/static.lua"
],
"behaviors": [
"SoundEmitterBehavior"
],
"transform": {
"position": [ -13.4342, 2.43658, 298.797 ],
"rotation": {
"axis": [ 0, 1, 0 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"system": {
"hot reload": {
"enabled": true
},
"defaults": {
"render": true,
"asset load": true
},
"load": {
"ignore": true
}
},
"metadata": {
"audio": {
"spatial": true,
"loop": true,
"streamed": false,
"volume": 1.6,
"rolloffFactor": 2
},
"static": {
"range": [ 0.0025, 1 ],
"flicker": 0.5,
"pieces": 16,
"scale": 0.4
},
"distance": false
}
}

View File

@ -0,0 +1,16 @@
{
"name": "Craeture",
"behaviors": [ "CraetureBehavior" ],
"assets": [
"./textures/craeture.jpg"
],
"transform": {
"position": [19.9875, 1.54269, -2.97276],
"scale": [1.5, 2, 1.5]
},
"metadata": {
"model": {
"cull mode": "none"
}
}
}

View File

@ -0,0 +1,11 @@
{
"assets": ["./scripts/door.lua"],
"system": {
"physics": {
"mass": 0,
"inertia": [0, 0, 0],
"type": "bounding box",
"recenter": true
}
}
}

View File

@ -0,0 +1,32 @@
{
"name": "Gui: Loading",
"type": "Object",
"behaviors": [
// "GuiBehavior"
],
"assets": [
{ "filename": "./sh2_mcdonalds.json", "delay": 0 }
],
"ignore": false,
"transform": {
"position": [ -0.830591, -0.699509, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 0.258737, 0.115371, 1 ]
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 0.1 ],
"location": "",
"scaling": "relative",
"text settings": {
"stroke": [ 1, 0.749, 0.368, 1 ],
"color": [ 1, 0.749, 0.368, 1 ],
"string": "Loading...",
"string1": "コマンド"
}
}
}

View File

@ -0,0 +1,24 @@
{
"name": "Marker",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 0.8 ],
"location": "",
"scaling": [ 1, 1 ],
"world": true,
"gui layer": false
},
"assets": [
"https://cdn..xyz//unity/Android/sprite/sprite_magiccircle_in2.png"
]
}

View File

@ -0,0 +1,20 @@
{
"import": "/player.json",
"assets": [
// { "filename": "/gui/hud/hud.json", "delay": 0 }
"./playerLight.json"
],
"metadata": {
"overlay": {
"floating": true
},
"collider": true,
"light": {
"should": false,
"color": [1, 1, 1],
"position": [ 0, 2.5, 0 ],
"power": 1,
"radius": [0.001, 32]
}
}
}

View File

@ -0,0 +1,32 @@
{
"import": "/light.json",
"ignore": true,
"assets": [
],
"transform": {
"track": "parent",
"position": [ 0, 1.7, 0 ]
},
"system": {
"hot reload": {
"enabled": true
}
},
"metadata": {
"light": {
"type": "point",
"color": [1, 1, 1],
"power": 15,
"fov": 90,
"bias": {
"constant": 1.25,
"slope": 1.75,
"shader": 0.000005 //0.000000005
},
"radius": [0.001, 0],
"resolution": 1024,
"shadows": false,
"static": false
}
}
}

View File

@ -0,0 +1,11 @@
{
"assets": [],
"system": {
"physics": {
"mass": 0,
"inertia": [0, 0, 0],
"type": "bounding box",
"recenter": true
}
}
}

View File

@ -0,0 +1,60 @@
{
"import": "/scene.json",
"assets": [
"./audio/soundscape/ambience.ogg",
"./loading.json"
// "./static.json"
],
"system": {
"hot reload": {
"enabled": true
},
"renderer": {
"shader": {
"mode": 1,
"scalar": 16,
"parameters": [ 0, 0, 0, "time" ]
},
"clear values": [
[ 1, 1, 1, 0 ]
]
}
},
"metadata": {
"menus": {
"pause": "/gui/pause/menu.json"
},
"bloom": {
"scale": 1.0,
"strength": 1.0,
"sigma": 2.0,
"samples": 2
},
"light": {
"exposure": 1.0,
"gamma": 1.0,
"brightnessThreshold": 1.2,
"ambient": [ 0.15, 0.15, 0.15 ],
"fog": {
"color": [ 0.5, 0.5, 0.5 ],
"range": [ 8, 256 ],
"step scale": 2,
"absorbtion": 0.07,
"density": {
"threshold": 0.35,
"multiplier": 5.0,
"scale": 25.0,
"offset": [0.2, 0, 1],
"timescale": 8
}
},
"should": true,
"shadows": true
},
"noise": {
"size": [ 16, 16, 16 ]
}
}
}

View File

@ -0,0 +1,107 @@
local scene = entities.currentScene()
local controller = entities.controller()
local timer = Timer.new()
if not timer:running() then
timer:start();
end
local polarity = 1
local state = 0
local targetAlpha = 1
local alpha = 0
local target = Vector3f(0,0,0)
local transform = ent:getComponent("Transform")
local metadata = ent:getComponent("Metadata")
local speed = metadata["speed"] or 1.0
local normal = Vector3f(0,0,-1)
if metadata["normal"] ~= nil then
local sign = -1
if metadata["angle"] < 0 then sign = 1 end
normal = Vector3f( metadata["normal"][1] * sign, metadata["normal"][2] * sign, metadata["normal"][3] * sign ):normalize()
end
local starting = Quaternion(transform.orientation)
local ending = transform.orientation:multiply(Quaternion.axisAngle( Vector3f(0,1,0), metadata["angle"] ))
local soundEmitter = ent:loadChild("./sound.json",true)
local playSound = function( key, loop )
if not loop then loop = false end
local url = "/door/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Emit.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"]),
spatial = true,
streamed = true,
volume = "sfx",
loop = loop
}, 0)
end
local stopSound = function( key )
local url = "/door/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Stop.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"])
}, 0)
end
local playSoundscape = function( key )
local url = "/soundscape/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Emit.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"]),
spatial = false,
volume = "sfx",
loop = true,
streamed = true
}, 0)
end
local stopSoundscape = function( key )
local url = "/soundscape/" .. key .. ".ogg"
soundEmitter:queueHook("sound:Stop.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"])
}, 0)
end
soundEmitter:getComponent("Transform"):setReference( transform )
-- on tick
ent:bind( "tick", function(self)
-- transform.orientation = starting:slerp( ending, math.cos(time.current() * speed) * 0.5 + 0.5 )
if state == 1 then
alpha = alpha + time.delta() * speed
if alpha > targetAlpha then
state = 2
alpha = targetAlpha
playSound("default_stop")
end
end
if state == 3 then
alpha = alpha - time.delta() * speed
if alpha < 0 then
state = 0
alpha = 0
playSound("default_stop")
end
end
if state > 0 then
transform.orientation = starting:slerp( ending, alpha * polarity )
end
end )
-- on use
ent:addHook( "entity:Use.%UID%", function( payload )
if state == 0 or state == 3 then
state = 1
playSound("default_move")
if payload.uid ~= nil then
local player = entities.get( payload.uid )
local pTransform = player:getComponent("Transform")
local delta = transform.position - pTransform.position
local side = normal:dot(delta)
if side > 0 then
polarity = 1
elseif side < 0 then
polarity = -1
end
end
elseif state == 2 or state == 1 then
state = 3
playSound("default_move")
end
end )

View File

@ -0,0 +1,22 @@
local scene = entities.currentScene()
local controller = entities.controller()
local timer = Timer.new()
if not timer:running() then
timer:start();
end
local transform = ent:getComponent("Transform")
-- on tick
ent:bind( "tick", function(self)
local offset = Vector3f(0,0,0)
if window.keyPressed("J") then offset.x = offset.x - time.delta() end
if window.keyPressed("L") then offset.x = offset.x + time.delta() end
if window.keyPressed("N") then offset.y = offset.y - time.delta() end
if window.keyPressed("M") then offset.y = offset.y + time.delta() end
if window.keyPressed("I") then offset.z = offset.z - time.delta() end
if window.keyPressed("K") then offset.z = offset.z + time.delta() end
if offset:magnitude() > 0.0001 then
transform.position = transform.position + offset
end
end )

View File

@ -0,0 +1,90 @@
local scene = entities.currentScene()
local controller = entities.controller()
local timer = Timer.new()
if not timer:running() then
timer:start();
end
-- release control
--[[
hooks.call("window:Mouse.CursorVisibility", { state = true })
hooks.call("window:Mouse.Lock", {});
]]
-- on tick
ent:bind( "tick", function(self)
-- update static effect
local metadatas = {
ent = ent:getComponent("Metadata"),
scene = scene:getComponent("Metadata")
}
local transforms = {
ent = ent:getComponent("Transform"),
controller = controller:getComponent("Transform")
}
local distanceSquared = transforms.controller.position:distance( transforms.ent.position )
distanceSquared = distanceSquared * distanceSquared
if type(metadatas.ent["static"]["scale"]) == "number" then
distanceSquared = distanceSquared * metadatas.ent["static"]["scale"]
end
local lo = type(metadatas.ent["static"]["range"][1]) == "number" and metadatas.ent["static"]["range"][1] or 0.1
local hi = type(metadatas.ent["static"]["range"][2]) == "number" and metadatas.ent["static"]["range"][2] or 0.5
local staticBlend = distanceSquared > 1 and 1.0 / distanceSquared or 1.0
staticBlend = math.clamp( staticBlend, lo, hi )
local flicker = type(metadatas.ent["static"]["flicker"]) == "number" and metadatas.ent["static"]["flicker"] or 0.001
local pieces = type(metadatas.ent["static"]["pieces"]) == "number" and metadatas.ent["static"]["pieces"] or 1000
local payload = {
mode = 2,
parameters = {
[1] = flicker,
[2] = pieces,
[3] = staticBlend,
[4] = "time"
}
}
scene:callHook("shader:Update.%UID%", payload)
end )
--[[
local hud = ent:loadChild("/hud.json", true)
hud:bind( "tick", function(self)
-- update distance HUD element
if timer:elapsed() <= 0.0125 then return end
timer:reset()
local metadata = self:getComponent("Metadata")
local transforms = {
controller = controller:getComponent("Transform"),
source = ent:getComponent("Transform")
}
local distance = transforms.controller.position:distance( transforms.source.position )
--distance = string.si( distance, "m" )
local maximum = 40
local value = math.floor(distance/maximum * 100)
if value >= 100 then value = 100 end
distance = "Sanity: " .. value .. "%"
--distance = math.floor((15-distance)/15 * 100) .. "%"
if metadata["text settings"]["string"] ~= distance then
self:callHook( "gui:UpdateString.%UID%", {
string = distance
} )
end
end )
]]
--[[
local marker = ent:loadChild("./marker.json", true)
marker:bind( "tick", function(self)
local transform = marker:getComponent("Transform")
local parentTransform = ent:getComponent("Transform")
local controllerTransform = controller:getComponent("Transform")
local controllerCamera = controller:getComponent("Camera")
local controllerCameraTransform = controllerCamera:getTransform()
transform.position = parentTransform.position + Vector3f(0,3,0)
transform.orientation = Quaternion.lookAt( transform.position - controllerTransform.position, Vector3f(0,1,0) )
-- transform.orientation = transform.orientation:normalize()
-- transform.model = controllerCamera:getProjection() * controllerCamera:getView() * Matrix4f.translate( transform.position ) * transform.orientation:matrix()
end )
]]

View File

@ -0,0 +1,11 @@
local scene = entities.currentScene()
local controller = entities.controller()
local transform = ent:getComponent("Transform")
local controllerTransform = controller:getComponent("Transform")
local offset = Vector3f(0,1,0) -- transform.position
io.print("TRACKING PLAYER")
-- on tick
ent:bind( "tick", function(self)
transform.position = offset + controllerTransform.position
end )

View File

@ -0,0 +1,110 @@
{
"import": "/model.json",
"assets": [
// { "filename": "./static.json", "delay": 8 },
{ "filename": "./models/sh_mcd.glb", "delay": 0, "single threaded": false }
// { "filename": "./models/sh_mcd/graph.json", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/sh_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
],
"metadata": {
"model": {
"cull mode": "none",
"alpha mode": "BLEND",
"grid": {
"/^worldspawn/": {
"size": [4,4,4],
// "epsilon": 0.01,
"cleanup": true,
"print": true
},
"/^worldspawn_sh2/": {
"size": [32,32,32],
// "epsilon": 0.01,
"cleanup": true,
"print": true
}
},
"tags": {
"worldspawn": { "physics": { "type": "mesh", "static": true } },
// "worldspawn_sh2": { "physics": { "type": "mesh", "static": true } },
"info_player_spawn": { "action": "attach", "filename": "./player.json", "preserve orientation": true },
"func_door_rotating_5409": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5487": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } },
"func_door_rotating_5495": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } },
"func_door_rotating_5656": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } },
"func_door_rotating_5664": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5689": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5698": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5712": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_physbox_5212": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_physbox_5548": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_physbox_5931": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5568": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5576": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_door_rotating_5584": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"func_physbox_5212": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_5548": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_5931": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_multiplayer_5839": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_multiplayer_5848": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_multiplayer_5857": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_multiplayer_5864": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_multiplayer_5872": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_multiplayer_5879": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_multiplayer_5886": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_multiplayer_5893": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_multiplayer_5905": { "action": "load", "payload": { "import": "./prop.json" } },
"func_physbox_multiplayer_5913": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5563": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5564": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5687": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5719": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5721": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5722": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5815": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5816": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5817": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5818": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5819": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5820": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_multiplayer_5821": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5227": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5373": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5374": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5375": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5545": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5546": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5565": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5566": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5591": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5675": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5680": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5681": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5682": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5683": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5684": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5685": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5696": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5707": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5723": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5749": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5750": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5760": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5764": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5787": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5807": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5808": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5809": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5810": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5814": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5822": { "action": "load", "payload": { "import": "./prop.json" } },
"prop_physics_override_5824": { "action": "load", "payload": { "import": "./prop.json" } }
}
}
}
}

View File

@ -0,0 +1,34 @@
{
"type": "Object",
"name": "Sound Emitter",
"ignore": false,
"assets": [
],
"behaviors": [
"SoundEmitterBehavior"
],
"transform": {
"reference": true
},
"system": {
"hot reload": {
"enabled": true
},
"defaults": {
"render": true,
"asset load": true
},
"load": {
"ignore": true
}
},
"metadata": {
"audio": {
"spatial": true,
"loop": false,
"volume": 1,
"rolloffFactor": 0.5,
"epsilon": 0.5
}
}
}

View File

@ -0,0 +1,48 @@
{
"type": "Object",
"name": "Static Emitter",
"ignore": false,
"assets": [
"/overworld/static.ogg",
"./scripts/static.lua"
],
"behaviors": [
"SoundEmitterBehavior"
],
"transform": {
"position": [ -13.4342, 2.43658, 298.797 ],
"rotation": {
"axis": [ 0, 1, 0 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"system": {
"hot reload": {
"enabled": true
},
"defaults": {
"render": true,
"asset load": true
},
"load": {
"ignore": true
}
},
"metadata": {
"audio": {
"spatial": true,
"loop": true,
"streamed": false,
"volume": 1.6,
"rolloffFactor": 2
},
"static": {
"range": [ 0.0025, 1 ],
"flicker": 0.5,
"pieces": 16,
"scale": 0.4
},
"distance": false
}
}

View File

@ -1,15 +1,16 @@
{
"import": "/model.json",
"assets": [
// { "filename": "./craeture.json", "delay": 1 },
// { "filename": "./models/tiny_msci.glb", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/tiny_msci/graph.json", "delay": 0, "single threaded": false, "category": "models" }
{ "filename": "./models/tiny_msci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/tiny_msci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/micro_sci.glb", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/micro_sci/graph.json", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/micro_sci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
{ "filename": "./models/micro_sci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./craeture.json", "delay": 1 }
// { "filename": "./models/msci.glb", "delay": 0, "single threaded": false, "category": "models" }
// { "filename": "./models/msci/graph.json", "delay": 0, "single threaded": false, "category": "models" }
@ -21,31 +22,17 @@
],
"metadata": {
"model": {
"exporter": {
"enabled": true
},
"baking": {
"enabled": false,
"resolution": 2048, // 8192
"shadows": 1024,
"layers": 22,
"trigger": { "mode": "rendered" },
// "trigger": { "mode": "key", "value": "B" },
"output": "./lightmap.%i.png"
},
"grid": {
"/^worldspawn/": {
"size": [3,3,3]
}
},
// "lightmap": "./lightmap.%i.min.png",
// "lightmap": false,
"lightmap": true,
"baking": {
"enabled": true,
"resolution": 1024
},
"filter": "LINEAR",
"tags": {
"worldspawn": { "physics": { "type": "mesh", "static": true } },
"worldspawn_20": { "physics": { "type": "mesh", "static": true } },
// "worldspawn": { "physics": { "type": "bounding boxes", "static": true } },
"/^worldspawn/": {
"physics": { "type": "mesh", "static": true },
"grid": { "size": [5,2,5], "epsilon": 1.0, "cleanup": true, "print": true }
},
"info_player_spawn": {
"action": "attach",
"filename": "./player.json",

View File

@ -32,6 +32,19 @@ vec2 encodeNormals( vec3 n ) {
// return n.xy/p + 0.5;
return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5;
}
vec3 encodeSrgb(vec3 rgb) {
const vec3 a = 12.92 * rgb;
const vec3 b = 1.055 * pow(rgb, vec3(1.0 / 2.4)) - 0.055;
const vec3 c = step(vec3(0.0031308), rgb);
return mix(a, b, c);
}
vec3 decodeSrgb(vec3 rgb) {
const vec3 a = rgb / 12.92;
const vec3 b = pow((rgb + 0.055) / 1.055, vec3(2.4));
const vec3 c = step(vec3(0.04045), rgb);
return mix(a, b, c);
}
bool validTextureIndex( int textureIndex ) {
return 0 <= textureIndex && textureIndex < MAX_TEXTURES;
}

View File

@ -21,7 +21,7 @@ void lambert() {
const vec3 diffuse = surface.material.albedo.rgb;
const vec3 specular = vec3(0);
surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
surface.fragment.a += light.power * La * Ls;
surface.light.rgb += (diffuse + specular) * Lr * cosLi;
surface.light.a += light.power * La * Ls;
}
}

View File

@ -0,0 +1,9 @@
#if PBR
#include "../common/pbr.h"
#endif
#if LAMBERT
#include "../common/lambert.h"
#endif
#if PHONG
#include "../common/phong.h"
#endif

View File

@ -13,7 +13,7 @@ float gaSchlickGGX(float cosLi, float cosLo, float roughness) {
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
}
vec3 fresnelSchlick(vec3 F0, float cosTheta) { return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); }
#if !BAKING
#if !BAKING && !COMPUTE
void pbr() {
if ( validTextureIndex( surface.instance.lightmapID ) ) return;
@ -42,13 +42,15 @@ void pbr() {
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
/*
// lightmapped, compute only specular
if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.fragment.rgb += (specular) * Lr * cosLi;
if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.light.rgb += (specular) * Lr * cosLi;
// point light, compute only diffuse
// else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi;
else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
surface.fragment.a += light.power * La * Ls;
// else if ( abs(light.type) == 1 ) surface.light.rgb += (diffuse) * Lr * cosLi;
else surface.light.rgb += (diffuse + specular) * Lr * cosLi;
*/
surface.light.rgb += (diffuse + specular) * Lr * cosLi;
surface.light.a += light.power * La * Ls;
}
}
#endif

View File

@ -158,6 +158,7 @@ struct Surface {
SurfaceMaterial material;
Instance instance;
vec4 light;
vec4 fragment;
} surface;

View File

@ -162,7 +162,7 @@ void indirectLighting() {
indirectSpecular = voxelConeTrace( ray, SPECULAR_CONE_APERTURE );
// outFragColor.rgb = indirectSpecular.rgb; return;
if ( length(indirectSpecular) < 0.0125 ) {
// indirectSpecular += (1.0 - indirectSpecular.a) * texture( samplerSkybox, R );
// indirectSpecular += (1.0 - indirectSpecular.a) * texture( samplerCubemaps[ubo.indexSkybox], R ) * SPECULAR_CONE_APERTURE;
}
}

View File

@ -101,7 +101,7 @@ layout (location = 1) out vec4 outFragBright;
#include "../common/functions.h"
#include "../common/fog.h"
#include "../common/pbr.h"
#include "../common/light.h"
#include "../common/shadows.h"
#if VXGI
#include "../common/vxgi.h"
@ -236,11 +236,11 @@ void populateSurface() {
}
// Lightmap
if ( validTextureIndex( surface.instance.lightmapID ) ) {
surface.material.albedo.rgb *= sampleTexture( surface.instance.lightmapID, surface.st ).rgb;
surface.light += surface.material.albedo * sampleTexture( surface.instance.lightmapID, surface.st );
}
// Emissive textures
if ( validTextureIndex( material.indexEmissive ) ) {
surface.material.albedo += sampleTexture( material.indexEmissive );
surface.light += sampleTexture( material.indexEmissive );
}
// Occlusion map
if ( validTextureIndex( material.indexOcclusion ) ) {
@ -262,15 +262,8 @@ void populateSurface() {
}
void directLighting() {
const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb;
// surface.fragment.rgb += surface.material.albedo.rgb * ambient;
if ( validTextureIndex( surface.instance.lightmapID ) ) {
surface.fragment.rgb += surface.material.albedo.rgb + ambient;
} else {
surface.fragment.rgb += surface.material.albedo.rgb * ambient;
}
// if ( ubo.lights == 0 ) { surface.fragment.rgb = surface.material.albedo.rgb; return; }
surface.light.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion; // add ambient lighting
surface.light.rgb += surface.material.indirect.rgb; // add indirect lighting
#if PBR
pbr();
#elif LAMBERT
@ -278,6 +271,7 @@ void directLighting() {
#elif PHONG
phong();
#endif
surface.fragment.rgb += surface.light.rgb;
}
#if MULTISAMPLING

View File

@ -4,8 +4,8 @@
layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
#define LAMBERT 1
#define PBR 0
#define LAMBERT 0
#define PBR 1
#define VXGI 1
#define COMPUTE 1
@ -72,6 +72,7 @@ layout (binding = 13, rg16f) uniform volatile coherent image3D voxelNormal[CASCA
#endif
#include "../common/functions.h"
#include "../common/light.h"
#undef VXGI
#include "../common/shadows.h"
@ -96,6 +97,7 @@ void main() {
const Material material = materials[surface.instance.materialID];
surface.material.albedo = material.colorBase;
surface.fragment = material.colorEmissive;
/*
#if DEFERRED_SAMPLING
{
vec4 uv = imageLoad(voxelUv[CASCADE], ivec3(tUvw) );
@ -127,20 +129,19 @@ void main() {
#else
surface.material.albedo = imageLoad(voxelRadiance[CASCADE], ivec3(tUvw) );
#endif
*/
surface.material.albedo = imageLoad(voxelRadiance[CASCADE], ivec3(tUvw) );
surface.material.metallic = material.factorMetallic;
surface.material.roughness = material.factorRoughness;
surface.material.occlusion = material.factorOcclusion;
float litFactor = 1.0;
const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion;
if ( validTextureIndex( surface.instance.lightmapID ) ) {
surface.fragment.rgb += surface.material.albedo.rgb + ubo.ambient.rgb * surface.material.occlusion;
surface.fragment.rgb += surface.material.albedo.rgb;
} else {
surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion;
}
// corrections
surface.material.roughness *= 4.0;
if ( !validTextureIndex( surface.instance.lightmapID ) )
{
surface.fragment.rgb += surface.material.albedo.rgb * ambient;
// corrections
surface.material.roughness *= 4.0;
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
const vec3 Lo = normalize( surface.position.world );
const float cosLo = max(0.0, dot(surface.normal.world, Lo));
@ -171,14 +172,19 @@ void main() {
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
#endif
// lightmapped, compute only specular
if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.fragment.rgb += (specular) * Lr * cosLi;
/*
if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.light.rgb += (specular) * Lr * cosLi;
// point light, compute only diffuse
// else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi;
else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
surface.fragment.a += light.power * La * Ls;
// else if ( abs(light.type) == 1 ) surface.light.rgb += (diffuse) * Lr * cosLi;
else surface.light.rgb += (diffuse + specular) * Lr * cosLi;
*/
surface.light.rgb += (diffuse + specular) * Lr * cosLi;
surface.light.a += light.power * La * Ls;
}
}
surface.fragment.rgb += surface.light.rgb;
imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(surface.fragment.rgb, surface.material.albedo.a));
}
}

View File

@ -67,8 +67,9 @@ void main() {
surface.material.roughness = material.factorRoughness;
surface.material.occlusion = 1.0f - material.factorOcclusion;
surface.fragment = material.colorEmissive;
surface.light = material.colorEmissive;
surface.material.albedo = vec4(1);
#if 1
{
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
for ( uint i = 0; i < lights.length(); ++i ) {
@ -107,22 +108,61 @@ void main() {
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
#endif
surface.fragment.rgb += (diffuse + specular) * Lr * cosLi;
surface.fragment.a += light.power * La * Ls;
surface.light.rgb += (diffuse + specular) * Lr * cosLi;
surface.light.a += light.power * La * Ls;
}
}
#else
{
// corrections
surface.material.roughness *= 4.0;
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
const vec3 Lo = normalize( surface.position.world );
const float cosLo = max(0.0, dot(surface.normal.world, Lo));
for ( uint i = 0; i < lights.length(); ++i ) {
const Light light = lights[i];
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) continue;
const vec3 Lp = light.position;
const vec3 Liu = light.position - surface.position.world;
const vec3 Li = normalize(Liu);
const float Ls = shadowFactor( light, 0.0 );
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
#define EXPOSURE 1
#define GAMMA 1
const float cosLi = max(0.0, dot(surface.normal.world, Li));
const vec3 Lr = light.color.rgb * light.power * La * Ls;
#if LAMBERT
const vec3 diffuse = surface.material.albedo.rgb;
const vec3 specular = vec3(0);
#elif PBR
const vec3 Lh = normalize(Li + Lo);
const float cosLh = max(0.0, dot(surface.normal.world, Lh));
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
const float D = ndfGGX( cosLh, surface.material.roughness );
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
#endif
// surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * EXPOSURE);
// surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / GAMMA));
surface.light.rgb += (diffuse + specular) * Lr * cosLi;
surface.light.a += light.power * La * Ls;
}
}
#endif
#define EXPOSURE 0
#define GAMMA 0
outAlbedo = vec4(surface.fragment.rgb, 1);
// surface.light.rgb = vec3(1.0) - exp(-surface.light.rgb * EXPOSURE);
// surface.light.rgb = pow(surface.light.rgb, vec3(1.0 / GAMMA));
outAlbedo = vec4(surface.light.rgb, 1);
{
const vec2 st = inSt.xy * imageSize(outAlbedos).xy;
const ivec3 uvw = ivec3(int(st.x), int(st.y), int(inLayer));
imageStore(outAlbedos, uvw, vec4(surface.fragment.rgb, 1) );
imageStore(outAlbedos, uvw, vec4(surface.light.rgb, 1) );
}
}

View File

@ -35,6 +35,8 @@ namespace uf {
static uf::Asset::Payload resolveToPayload( const uf::stl::string&, const uf::stl::string& = "" );
static bool isExpected( const uf::Asset::Payload&, uf::Asset::Type expected );
static bool assertionLoad;
// URL or file path
void processQueue();

View File

@ -9,9 +9,7 @@
#include <uf/utils/memory/pool.h>
namespace uf {
class UF_API Object;
class UF_API Entity : public uf::Behaviors {
//friend class EntityBehavior;
public:
typedef uf::stl::vector<uf::Entity*> container_t;
static uf::Entity null;
@ -36,8 +34,8 @@ namespace uf {
std::size_t getUid() const;
void setName( const uf::stl::string& );
// cast to other Entity classes, avoid nasty shit like *((uf::Object*) &entity)
template<typename T=uf::Object> T& as();
template<typename T=uf::Object> const T& as() const;
template<typename T> T& as();
template<typename T> const T& as() const;
// parent-child relationship
bool hasParent() const;
template<typename T=uf::Entity> T& getParent();

View File

@ -44,6 +44,7 @@ namespace uf {
} load;
bool ignoreGraph = false;
bool invalid = false;
} system;
struct {
pod::Transform<> initial;

View File

@ -13,6 +13,8 @@ namespace uf {
class UF_API Object : public uf::Entity {
public:
static uf::Timer<long long> timer;
static bool assertionLoad;
Object();
bool reload( bool = false );

View File

@ -56,6 +56,7 @@ namespace uf {
pod::Thread& UF_API fetchWorker( const uf::stl::string& name = "Aux" );
void UF_API batchWorker( const pod::Thread::function_t&, const uf::stl::string& name = "Aux" );
void UF_API batchWorkers( const uf::stl::vector<pod::Thread::function_t>&, bool = true, const uf::stl::string& name = "Aux" );
void UF_API batchWorkers_Async( const uf::stl::vector<pod::Thread::function_t>&, bool = true, const uf::stl::string& name = "Aux" );
void UF_API add( pod::Thread&, const pod::Thread::function_t&, bool = false );
void UF_API process( pod::Thread& );

View File

@ -47,6 +47,7 @@ namespace {
}
uf::Asset uf::Asset::masterAssetLoader;
bool uf::Asset::assertionLoad = true;
void uf::Asset::processQueue() {
uf::thread::batchWorker( [&](){
@ -223,18 +224,30 @@ uf::stl::string uf::Asset::cache( const uf::Asset::Payload& payload ) {
uf::stl::string hash = uf::string::sha256( filename );
uf::stl::string cached = uf::io::root + "/cache/http/" + hash + "." + extension;
if ( !uf::io::exists( cached ) && !retrieve( filename, cached, hash ) ) {
UF_MSG_ERROR("Failed to preload `" + filename + "` (`" + cached + "`): HTTP error");
if ( !uf::Asset::assertionLoad ) {
UF_MSG_ERROR("Failed to preload `" + filename + "` (`" + cached + "`): HTTP error");
} else {
UF_EXCEPTION("Failed to preload `" + filename + "` (`" + cached + "`): HTTP error");
}
return "";
}
filename = cached;
}
if ( !uf::io::exists( filename ) ) {
UF_MSG_ERROR("Failed to preload `" + filename + "`: Does not exist");
if ( !uf::Asset::assertionLoad ) {
UF_MSG_ERROR("Failed to preload `" + filename + "`: Does not exist");
} else {
UF_EXCEPTION("Failed to preload `" + filename + "`: Does not exist");
}
return "";
}
uf::stl::string actual = payload.hash;
if ( payload.hash != "" && (actual = uf::io::hash( filename )) != payload.hash ) {
UF_MSG_ERROR("Failed to preload `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual);
if ( !uf::Asset::assertionLoad ) {
UF_MSG_ERROR("Failed to preload `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual);
} else {
UF_EXCEPTION("Failed to preload `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual);
}
return "";
}
return filename;
@ -247,18 +260,30 @@ uf::stl::string uf::Asset::load(const uf::Asset::Payload& payload ) {
uf::stl::string hash = uf::string::sha256( payload.filename );
uf::stl::string cached = uf::io::root + "/cache/http/" + hash + "." + extension;
if ( !uf::io::exists( cached ) && !retrieve( payload.filename, cached, hash ) ) {
UF_MSG_ERROR("Failed to load `" + payload.filename + "` (`" + cached + "`): HTTP error");
if ( !uf::Asset::assertionLoad ) {
UF_MSG_ERROR("Failed to load `" + payload.filename + "` (`" + cached + "`): HTTP error");
} else {
UF_EXCEPTION("Failed to load `" + payload.filename + "` (`" + cached + "`): HTTP error");
}
return "";
}
filename = cached;
}
if ( !uf::io::exists( filename ) ) {
UF_MSG_ERROR("Failed to load `" + filename + "`: Does not exist");
if ( !uf::Asset::assertionLoad ) {
UF_MSG_ERROR("Failed to load `" + filename + "`: Does not exist");
} else {
UF_EXCEPTION("Failed to load `" + filename + "`: Does not exist");
}
return "";
}
uf::stl::string actual = payload.hash;
if ( payload.hash != "" && (actual = uf::io::hash( filename )) != payload.hash ) {
UF_MSG_ERROR("Failed to load `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual);
if ( !uf::Asset::assertionLoad ) {
UF_MSG_ERROR("Failed to load `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual);
} else {
UF_EXCEPTION("Failed to load `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual);
}
return "";
}

View File

@ -12,7 +12,7 @@
#if UF_ENV_DREAMCAST
#define UF_GRAPH_LOAD_MULTITHREAD 0
#else
#define UF_GRAPH_LOAD_MULTITHREAD 0
#define UF_GRAPH_LOAD_MULTITHREAD 1 // causes Vulkan OOM
#endif
namespace {
@ -428,7 +428,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize
graph.root = decodeNode( serializer["root"], graph );
});
#if UF_GRAPH_LOAD_MULTITHREAD
if ( !jobs.empty() ) uf::thread::batchWorkers( jobs );
if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs );
#else
for ( auto& job : jobs ) job();
#endif

View File

@ -12,7 +12,7 @@
#if UF_ENV_DREAMCAST
#define UF_GRAPH_LOAD_MULTITHREAD 0
#else
#define UF_GRAPH_LOAD_MULTITHREAD 0
#define UF_GRAPH_LOAD_MULTITHREAD 1 // causes Vulkan OOM
#endif
namespace {
@ -427,7 +427,7 @@ void uf::graph::save( const pod::Graph& graph, const uf::stl::string& filename )
serializer["root"] = encode(graph.root, settings);
});
#if UF_GRAPH_LOAD_MULTITHREAD
if ( !jobs.empty() ) uf::thread::batchWorkers( jobs );
if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs );
#else
for ( auto& job : jobs ) job();
#endif

View File

@ -367,31 +367,37 @@ void uf::graph::process( pod::Graph& graph ) {
//
if ( !graph.root.entity ) graph.root.entity = new uf::Object;
//
uf::stl::unordered_map<uf::stl::string, bool> isSrgb;
// process lightmap
#if UF_USE_OPENGL
#define UF_GRAPH_DEFAULT_LIGHTMAP "./lightmap.%i.min.dtex"
#else
#define UF_GRAPH_DEFAULT_LIGHTMAP "./lightmap.%i.png"
#endif
if ( graph.metadata["lightmap"].as<bool>() ) {
{
uf::stl::unordered_map<size_t, uf::stl::string> filenames;
uf::stl::unordered_map<size_t, size_t> lightmapIDs;
UF_MSG_DEBUG( graph.instances.size() );
uint32_t lightmapCount = 0;
for ( auto& name : graph.instances ) {
auto& instance = uf::graph::storage.instances[name];
// if ( !instance.auxID ) break;
filenames[instance.auxID] = uf::string::replace(UF_GRAPH_DEFAULT_LIGHTMAP, "%i", std::to_string(instance.auxID));
lightmapCount = std::max( lightmapCount, instance.auxID );
}
for ( auto& name : graph.primitives ) {
auto& primitives = uf::graph::storage.primitives[name];
for ( auto& primitive : primitives ) {
// if ( !primitive.instance.auxID ) break;
filenames[primitive.instance.auxID] = uf::string::replace(UF_GRAPH_DEFAULT_LIGHTMAP, "%i", std::to_string(primitive.instance.auxID));
lightmapCount = std::max( lightmapCount, primitive.instance.auxID );
}
}
for ( auto& pair : filenames ) {
graph.metadata["baking"]["layers"] = lightmapCount;
if ( graph.metadata["lightmap"].as<bool>() ) for ( auto& pair : filenames ) {
auto i = pair.first;
auto f = uf::io::sanitize( pair.second, uf::io::directory( graph.name ) );
@ -399,6 +405,7 @@ void uf::graph::process( pod::Graph& graph ) {
UF_MSG_ERROR( "lightmap does not exist: " << f )
continue;
}
auto textureID = graph.textures.size();
auto imageID = graph.images.size();
@ -413,6 +420,8 @@ void uf::graph::process( pod::Graph& graph ) {
graph.metadata["lightmaps"][i] = f;
graph.metadata["baking"]["enabled"] = false;
isSrgb[f] = false;
}
for ( auto& name : graph.instances ) {
@ -427,38 +436,6 @@ void uf::graph::process( pod::Graph& graph ) {
primitive.instance.lightmapID = lightmapIDs[primitive.instance.auxID];
}
}
#if 0
const uf::stl::string lightmapFilename = graph.metadata["lightmap"].as<uf::stl::string>(UF_GRAPH_DEFAULT_LIGHTMAP);
// load lightmap, if requested
if ( lightmapFilename != "" ) {
// check if valid filename, if not it's a texture name
uf::stl::string f = uf::io::sanitize( lightmapFilename, uf::io::directory( graph.name ) );
if ( uf::io::exists( f ) ) {
auto textureID = graph.textures.size();
auto imageID = graph.images.size();
auto& texture = /*graph.storage*/uf::graph::storage.textures[graph.textures.emplace_back(f)];
auto& image = /*graph.storage*/uf::graph::storage.images[graph.images.emplace_back(f)];
image.open( f, false );
texture.index = imageID;
for ( auto& name : graph.instances ) {
auto& instance = uf::graph::storage.instances[name];
instance.lightmapID = textureID;
}
for ( auto& name : graph.primitives ) {
auto& primitives = uf::graph::storage.primitives[name];
for ( auto& primitive : primitives ) {
primitive.instance.lightmapID = textureID;
}
}
graph.metadata["lightmapped"] = f;
graph.metadata["baking"]["enabled"] = false;
}
}
#endif
}
// add atlas
@ -480,19 +457,21 @@ void uf::graph::process( pod::Graph& graph ) {
if ( !(0 <= ID && ID < graph.textures.size()) ) continue;
auto texName = graph.textures[ID];
auto& texture = uf::graph::storage.texture2Ds[texName];
texture.srgb = true;
isSrgb[texName] = true;
}
for ( auto& key : graph.images ) {
auto& image = uf::graph::storage.images[key];
auto& texture = uf::graph::storage.texture2Ds[key];
if ( !texture.generated() ) {
bool isLightmap = graph.metadata["lightmapped"].as<uf::stl::string>() == key;
auto filter = graph.metadata["filter"].as<uf::stl::string>() == "NEAREST" && !isLightmap ? uf::renderer::enums::Filter::NEAREST : uf::renderer::enums::Filter::LINEAR;
// bool isLightmap = graph.metadata["lightmapped"].as<uf::stl::string>() == key;
// auto filter = graph.metadata["filter"].as<uf::stl::string>() == "NEAREST" && !isLightmap ? uf::renderer::enums::Filter::NEAREST : uf::renderer::enums::Filter::LINEAR;
// auto filter = uf::renderer::enums::Filter::LINEAR;
auto filter = graph.metadata["filter"].as<uf::stl::string>() == "NEAREST" ? uf::renderer::enums::Filter::NEAREST : uf::renderer::enums::Filter::LINEAR;
texture.sampler.descriptor.filter.min = filter;
texture.sampler.descriptor.filter.mag = filter;
texture.srgb = isSrgb.count(key) == 0 ? false : isSrgb[key];
texture.loadFromImage( image );
#if UF_ENV_DREAMCAST
@ -706,40 +685,40 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
// on systems where frametime is very, very important, we can set all static nodes to not tick
// tie to tag
{
ext::json::Value info = ext::json::null();
if ( ext::json::isObject( graph.metadata["tags"][node.name] ) ) {
info = graph.metadata["tags"][node.name];
} else {
ext::json::forEach( graph.metadata["tags"], [&]( const uf::stl::string& key, ext::json::Value& value ) {
if ( !uf::string::isRegex( key ) ) return;
if ( uf::string::matches( node.name, key ).empty() ) return;
info = value;
});
}
if ( ext::json::isObject( info ) ) {
if ( info["ignore"].as<bool>() ) return;
ext::json::Value tag = ext::json::null();
/*
if ( ext::json::isObject( graph.metadata["tags"][node.name] ) ) {
tag = graph.metadata["tags"][node.name];
}
*/
ext::json::forEach( graph.metadata["tags"], [&]( const uf::stl::string& key, ext::json::Value& value ) {
if ( uf::string::isRegex( key ) ) {
if ( uf::string::matches( node.name, key ).empty() ) return;
} else if ( node.name != key ) return;
tag = value;
});
if ( ext::json::isObject( tag ) ) {
if ( tag["ignore"].as<bool>() ) return;
if ( info["action"].as<uf::stl::string>() == "load" ) {
if ( info["filename"].is<uf::stl::string>() ) {
uf::stl::string filename = uf::io::resolveURI( info["filename"].as<uf::stl::string>(), graph.metadata["root"].as<uf::stl::string>() );
entity.load(filename);
} else if ( ext::json::isObject( info["payload"] ) ) {
uf::Serializer json = info["payload"];
json["root"] = graph.metadata["root"];
entity.load(json);
}
} else if ( info["action"].as<uf::stl::string>() == "attach" ) {
uf::stl::string filename = uf::io::resolveURI( info["filename"].as<uf::stl::string>(), graph.metadata["root"].as<uf::stl::string>() );
auto& child = entity.loadChild( filename, false );
auto& childTransform = child.getComponent<pod::Transform<>>();
auto flatten = uf::transform::flatten( node.transform );
if ( !info["preserve position"].as<bool>() ) childTransform.position = flatten.position;
if ( !info["preserve orientation"].as<bool>() ) childTransform.orientation = flatten.orientation;
}
if ( info["static"].is<bool>() ) {
metadata.system.ignoreGraph = info["static"].as<bool>();
if ( tag["action"].as<uf::stl::string>() == "load" ) {
if ( tag["filename"].is<uf::stl::string>() ) {
uf::stl::string filename = uf::io::resolveURI( tag["filename"].as<uf::stl::string>(), graph.metadata["root"].as<uf::stl::string>() );
entity.load(filename);
} else if ( ext::json::isObject( tag["payload"] ) ) {
uf::Serializer json = tag["payload"];
json["root"] = graph.metadata["root"];
entity.load(json);
}
} else if ( tag["action"].as<uf::stl::string>() == "attach" ) {
uf::stl::string filename = uf::io::resolveURI( tag["filename"].as<uf::stl::string>(), graph.metadata["root"].as<uf::stl::string>() );
auto& child = entity.loadChild( filename, false );
auto& childTransform = child.getComponent<pod::Transform<>>();
auto flatten = uf::transform::flatten( node.transform );
if ( !tag["preserve position"].as<bool>() ) childTransform.position = flatten.position;
if ( !tag["preserve orientation"].as<bool>() ) childTransform.orientation = flatten.orientation;
}
if ( tag["static"].is<bool>() ) {
metadata.system.ignoreGraph = tag["static"].as<bool>();
}
}
// create as light
@ -790,27 +769,24 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
transform = node.transform;
transform.reference = &parent.getComponent<pod::Transform<>>();
// override transform
if ( !ext::json::isNull( graph.metadata["tags"][node.name] ) ) {
auto& info = graph.metadata["tags"][node.name];
if ( info["transform"]["offset"].as<bool>() ) {
auto parsed = uf::transform::decode( info["transform"], pod::Transform<>{} );
transform.position += parsed.position;
transform.orientation = uf::quaternion::multiply( transform.orientation, parsed.orientation );
} else {
transform = uf::transform::decode( info["transform"], transform );
if ( info["transform"]["parent"].is<uf::stl::string>() ) {
auto* parentPointer = uf::graph::find( graph, info["transform"]["parent"].as<uf::stl::string>() );
if ( parentPointer ) {
auto& parentNode = *parentPointer;
// entity already exists, bind to its transform
if ( parentNode.entity && parentNode.entity->hasComponent<pod::Transform<>>() ) {
auto& parentTransform = parentNode.entity->getComponent<pod::Transform<>>();
transform = uf::transform::reference( transform, parentTransform, info["transform"]["reorient"].as<bool>() );
transform.position = -transform.position;
// doesnt exist, bind to the node transform
} else {
transform = uf::transform::reference( transform, parentNode.transform, info["transform"]["reorient"].as<bool>() );
}
if ( tag["transform"]["offset"].as<bool>() ) {
auto parsed = uf::transform::decode( tag["transform"], pod::Transform<>{} );
transform.position += parsed.position;
transform.orientation = uf::quaternion::multiply( transform.orientation, parsed.orientation );
} else {
transform = uf::transform::decode( tag["transform"], transform );
if ( tag["transform"]["parent"].is<uf::stl::string>() ) {
auto* parentPointer = uf::graph::find( graph, tag["transform"]["parent"].as<uf::stl::string>() );
if ( parentPointer ) {
auto& parentNode = *parentPointer;
// entity already exists, bind to its transform
if ( parentNode.entity && parentNode.entity->hasComponent<pod::Transform<>>() ) {
auto& parentTransform = parentNode.entity->getComponent<pod::Transform<>>();
transform = uf::transform::reference( transform, parentTransform, tag["transform"]["reorient"].as<bool>() );
transform.position = -transform.position;
// doesnt exist, bind to the node transform
} else {
transform = uf::transform::reference( transform, parentNode.transform, tag["transform"]["reorient"].as<bool>() );
}
}
}
@ -860,23 +836,23 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
uf::graph::initializeGraphics( graph, entity );
}
if ( !ext::json::isNull( graph.metadata["tags"][node.name] ) ) {
auto info = graph.metadata["tags"][node.name]["physics"];
if ( !ext::json::isObject( info ) ) info = metadataJson["system"]["physics"];
else metadataJson["system"]["physics"] = info;
{
auto phyziks = tag["physics"];
if ( !ext::json::isObject( phyziks ) ) phyziks = metadataJson["system"]["physics"];
else metadataJson["system"]["physics"] = phyziks;
if ( ext::json::isObject( info ) ) {
uf::stl::string type = info["type"].as<uf::stl::string>();
if ( ext::json::isObject( phyziks ) ) {
uf::stl::string type = phyziks["type"].as<uf::stl::string>();
if ( type == "mesh" ) {
auto& collider = entity.getComponent<pod::PhysicsState>();
collider.stats.mass = info["mass"].as(collider.stats.mass);
collider.stats.friction = info["friction"].as(collider.stats.friction);
collider.stats.restitution = info["restitution"].as(collider.stats.restitution);
collider.stats.inertia = uf::vector::decode( info["inertia"], collider.stats.inertia );
collider.stats.gravity = uf::vector::decode( info["gravity"], collider.stats.gravity );
collider.stats.mass = phyziks["mass"].as(collider.stats.mass);
collider.stats.friction = phyziks["friction"].as(collider.stats.friction);
collider.stats.restitution = phyziks["restitution"].as(collider.stats.restitution);
collider.stats.inertia = uf::vector::decode( phyziks["inertia"], collider.stats.inertia );
collider.stats.gravity = uf::vector::decode( phyziks["gravity"], collider.stats.gravity );
uf::physics::impl::create( entity.as<uf::Object>(), mesh, !info["static"].as<bool>(true) );
uf::physics::impl::create( entity.as<uf::Object>(), mesh, !phyziks["static"].as<bool>(true) );
} else {
auto min = uf::matrix::multiply<float>( model, bounds.min, 1.0f );
auto max = uf::matrix::multiply<float>( model, bounds.max, 1.0f );

View File

@ -10,10 +10,14 @@
#include <uf/utils/mesh/mesh.h>
#include <uf/ext/gltf/gltf.h>
uf::Timer<long long> uf::Object::timer(false);
/*
namespace {
uf::Object null;
}
*/
uf::Timer<long long> uf::Object::timer(false);
bool uf::Object::assertionLoad = true;
UF_OBJECT_REGISTER_BEGIN(uf::Object)
UF_OBJECT_REGISTER_BEHAVIOR(uf::EntityBehavior)
@ -432,7 +436,14 @@ uf::Object& uf::Object::loadChild( const uf::stl::string& f, bool initialize ) {
uf::Serializer json;
uf::stl::string filename = uf::io::resolveURI( f, metadata.system.root );
if ( !json.readFromFile(filename) ) {
return ::null;
if ( !uf::Object::assertionLoad ) {
UF_MSG_ERROR("assertionLoad is unset, loading empty entity");
auto& entity = uf::instantiator::instantiate("Object");
entity.getComponent<uf::ObjectBehavior::Metadata>().system.invalid = true;
this->addChild(entity);
} else {
UF_EXCEPTION("Failed to load file: " << filename);
}
}
json["source"] = filename;
@ -445,33 +456,39 @@ uf::Object& uf::Object::loadChild( const uf::Serializer& _json, bool initialize
uf::Serializer json = _json;
uf::stl::string type = json["type"].as<uf::stl::string>();
if ( type == "" ) type = "Object";
if ( json["ignore"].as<bool>() ) return ::null;
uf::Entity& entity = uf::instantiator::instantiate(type);
uf::Object& object = entity.as<uf::Object>();
this->addChild(entity);
if ( json["ignore"].as<bool>() ) return object;
if ( !object.load(json) ) {
this->removeChild(entity);
return ::null;
if ( !uf::Object::assertionLoad ) {
UF_MSG_ERROR("assertionLoad is unset, loading empty entity");
entity.getComponent<uf::ObjectBehavior::Metadata>().system.invalid = true;
} else {
UF_EXCEPTION("Failed to load JSON: " << json);
}
}
if ( initialize ) entity.initialize();
return object;
}
uf::Object* uf::Object::loadChildPointer( const uf::stl::string& f, bool initialize ) {
uf::Object* pointer = &this->loadChild(f, initialize);
return pointer != &::null ? pointer : NULL;
return pointer;
// return pointer != &::null ? pointer : NULL;
}
uf::Object* uf::Object::loadChildPointer( const uf::Serializer& json, bool initialize ) {
uf::Object* pointer = &this->loadChild(json, initialize);
return pointer != &::null ? pointer : NULL;
return pointer;
// return pointer != &::null ? pointer : NULL;
}
std::size_t uf::Object::loadChildUid( const uf::stl::string& f, bool initialize ) {
size_t uf::Object::loadChildUid( const uf::stl::string& f, bool initialize ) {
uf::Object* pointer = this->loadChildPointer(f, initialize);
return pointer ? pointer->getUid() : -1;
return pointer ? pointer->getUid() : 0;
}
std::size_t uf::Object::loadChildUid( const uf::Serializer& json, bool initialize ) {
size_t uf::Object::loadChildUid( const uf::Serializer& json, bool initialize ) {
uf::Object* pointer = this->loadChildPointer(json, initialize);
return pointer ? pointer->getUid() : -1;
return pointer ? pointer->getUid() : 0;
}
uf::stl::string uf::Object::grabURI( const uf::stl::string& filename, const uf::stl::string& root ) {

View File

@ -243,17 +243,15 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
bool print = false;
bool cleanup = true;
} meshgrid;
if ( ext::json::isObject( graph.metadata["grid"][m.name] ) ) {
meshgrid.metadata = graph.metadata["grid"][m.name];
} else {
ext::json::forEach( graph.metadata["grid"], [&]( const uf::stl::string& key, ext::json::Value& value ) {
if ( !ext::json::isNull( meshgrid.metadata["size"] ) ) return;
if ( !uf::string::isRegex( key ) ) return;
ext::json::forEach( graph.metadata["tags"], [&]( const uf::stl::string& key, ext::json::Value& value ) {
if ( !ext::json::isObject( value["grid"] ) ) return; // no tag["grid"] defined
if ( ext::json::isNull( value["grid"]["size"] ) ) return; // no tag["grid"]["size"] defined
if ( uf::string::isRegex( key ) ) {
if ( uf::string::matches( m.name, key ).empty() ) return;
meshgrid.metadata = value;
});
}
} else if ( m.name != key ) return;
meshgrid.metadata = value["grid"];
});
if ( ext::json::isObject( meshgrid.metadata ) ) {
if ( meshgrid.metadata["size"].is<size_t>() ) {
@ -267,6 +265,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
meshgrid.print = meshgrid.metadata["print"].as(meshgrid.print);
meshgrid.cleanup = meshgrid.metadata["cleanup"].as(meshgrid.cleanup);
}
if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) {
#define UF_GRAPH_MESH_FORMAT uf::graph::mesh::Skinned, uint32_t
@ -505,7 +504,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
}
// generate STs
#if UF_USE_XATLAS
{
if ( graph.metadata["exporter"]["unwrap"].as<bool>() ) {
UF_MSG_DEBUG( "Generating ST's..." );
size_t atlases = ext::xatlas::unwrap( graph );
UF_MSG_DEBUG( "Generated ST's for " << atlases << " lightmaps" );
@ -514,6 +513,10 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
if ( graph.metadata["exporter"]["enabled"].as<bool>() ) {
uf::graph::save( graph, filename );
// disable baking, doesn't output right if baking from a gltf imported model
graph.metadata["baking"]["enabled"] = false;
// disable lightmap loading, 99.999% of the time a previously baked lightmap will not work due to changing STs
graph.metadata["lightmap"] = false;
}
return graph;
}

View File

@ -155,6 +155,8 @@ for ( auto& p : m.primitives ) {
#undef COPY_INDICES
}
meshlet.primitive.instance.materialID = p.material;
meshlet.primitive.instance.primitiveID = meshlets.size() - 1;
meshlet.primitive.instance.meshID = meshID;
@ -195,8 +197,7 @@ if ( meshgrid.grid.divisions.x > 1 && meshgrid.grid.divisions.y > 1 && meshgrid.
.materialID = meshlet.primitive.drawCommand.materialID,
.vertices = meshlet.vertices.size(),
});
//UF_MSG_DEBUG( );
primitives.emplace_back( meshlet.primitive );
indexID += meshlet.indices.size();

View File

@ -2,6 +2,9 @@
#if UF_USE_XATLAS
#include <xatlas/xatlas.h>
#define UF_XATLAS_UNWRAP_MULTITHREAD 1
#define UF_XATLAS_LAZY 1 // i do not understand why it needs to insert extra vertices for it to not even be used in the indices buffer, this flag avoids having to account for it
size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) {
struct Entry {
size_t index = 0;
@ -134,15 +137,37 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) {
packOptions.bilinear = true;
// pack
pod::Thread::container_t jobs;
for ( auto& pair : atlases ) {
jobs.emplace_back([&]{
auto& atlas = pair.second;
::xatlas::Generate(atlas.pointer, chartOptions, packOptions);
/*
// get vertices size ahead of time
for ( auto i = 0; i < atlas.pointer->meshCount; ++i ) {
auto& xmesh = atlas.pointer->meshes[i];
auto& entry = atlas.entries[i];
// atlas.vertices += xmesh.vertexCount;
sizes[entry.index] += xmesh.vertexCount;
}
*/
});
}
#if UF_XATLAS_UNWRAP_MULTITHREAD
if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs );
#else
for ( auto& job : jobs ) job();
#endif
#if !UF_XATLAS_LAZY
for ( auto& pair : atlases ) {
auto& atlas = pair.second;
::xatlas::Generate(atlas.pointer, chartOptions, packOptions);
// get vertices size ahead of time
for ( auto i = 0; i < atlas.pointer->meshCount; ++i ) {
auto& xmesh = atlas.pointer->meshes[i];
auto& entry = atlas.entries[i];
// atlas.vertices += xmesh.vertexCount;
sizes[entry.index] += xmesh.vertexCount;
}
}
@ -151,13 +176,16 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) {
for ( auto i = 0; i < graph.meshes.size(); ++i ) {
auto& name = graph.meshes[i];
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name];
mesh.resizeVertices( sizes[i] );
mesh.updateDescriptor();
if ( sizes[i] != mesh.vertex.count ) {
mesh.resizeVertices( sizes[i] );
mesh.updateDescriptor();
}
}
#endif
// update vertices
for ( auto& pair : atlases ) {
size_t vertexIDOffset = 0;
auto& atlas = pair.second;
for ( auto i = 0; i < atlas.pointer->meshCount; i++ ) {
auto& xmesh = atlas.pointer->meshes[i];
@ -166,32 +194,47 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) {
auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name];
auto& source = sources[entry.index];
// draw commands
if ( mesh.indirect.count ) {
// vertices
auto srcInput = source.remapVertexInput( entry.commandID );
auto dstInput = mesh.remapVertexInput( entry.commandID );
auto vertexCount = xmesh.vertexCount;
#if UF_XATLAS_LAZY
for ( auto j = 0; j < xmesh.vertexCount; ++j ) {
auto& vertex = xmesh.vertexArray[j];
auto ref = vertex.xref;
for ( auto k = 0; k < srcInput.attributes.size(); ++k ) {
auto dstAttribute = dstInput.attributes[k];
if ( dstAttribute.descriptor.name != "st" ) continue;
pod::Vector2f& st = *(pod::Vector2f*) ( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * (ref + dstInput.first) );
st = pod::Vector2f{ vertex.uv[0] / atlas.pointer->width, vertex.uv[1] / atlas.pointer->height };;
}
}
#else
auto& primitives = /*graph.storage*/uf::graph::storage.primitives[name];
pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer(mesh.indirect).data();
drawCommands[entry.commandID].vertices = vertexCount;
primitives[entry.commandID].drawCommand.vertices = vertexCount;
bool mismatched = xmesh.vertexCount != drawCommands[entry.commandID].vertices;
vertexIDOffset += xmesh.vertexCount - drawCommands[entry.commandID].vertices;
drawCommands[entry.commandID].vertices = xmesh.vertexCount;
primitives[entry.commandID].drawCommand.vertices = xmesh.vertexCount;
drawCommands[entry.commandID].vertexID += vertexIDOffset;
primitives[entry.commandID].drawCommand.vertexID += vertexIDOffset;
for ( auto j = 0; j < xmesh.vertexCount; ++j ) {
auto& vertex = xmesh.vertexArray[j];
auto ref = vertex.xref;
for ( auto k = 0; k < mesh.vertex.attributes.size(); ++k ) {
// auto srcAttribute = source.remapVertexAttribute( source.vertex.attributes[k], entry.commandID );
// auto dstAttribute = mesh.remapVertexAttribute( mesh.vertex.attributes[k], entry.commandID );
auto srcAttribute = source.vertex.attributes[k];
auto dstAttribute = mesh.vertex.attributes[k];
for ( auto k = 0; k < srcInput.attributes.size(); ++k ) {
auto srcAttribute = srcInput.attributes[k];
auto dstAttribute = dstInput.attributes[k];
if ( dstAttribute.descriptor.name == "st" ) {
pod::Vector2f& st = *(pod::Vector2f*) ( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * (j + dstInput.first) );
st = pod::Vector2f{ vertex.uv[0] / atlas.pointer->width, vertex.uv[1] / atlas.pointer->height };
st = pod::Vector2f{ vertex.uv[0] / atlas.pointer->width, vertex.uv[1] / atlas.pointer->height };;
} else {
memcpy( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * (j + dstInput.first), static_cast<uint8_t*>(srcAttribute.pointer) + srcAttribute.stride * (ref + srcInput.first), srcAttribute.stride );
}
@ -211,12 +254,29 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) {
}
}
}
#endif
} else {
uf::Mesh::Attribute stAttribute;
for ( auto& attribute : mesh.vertex.attributes ) if ( attribute.descriptor.name == "st" ) stAttribute = attribute;
UF_ASSERT( stAttribute.descriptor.name == "st" );
// vertices
#if UF_XATLAS_LAZY
auto srcInput = source.vertex;
auto dstInput = mesh.vertex;
for ( auto j = 0; j < xmesh.vertexCount; ++j ) {
auto& vertex = xmesh.vertexArray[j];
auto ref = vertex.xref;
for ( auto k = 0; k < srcInput.attributes.size(); ++k ) {
auto dstAttribute = dstInput.attributes[k];
if ( dstAttribute.descriptor.name != "st" ) continue;
pod::Vector2f& st = *(pod::Vector2f*) ( static_cast<uint8_t*>(dstAttribute.pointer) + dstAttribute.stride * (ref + dstInput.first) );
st = pod::Vector2f{ vertex.uv[0] / atlas.pointer->width, vertex.uv[1] / atlas.pointer->height };;
}
}
#else
for ( auto j = 0; j < xmesh.vertexCount; ++j ) {
auto& vertex = xmesh.vertexArray[j];
auto ref = vertex.xref;
@ -265,12 +325,13 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) {
}
}
}
#endif
}
mesh.updateDescriptor();
}
}
#if !UF_XATLAS_LAZY
// update vertexID offsets for indirect commands
for ( auto index = 0; index < graph.meshes.size(); ++index ) {
auto& name = graph.meshes[index];
@ -281,6 +342,7 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) {
auto& primitives = /*graph.storage*/uf::graph::storage.primitives[name];
pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer(mesh.indirect).data();
size_t vertexID = 0;
for ( auto i = 0; i < mesh.indirect.count; ++i ) {
auto& primitive = primitives[i];
@ -292,6 +354,7 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) {
vertexID += drawCommand.vertices;
}
}
#endif
// cleanup
size_t atlasCount = 0;

View File

@ -4295,8 +4295,8 @@ static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix* M)
CRS->sliceptr[0] = 0;
for (slice = 1; slice < nslices; ++slice) {
while (cur_NNZ < cur_bound && cur_row < M->m) {
++cur_row;
cur_NNZ += CRS->rowptr[cur_row + 1] - CRS->rowptr[cur_row];
++cur_row;
}
CRS->sliceptr[slice] = cur_row;
cur_bound += slice_size;
@ -4754,13 +4754,10 @@ public:
Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
v[m_numVertices] = v[0];
m_area = 0;
float centroidx = 0, centroidy = 0;
for (uint32_t k = 0; k < m_numVertices; k++) {
// http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
float f = v[k].x * v[k + 1].y - v[k + 1].x * v[k].y;
m_area += f;
centroidx += f * (v[k].x + v[k + 1].x);
centroidy += f * (v[k].y + v[k + 1].y);
}
m_area = 0.5f * fabsf(m_area);
}
@ -9090,7 +9087,6 @@ AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountH
const uint32_t kMaxWarnings = 50;
uint32_t warningCount = 0;
internal::Array<uint32_t> triIndices;
uint32_t firstFaceIndex = 0;
internal::Triangulator triangulator;
for (uint32_t face = 0; face < faceCount; face++) {
// Decode face indices.
@ -9200,7 +9196,6 @@ AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountH
for (uint32_t i = 0; i < triIndices.size(); i++)
meshPolygonMapping->triangleToPolygonIndicesMap.push_back(triIndices[i]);
}
firstFaceIndex += faceVertexCount;
}
if (warningCount > kMaxWarnings)
XA_PRINT(" %u additional warnings truncated\n", warningCount - kMaxWarnings);

View File

@ -66,14 +66,6 @@ void UF_API uf::thread::batchWorker( const pod::Thread::function_t& function, co
return batchWorkers( { function }, false, name );
}
void UF_API uf::thread::batchWorkers( const uf::stl::vector<pod::Thread::function_t>& functions, bool wait, const uf::stl::string& name ) {
if ( uf::thread::async ) {
uf::stl::vector<std::future<void>> futures;
futures.reserve(functions.size());
for ( auto& function : functions ) futures.emplace_back(std::async( std::launch::async, function ));
if ( wait ) for ( auto& future : futures ) future.wait();
return;
}
uf::stl::vector<pod::Thread*> workers;
for ( auto& function : functions ) {
auto& worker = uf::thread::fetchWorker( name );
@ -82,6 +74,14 @@ void UF_API uf::thread::batchWorkers( const uf::stl::vector<pod::Thread::functio
}
if ( wait ) for ( auto& worker : workers ) uf::thread::wait( *worker );
}
void UF_API uf::thread::batchWorkers_Async( const uf::stl::vector<pod::Thread::function_t>& functions, bool wait, const uf::stl::string& name ) {
// if ( uf::thread::async )
uf::stl::vector<std::future<void>> futures;
futures.reserve(functions.size());
for ( auto& function : functions ) futures.emplace_back(std::async( std::launch::async, function ));
if ( wait ) for ( auto& future : futures ) future.wait();
return;
}
void UF_API uf::thread::add( pod::Thread& thread, const pod::Thread::function_t& function, bool temporary ) {
if ( thread.mutex != NULL ) thread.mutex->lock();
temporary ? thread.temps.push( function ) : thread.consts.push_back( function );

View File

@ -15,6 +15,8 @@
#include "../light/behavior.h"
#include "../scene/behavior.h"
#define UF_BAKER_SAVE_MULTITHREAD 1
UF_BEHAVIOR_REGISTER_CPP(ext::BakingBehavior)
UF_BEHAVIOR_TRAITS_CPP(ext::BakingBehavior, ticks = true, renders = false, multithread = false)
#define this (&self)
@ -39,14 +41,15 @@ void ext::BakingBehavior::initialize( uf::Object& self ) {
metadata.output = this->grabURI( metadataJson["baking"]["output"].as<uf::stl::string>(), metadataJson["baking"]["root"].as<uf::stl::string>() );
metadata.renderModeName = "B:" + std::to_string((int) this->getUid());
metadata.trigger.mode = metadataJson["baking"]["trigger"]["mode"].as<uf::stl::string>();
metadata.trigger.value = metadataJson["baking"]["trigger"]["value"].as<uf::stl::string>();
metadata.trigger.mode = metadataJson["baking"]["trigger"]["mode"].as( metadata.trigger.mode );
metadata.trigger.value = metadataJson["baking"]["trigger"]["value"].as( metadata.trigger.value );
metadata.trigger.quits = metadataJson["baking"]["trigger"]["quits"].as( metadata.trigger.quits );
if ( metadataJson["baking"]["resolution"].is<size_t>() )
metadata.size = { metadataJson["baking"]["resolution"].as<size_t>(), metadataJson["baking"]["resolution"].as<size_t>() };
metadata.max.shadows = metadataJson["baking"]["shadows"].as<size_t>(metadata.max.shadows);
metadata.max.layers = metadataJson["baking"]["layers"].as<size_t>(metadata.max.layers);
metadata.max.layers = std::max( metadataJson["baking"]["layers"].as<size_t>(metadata.max.layers), (size_t) 1 );
metadata.cull = metadataJson["baking"]["cull"].as<bool>();
@ -113,20 +116,30 @@ PREPARE: {
renderMode.setTarget("");
uf::renderer::states::rebuild = true;
UF_MSG_DEBUG("Graphic configured, ready to bake");
UF_MSG_DEBUG("Graphic configured, ready to bake " << metadata.max.layers << " lightmaps");
return;
}
SAVE: {
#if 1
renderMode.execute = false;
UF_MSG_DEBUG("Baking...");
pod::Thread::container_t jobs;
for ( size_t i = 0; i < metadata.max.layers; ++i ) {
// auto image = renderMode.screenshot(0, i);
auto image = metadata.buffers.baked.screenshot(i);
uf::stl::string filename = uf::string::replace( metadata.output, "%i", std::to_string(i) );
bool status = image.save(filename);
UF_MSG_DEBUG("Writing to " << filename << ": " << status);
jobs.emplace_back([&, i]{
// auto image = renderMode.screenshot(0, i);
auto image = metadata.buffers.baked.screenshot(i);
uf::stl::string filename = uf::string::replace( metadata.output, "%i", std::to_string(i) );
bool status = image.save(filename);
UF_MSG_DEBUG("Writing to " << filename << ": " << status);
});
}
#if UF_BAKER_SAVE_MULTITHREAD
if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs );
#else
for ( auto& job : jobs ) job();
#endif
UF_MSG_DEBUG("Baked.");
metadata.initialized.map = true;
@ -142,6 +155,8 @@ SAVE: {
ext::json::Value payload;
payload["uid"] = this->getUid();
uf::scene::getCurrentScene().queueHook("system:Destroy", payload);
if ( metadata.trigger.quits ) uf::scene::getCurrentScene().queueHook("system:Quit", payload);
#endif
return;
}

View File

@ -5,6 +5,7 @@
#include <uf/engine/entity/entity.h>
#include <uf/engine/scene/scene.h>
#include <uf/utils/math/vector.h>
#include <uf/utils/renderer/renderer.h>
namespace ext {
namespace BakingBehavior {
@ -39,8 +40,9 @@ namespace ext {
size_t update = 0;
} previous;
struct {
uf::stl::string mode = "key";
uf::stl::string mode = "rendered";
uf::stl::string value = "";
bool quits = true;
} trigger;
struct {
bool renderMode = false;

View File

@ -214,6 +214,9 @@ void EXT_API ext::initialize() {
{
uf::Entity::deleteChildrenOnDestroy = ::json["engine"]["debug"]["entity"]["delete children on destroy"].as( uf::Entity::deleteChildrenOnDestroy );
uf::Entity::deleteComponentsOnDestroy = ::json["engine"]["debug"]["entity"]["delete components on destroy"].as( uf::Entity::deleteComponentsOnDestroy );
uf::Object::assertionLoad = ::json["engine"]["debug"]["loader"]["assert"].as( uf::Object::assertionLoad );
uf::Asset::assertionLoad = ::json["engine"]["debug"]["loader"]["assert"].as( uf::Asset::assertionLoad );
}
{