539 Commits
e2002e ... main

Author SHA1 Message Date
394ab38a80 patch 2026-02-27 00:54:58 -08:00
cc95912a7e Next patch 2026-02-24 23:46:31 -08:00
85a44b930d Node patch 2026-02-24 23:04:47 -08:00
cd3090817a Next patch 2026-02-24 21:30:00 -08:00
d45c632dcd Patch_2 2026-02-24 17:35:26 -08:00
1c3c30e6ce Patch_2 2026-02-24 11:44:01 -08:00
c9839c9be6 Merge pull request 'Patch_2' (#2) from e2002e_0 into main
Reviewed-on: #2
2026-02-24 18:54:11 +00:00
6a17251520 merge upstream 2026-02-24 07:40:25 +00:00
0adcafd697 Patch_1 2026-02-21 22:17:44 -08:00
423807c62f merge upstream 2026-02-21 22:47:25 +00:00
5598161b40 Upload files to "Krom" 2026-02-21 08:05:08 +00:00
e6ac30e57f Delete Krom/Krom.exe 2026-02-21 08:04:28 +00:00
5d1132b24c merge upstream 2026-02-21 07:52:44 +00:00
232ae3e7bc Upload files to "Krom" 2026-02-21 07:50:44 +00:00
a861665c98 Delete Krom/Krom.exe 2026-02-21 07:49:27 +00:00
4852a40848 Delete Krom/Krom 2026-02-21 07:49:09 +00:00
a00f3506ed Update leenkx/blender/lnx/material/cycles_nodes/nodes_vector.py 2026-01-05 07:14:08 +00:00
9aa01e6436 Update leenkx/blender/lnx/material/cycles_nodes/nodes_texture.py 2026-01-05 07:13:51 +00:00
18c564048f Update leenkx/blender/lnx/material/cycles_nodes/nodes_shader.py 2026-01-05 07:13:24 +00:00
da19096658 Update leenkx/blender/lnx/material/cycles_nodes/nodes_converter.py 2026-01-05 07:12:32 +00:00
06343dcca1 Update leenkx/blender/lnx/material/cycles_nodes/nodes_input.py 2026-01-05 07:11:59 +00:00
4375087d3a Update leenkx/blender/lnx/material/cycles_nodes/nodes_vector.py 2025-12-15 02:04:50 +00:00
825f783cbe Update leenkx/blender/lnx/material/cycles_nodes/nodes_texture.py 2025-12-15 02:04:30 +00:00
2f9a24753e Update leenkx/blender/lnx/material/cycles_nodes/nodes_shader.py 2025-12-15 02:04:10 +00:00
07efcaffdb Update leenkx/blender/lnx/material/cycles_nodes/nodes_input.py 2025-12-15 02:03:51 +00:00
a6bef6b35a Update leenkx/blender/lnx/material/cycles_nodes/nodes_color.py 2025-12-15 02:03:07 +00:00
b88f471f0f Update leenkx/blender/lnx/material/cycles_nodes/nodes_converter.py 2025-12-15 02:02:20 +00:00
7e31a73d28 Update leenkx/blender/lnx/lightmapper/utility/encoding.py 2025-12-14 20:30:49 +00:00
7fa4be0b07 Update leenkx/blender/lnx/lightmapper/utility/gui/Viewport.py 2025-12-14 20:29:53 +00:00
d5f3f05ab6 merge upstream 2025-11-14 17:48:37 +00:00
3bee97a560 Update leenkx/blender/lnx/material/cycles.py 2025-11-14 17:41:39 +00:00
4f4f28d62f Merge pull request 'main' (#111) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#111
2025-11-06 16:32:50 +00:00
7076fb6b7e Update leenkx/blender/lnx/material/cycles.py 2025-11-06 16:29:46 +00:00
b72a22b5e9 Update leenkx/blender/lnx/props_ui.py 2025-11-06 16:17:18 +00:00
b265ab863c Update leenkx/blender/lnx/props.py 2025-11-06 16:13:39 +00:00
f5fa754e17 merge upstream 2025-10-03 22:16:29 +00:00
48f5575e4e Update leenkx/Sources/leenkx/logicnode/OnContactNode.hx 2025-10-03 07:56:12 +00:00
f2c4be6336 Update leenkx/Sources/leenkx/logicnode/HasContactNode.hx 2025-10-03 07:55:46 +00:00
2ddc938db8 Update leenkx/Sources/leenkx/logicnode/AnyContactNode.hx 2025-10-03 07:55:14 +00:00
5eb735ada2 Update leenkx/Sources/leenkx/trait/physics/bullet/PhysicsWorld.hx 2025-10-03 07:52:01 +00:00
9894cc20f2 Update leenkx/Sources/leenkx/trait/physics/PhysicsWorld.hx 2025-10-03 07:51:32 +00:00
dbe6d0829a Add leenkx/Sources/leenkx/trait/physics/PhysicsCache.hx 2025-10-03 07:51:07 +00:00
6f383e2ab2 Update leenkx/Sources/leenkx/trait/physics/PhysicsWorld.hx 2025-10-03 05:38:54 +00:00
5c2d29d7ce Update leenkx/Sources/leenkx/trait/physics/bullet/PhysicsWorld.hx 2025-10-03 05:37:50 +00:00
28579e14d7 Update leenkx/Sources/leenkx/logicnode/AnyContactNode.hx 2025-10-03 05:37:06 +00:00
2ec6f43cc5 Update leenkx/Sources/leenkx/logicnode/OnContactNode.hx 2025-10-03 05:36:14 +00:00
027021815a Update leenkx/Sources/leenkx/logicnode/HasContactNode.hx 2025-10-03 05:35:48 +00:00
b9b387803f Add leenkx/blender/lnx/logicnode/physics/LN_any_contact.py 2025-10-03 05:06:23 +00:00
e05d9d0237 Update leenkx/Sources/leenkx/logicnode/HasContactNode.hx 2025-10-03 05:04:48 +00:00
c908e6cad2 Update leenkx/Sources/leenkx/logicnode/OnContactNode.hx 2025-10-03 05:04:18 +00:00
506a0a0245 Add leenkx/Sources/leenkx/logicnode/AnyContactNode.hx 2025-10-03 05:03:29 +00:00
5cf33724e4 Update leenkx/Sources/leenkx/trait/physics/bullet/PhysicsWorld.hx 2025-10-03 05:02:28 +00:00
ac5aa3d19c Merge pull request 'Hashlink fix' (#110) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#110
2025-10-03 03:21:56 +00:00
0c534ee632 Update leenkx/Sources/iron/object/ParticleSystem.hx 2025-10-01 01:42:51 +00:00
69a2bb1e7e merge upstream 2025-09-30 06:02:59 +00:00
e3e7855d26 Merge pull request 'main' (#109) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#109
2025-09-30 05:59:23 +00:00
f7917974f8 Update leenkx/Sources/iron/object/ObjectAnimation.hx 2025-09-30 05:52:44 +00:00
fa2d8f05d5 Update leenkx/Sources/iron/object/ObjectAnimation.hx 2025-09-30 05:35:50 +00:00
5b86f32b51 merge upstream 2025-09-29 22:41:09 +00:00
73fcb55acc Update leenkx/blender/lnx/props_traits.py 2025-09-29 05:28:13 +00:00
c24baa3364 Update leenkx/blender/lnx/props_traits_props.py 2025-09-29 05:27:43 +00:00
4517c4863f Merge pull request 'Downward support to 2.8 LTS!!' (#108) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#108
2025-09-28 20:02:58 +00:00
1299306e09 Update leenkx.py 2025-09-28 20:01:00 +00:00
f97d8fd846 Blender 2.8 - 4.5 Support 2025-09-28 12:44:04 -07:00
8f8d4b1376 Update leenkx/blender/lnx/props_traits.py 2025-09-28 00:09:57 +00:00
a926fa8dbb Update leenkx/blender/lnx/nodes_logic.py 2025-09-27 03:03:08 +00:00
6c3efa6c83 Update leenkx/blender/lnx/props_ui.py 2025-09-24 01:54:38 +00:00
21afad6d09 Update leenkx/blender/lnx/exporter.py 2025-09-24 01:53:43 +00:00
04c6983a09 Update leenkx/Sources/iron/data/SceneFormat.hx 2025-09-24 01:52:47 +00:00
45966ef0bb Update leenkx/blender/lnx/props.py 2025-09-24 01:51:11 +00:00
a72edc6203 Update leenkx/Sources/iron/object/ParticleSystem.hx 2025-09-24 01:50:03 +00:00
6af1ef2df1 Update leenkx/blender/lnx/props_ui.py 2025-09-24 01:33:47 +00:00
46e3047877 Update leenkx/blender/lnx/props.py 2025-09-23 19:57:53 +00:00
de74af215a Merge pull request 'main' (#107) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#107
2025-09-23 17:54:11 +00:00
b6e96553c2 Update leenkx/blender/lnx/lightmapper/utility/build.py 2025-09-19 22:52:01 +00:00
58e009f709 Terrain Generation fix 2025-09-19 21:17:58 +00:00
e88f101ca6 t3du - Particle info random 2025-09-19 19:40:49 +00:00
d28d59b9e6 t3du - Particle info random 2025-09-19 19:38:12 +00:00
a4398c7279 t3du - Particle info random 2025-09-19 19:31:45 +00:00
abedfd799e t3du - Fix World Errors 2025-09-19 19:28:54 +00:00
4520422f6b t3du - Fix World Errors 2025-09-19 19:27:02 +00:00
88418c06c3 t3du - Fix World Errors 2025-09-19 19:25:30 +00:00
aedc2783ab t3du - Labels for finding nodes 2025-09-19 19:22:45 +00:00
1505414c4c t3du - Labels for finding nodes 2025-09-19 19:19:25 +00:00
fa818602c4 t3du - Labels for finding nodes 2025-09-19 19:18:05 +00:00
79dc458671 t3du - Labels for finding nodes 2025-09-19 19:15:41 +00:00
8e635fb1e9 t3du - Labels for finding nodes 2025-09-19 19:11:47 +00:00
4c2e6ab26a t3du - Probabilistic Index Node 2025-09-19 19:09:18 +00:00
2371e3777e t3du - Probabilistic Index Node 2025-09-19 19:08:03 +00:00
b458b77e5c moisesjpelaez - Include external blend files on build 2025-09-19 19:04:43 +00:00
9b76f8cca9 moisesjpelaez - Include external blend files on build 2025-09-19 19:03:22 +00:00
5f2acb209e moisesjpelaez - Include external blend files on build 2025-09-19 19:00:50 +00:00
6fc446e7a9 moisesjpelaez - General Fixes 2025-09-19 18:54:44 +00:00
71e57026e1 moisesjpelaez - General Fixes 2025-09-19 18:53:25 +00:00
5288a98440 moisesjpelaez - General Fixes 2025-09-19 18:49:09 +00:00
35e346be39 moisesjpelaez - General Fixes 2025-09-19 18:39:54 +00:00
843ef0b058 moisesjpelaez - General Fixes 2025-09-19 18:39:14 +00:00
177890bf39 moisesjpelaez - General Fixes 2025-09-19 18:37:01 +00:00
9ac37e6dc7 moisesjpelaez - General Fixes 2025-09-19 18:34:42 +00:00
e697437778 moisesjpelaez - General Fixes 2025-09-19 18:33:44 +00:00
c94fc0fd97 moisesjpelaez - General Fixes 2025-09-19 18:29:52 +00:00
cd0a6f6788 Update leenkx/Sources/iron/data/SceneFormat.hx 2025-09-19 18:28:19 +00:00
4400e0e9c8 moisesjpelaez - General Fixes 2025-09-19 18:27:22 +00:00
20cf07cfc3 moisesjpelaez - General Fixes 2025-09-19 18:25:54 +00:00
1939f19c05 moisesjpelaez - General Fixes 2025-09-19 18:24:19 +00:00
0d2b152ccb moisesjpelaez - General Fixes 2025-09-19 18:15:23 +00:00
7f58e0fc85 moisesjpelaez - General Fixes 2025-09-19 18:13:00 +00:00
0e4a6575c7 moisesjpelaez - General Material Updates 2025-09-19 18:09:04 +00:00
024676f43a moisesjpelaez - General Material Updates 2025-09-19 17:43:54 +00:00
8fe758862c moisesjpelaez - General Material Updates 2025-09-19 17:35:59 +00:00
1f3d1b47ae moisesjpelaez - General Material Updates 2025-09-19 17:34:27 +00:00
f659a3c2be moisesjpelaez - General Material Updates 2025-09-19 17:32:38 +00:00
6eeb9017d4 moisesjpelaez - General Material Updates 2025-09-19 17:30:42 +00:00
afe89c3834 Update leenkx/Sources/iron/data/ShaderData.hx 2025-09-19 17:27:14 +00:00
8b695f72bb moisesjpelaez - General Material Updates 2025-09-19 17:25:03 +00:00
3d99fa60c0 moisesjpelaez - General Material Updates 2025-09-19 17:23:42 +00:00
43be7729ba moisesjpelaez - Tween var 2025-09-19 17:17:41 +00:00
de0b1075c2 moisesjpelaez - Time Fix 2025-09-19 17:13:16 +00:00
c7aba23fa4 t3du - Fix DOF condition 2025-09-19 17:08:21 +00:00
881f3267cc t3du - Fix DOF condition 2025-09-19 17:06:10 +00:00
19b79d61c7 ObiNoWanKenobi - FirstPersonController Changes 2025-09-19 17:03:20 +00:00
fcbab54a0c moisesjpelaez - General Fixes 2025-09-19 16:57:49 +00:00
8fd05d5514 Update leenkx/Sources/leenkx/renderpath/RenderPathForward.hx 2025-08-28 19:21:48 +00:00
ad4013ed75 Update leenkx/Sources/leenkx/renderpath/RenderPathForward.hx 2025-08-28 19:11:31 +00:00
590e6219d5 merge upstream 2025-08-14 23:01:45 +00:00
8ac567b57b Merge pull request 'Update leenkx/Shaders/std/conetrace.glsl' (#104) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#104
2025-08-14 23:01:04 +00:00
43b7ae7060 Update leenkx/Shaders/std/conetrace.glsl 2025-08-14 22:58:57 +00:00
662981fa03 Update leenkx/blender/lnx/material/make_mesh.py 2025-08-14 22:46:53 +00:00
a3866fb604 merge upstream 2025-08-14 21:32:32 +00:00
29e9e71a6a Merge pull request 'main' (#103) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#103
2025-08-14 21:29:54 +00:00
bfb85b0a3b Update leenkx/Sources/iron/Scene.hx 2025-08-14 20:29:28 +00:00
ef99b800e0 Update leenkx/Sources/iron/App.hx 2025-08-14 20:27:20 +00:00
7cca955fc5 Update leenkx/Sources/iron/App.hx 2025-08-14 20:26:33 +00:00
7e7bbd5eae merge upstream 2025-08-14 20:24:23 +00:00
c31b2a18ad Update leenkx/blender/lnx/logicnode/draw/LN_draw_string.py 2025-08-14 19:03:28 +00:00
fb47bf2564 Update leenkx/blender/lnx/logicnode/draw/LN_draw_Text_Area_string.py 2025-08-14 19:01:59 +00:00
7ae6750620 Update leenkx/blender/lnx/logicnode/camera/LN_set_camera_start_end.py 2025-08-14 19:00:58 +00:00
5b87010f76 Update leenkx/Sources/leenkx/trait/internal/DebugConsole.hx 2025-08-14 18:58:52 +00:00
97e952fc15 Update leenkx/Sources/leenkx/logicnode/DrawStringNode.hx 2025-08-14 18:57:13 +00:00
b440539d65 Merge pull request 'main' (#102) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#102
2025-07-23 17:34:02 +00:00
fbf63e4f17 Update leenkx/Shaders/std/brdf.glsl 2025-07-22 23:33:21 +00:00
a318e08072 Update leenkx/Shaders/sss_pass/sss_pass.frag.glsl 2025-07-22 23:20:35 +00:00
7ae458a9dd merge upstream 2025-07-22 23:06:30 +00:00
60a9db6459 Update api/api.hxml 2025-07-22 21:54:56 +00:00
3b5a93c92a Update leenkx/Sources/leenkx/trait/PhysicsBreak.hx 2025-07-22 21:51:25 +00:00
4af990796e t3du - Add TSceneFormat as Trait property type 2025-07-21 23:27:34 +00:00
9fb4916c3c t3du - Add TSceneFormat as Trait property type 2025-07-21 23:24:30 +00:00
f61d5833bb Update leenkx/blender/lnx/exporter.py 2025-07-21 23:15:59 +00:00
40b52be713 t3du - Add TSceneFormat as Trait property type 2025-07-21 23:12:43 +00:00
07d8422f22 Merge pull request 'Update leenkx/Sources/iron/system/Time.hx' (#101) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#101
2025-07-19 20:23:46 +00:00
7179d42b27 Update leenkx/Sources/iron/system/Time.hx 2025-07-19 20:07:08 +00:00
9984615f8c merge upstream 2025-07-17 17:23:34 +00:00
99a5d7d445 Merge pull request 'Update leenkx/Sources/leenkx/logicnode/SetObjectDelayedLocationNode.hx' (#100) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#100
2025-07-17 15:58:08 +00:00
5e0acd3d5d Update leenkx/Sources/leenkx/logicnode/SetObjectDelayedLocationNode.hx 2025-07-16 22:18:14 +00:00
0430e06acd merge upstream 2025-07-16 05:57:15 +00:00
f4077e461b Merge pull request 'Tangazo - Once Node + Set Object Delayed Location Node [ Additional Clean Handler ]' (#99) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#99
2025-07-16 05:23:34 +00:00
28943f1522 Add leenkx/Sources/leenkx/logicnode/SetObjectDelayedLocationNode.hx 2025-07-16 05:15:59 +00:00
df4feac132 Add leenkx/blender/lnx/logicnode/object/LN_set_object_delayed_location.py 2025-07-16 05:14:28 +00:00
82412dbf81 Add leenkx/Sources/leenkx/logicnode/OnceNode.hx 2025-07-15 22:07:02 +00:00
6afc209db7 Add leenkx/blender/lnx/logicnode/logic/LN_once.py 2025-07-15 22:06:11 +00:00
e9aae53be9 t3du - Fix attribute error rp_gi 2025-07-15 19:05:14 +00:00
a65675ef75 Update leenkx/blender/lnx/handlers.py 2025-07-15 17:57:38 +00:00
8f073c5ae1 merge upstream 2025-07-15 17:56:41 +00:00
08d08e42d9 Merge pull request 'improved mouse look node and added missing rigid body settings in Properties > physics > leenkx Props' (#98) from wuaieyo/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#98
2025-07-15 02:59:53 +00:00
a1ee335c68 removed the translation daping and rotation dampign because they would override the alreayd existedt under Dynamics panel 2025-07-13 04:23:51 +02:00
de6bf8a08a added last needed important rigid body settings in the blender RB leenkx settings for game engine ? like min max velocity,damping and lock translation and rotationboolean settings 2025-07-11 19:21:01 +02:00
9622f35b73 Update leenkx/Shaders/std/brdf.glsl 2025-07-10 09:10:43 +00:00
da666e6d23 Update leenkx/blender/lnx/material/cycles_nodes/nodes_shader.py 2025-07-10 09:03:26 +00:00
6ff7804ec1 Update leenkx/Shaders/ssrefr_pass/ssrefr_pass.json 2025-07-10 09:01:58 +00:00
0265ef5b64 Update leenkx/Shaders/ssrefr_pass/ssrefr_pass.frag.glsl 2025-07-10 09:01:28 +00:00
53c5000975 Update leenkx/Shaders/ssrefr_pass/ssrefr_pass.frag.glsl 2025-07-10 09:00:12 +00:00
7647231696 Update leenkx/Shaders/ssrefr_pass/ssrefr_pass.frag.glsl 2025-07-10 08:59:53 +00:00
1e583a795d Update leenkx/blender/lnx/props_renderpath.py 2025-07-10 05:10:54 +00:00
da25d8c313 Update leenkx/Shaders/voxel_resolve_diffuse/voxel_resolve_diffuse.comp.glsl 2025-07-10 01:16:02 +00:00
70695b3b31 Update leenkx/Shaders/deferred_light/deferred_light.frag.glsl 2025-07-10 01:14:03 +00:00
858537d54c revert 2998a5585e
revert Update leenkx/Shaders/ssao_pass/ssao_pass.frag.glsl
2025-07-10 00:58:53 +00:00
2998a5585e Update leenkx/Shaders/ssao_pass/ssao_pass.frag.glsl 2025-07-10 00:57:07 +00:00
c35c59e6a9 Update leenkx/Shaders/voxel_temporal/voxel_temporal.comp.glsl 2025-07-10 00:10:46 +00:00
15ac833f2c Update leenkx/Shaders/std/constants.glsl 2025-07-10 00:09:21 +00:00
8077f00ada Update leenkx/blender/lnx/props_renderpath.py 2025-07-09 23:53:56 +00:00
b9848cd2dc revert e922cc38e6
revert Update leenkx/Shaders/std/shadows.glsl
2025-07-09 23:20:46 +00:00
58140ad583 Update leenkx/Shaders/std/shadows.glsl 2025-07-09 23:18:52 +00:00
e922cc38e6 Update leenkx/Shaders/std/shadows.glsl 2025-07-09 23:17:55 +00:00
9e2b601445 revert 0439dde4a8
revert Update leenkx/Shaders/deferred_light/deferred_light.frag.glsl
2025-07-09 23:16:54 +00:00
0439dde4a8 Update leenkx/Shaders/deferred_light/deferred_light.frag.glsl 2025-07-09 23:15:54 +00:00
57f0e937d0 fixed properties numbering, comments and LNXfactor to LNXFloat 2025-07-08 22:48:16 +02:00
e234c8615c merge upstream 2025-07-08 20:01:27 +00:00
2e7ccb5151 merge upstream 2025-07-06 17:41:02 +00:00
e594518e57 Merge pull request 'main' (#96) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#96
2025-07-06 17:29:11 +00:00
a41be0f436 Update leenkx/blender/lnx/material/cycles_nodes/nodes_input.py 2025-07-06 17:23:04 +00:00
1306033b36 Update leenkx/Sources/leenkx/logicnode/SetParticleDataNode.hx 2025-07-05 22:03:54 +00:00
eee0011cdd Update leenkx/Sources/leenkx/logicnode/GetWorldOrientationNode.hx 2025-07-05 21:52:57 +00:00
315ac0bd16 Update lib/aura/Sources/aura/dsp/panner/StereoPanner.hx 2025-07-05 21:49:10 +00:00
f289e6f89c merge upstream 2025-07-03 07:46:23 +00:00
b89ebfd9c6 Update leenkx/blender/lnx/material/make_refract.py 2025-07-03 04:34:04 +00:00
a142b248ef merge upstream 2025-07-03 04:30:45 +00:00
700d236bf1 Merge pull request 'main' (#94) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#94
2025-07-03 04:12:51 +00:00
f228eab8d3 Add leenkx/Sources/leenkx/logicnode/SetAudioPositionNode.hx 2025-07-03 03:55:23 +00:00
863d884b76 Add leenkx/Sources/leenkx/logicnode/GetAudioPositionNode.hx 2025-07-03 03:54:54 +00:00
34e0f5a282 Add leenkx/blender/lnx/logicnode/custom/LN_set_audio_position.py 2025-07-03 03:53:59 +00:00
45e2e52008 Add leenkx/blender/lnx/logicnode/custom/LN_get_audio_position.py 2025-07-03 03:52:39 +00:00
444a215e63 made default resolution adaptive sensiticity because makes more sense, removed other things since no difference and dunno 2025-07-03 05:27:24 +02:00
fb2d2a1a7c Add leenkx/Sources/leenkx/logicnode/SetPositionSpeakerNode.hx 2025-07-03 01:23:13 +00:00
f88c04abea Add leenkx/Sources/leenkx/logicnode/GetPositionSpeakerNode.hx 2025-07-03 01:22:44 +00:00
6fdd4b3f70 Add leenkx/blender/lnx/logicnode/sound/LN_get_position_speaker.py 2025-07-03 01:21:37 +00:00
a389c27d75 Add leenkx/blender/lnx/logicnode/sound/LN_set_position_speaker.py 2025-07-03 01:20:22 +00:00
1909c3da9f Update leenkx/blender/lnx/material/cycles.py 2025-07-02 15:29:05 +00:00
1c648b0433 merge upstream 2025-07-02 05:19:56 +00:00
5824bd91aa Merge pull request 't3du [ Repe ] - VR Code' (#93) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#93
2025-07-02 05:19:25 +00:00
43fe559eef t3du - Restore VR code 2025-07-02 05:16:53 +00:00
12c09545ce t3du - Restore VR code 2025-07-02 05:15:34 +00:00
0e60951ec9 t3du - Restore VR code 2025-07-02 05:14:05 +00:00
ccb8b358d3 t3du - Restore VR code 2025-07-02 05:11:23 +00:00
3103a976a6 merge upstream 2025-06-30 21:02:24 +00:00
1a8586777b Merge pull request 'main' (#91) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#91
2025-06-30 21:01:50 +00:00
3721c774a1 Update leenkx/blender/lnx/material/node_meta.py 2025-06-30 20:59:56 +00:00
a58fba408d Update leenkx/blender/lnx/material/cycles.py 2025-06-30 20:58:56 +00:00
82fa7bcfe3 merge upstream 2025-06-30 20:40:44 +00:00
268fba6cd5 Merge pull request 'main' (#90) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#90
2025-06-30 20:39:41 +00:00
4ab14ce6c8 merge upstream 2025-06-30 20:39:14 +00:00
9023e8d1da Merge pull request 'added Mouse Look node for FSP style movement of object like camera...' (#89) from wuaieyo/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#89
2025-06-30 20:37:10 +00:00
b58c7a9632 Update leenkx/blender/lnx/material/cycles.py 2025-06-30 20:33:04 +00:00
99b70622f5 Update leenkx/blender/lnx/material/node_meta.py 2025-06-30 20:31:50 +00:00
647b73b746 added Mouse Look node for FSP style movement of object like camera... 2025-06-30 06:35:06 +02:00
935c30ec08 Merge pull request 'main' (#88) from wuaieyo/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#88
2025-06-27 22:39:32 +00:00
0b0d597f89 merge upstream 2025-06-27 22:31:19 +00:00
d5878afb30 Merge pull request 't3du [ Repe ] + Moisesjpelaez Fixes' (#87) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#87
2025-06-27 22:28:35 +00:00
96b55a1a56 t3du - Add SetLightShadowNode for controlling light shadows 2025-06-27 18:03:37 +00:00
91b3072305 t3du - Add SetLightShadowNode for controlling light shadows 2025-06-27 17:57:26 +00:00
1d0b338d92 t3du - Particle export: add support for linked particle info 2025-06-27 17:52:19 +00:00
8e83c0d0d0 moisesjpelaez - Fix linked particle's render object vertex shader export 2025-06-27 17:49:35 +00:00
927baec4df t3du - Show world name in debug console 2025-06-27 17:46:36 +00:00
f5c9e70d1a 1. added local rotation so that if the source object is child then it would still align to the target object. 2. removed rotation output socket since is not really needed. 2025-06-26 03:05:11 +02:00
709e0ed9cb merge upstream 2025-06-24 18:45:57 +00:00
0423a735fc Update leenkx/Sources/leenkx/logicnode/PlayAnimationTreeNode.hx 2025-06-24 18:43:30 +00:00
7bcf985023 merge upstream 2025-06-24 18:24:23 +00:00
bd413917fc Merge pull request 'main' (#84) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#84
2025-06-24 18:18:27 +00:00
852377f60d merge upstream 2025-06-24 18:07:23 +00:00
e17e9a8e35 Merge pull request 'added new set look at rotation node' (#83) from wuaieyo/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#83
2025-06-24 18:06:48 +00:00
4055c979a1 add new Set Look At Rotation Node for making logic nodes great again 2025-06-24 19:47:03 +02:00
06b003ecdb revert 14cf5cebed
revert add new node called Set Look at Rotation
2025-06-24 17:38:18 +00:00
fd7f215bb2 .gitattributes 2025-06-24 17:31:59 +00:00
6a1df9ec46 merge upstream 2025-06-24 17:31:29 +00:00
deccac3c46 Merge pull request '.gitignore' (#81) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#81
2025-06-24 17:21:28 +00:00
432b0210b2 .gitignore 2025-06-24 17:13:27 +00:00
14cf5cebed add new node called Set Look at Rotation 2025-06-24 18:39:16 +02:00
d23232205b merge upstream 2025-06-22 21:38:20 +00:00
2307e1504f Merge pull request 't3du [ Repe ] - Fix particle export' (#78) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#78
2025-06-22 20:25:21 +00:00
1ebfecb644 Update leenkx/blender/lnx/exporter.py 2025-06-22 20:13:33 +00:00
175b575b23 Update leenkx/blender/lnx/exporter.py 2025-06-22 20:12:43 +00:00
63943a9cbf Merge pull request 'Remove pycache folders' (#77) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#77
2025-06-20 20:51:03 +00:00
224d9be76f Remove cache folders 2025-06-20 13:47:02 -07:00
62d3c8757b Update leenkx/blender/lnx/exporter.py 2025-06-20 16:06:08 +00:00
3785f93573 Merge pull request 'main' (#75) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#75
2025-06-20 15:59:18 +00:00
ffb276745f Update leenkx/blender/lnx/exporter.py 2025-06-20 15:55:56 +00:00
d1c9258da5 Update leenkx/blender/lnx/exporter.py 2025-06-20 15:55:29 +00:00
3e0cd2be35 Update leenkx/blender/lnx/props_traits.py 2025-06-20 15:50:09 +00:00
1fd1973470 Update leenkx/blender/lnx/material/make_mesh.py 2025-06-18 17:12:53 +00:00
a01c72ef76 Merge pull request 'Update leenkx/blender/lnx/exporter.py' (#74) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#74
2025-06-17 16:38:21 +00:00
4b01a562c9 Update leenkx/blender/lnx/exporter.py 2025-06-16 02:34:28 +00:00
88c7c5b99e merge upstream 2025-06-13 15:18:22 +00:00
6972d9abc4 Merge pull request 't3du [ Repe ] - Camera Render Filter' (#73) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#73
2025-06-13 15:14:13 +00:00
63c6b9d98b t3du - Camera Render Filter 2025-06-12 22:38:30 +00:00
313d24bbc8 t3du - Camera Render Filter 2025-06-12 22:35:21 +00:00
6d2812306d t3du - Camera Render Filter 2025-06-12 22:23:33 +00:00
e84d6ada84 t3du - Camera Render Filter 2025-06-12 22:21:24 +00:00
5057f2b946 t3du - Camera Render Filter 2025-06-12 22:16:22 +00:00
2715fe3398 t3du - Camera Render Filter 2025-06-12 22:14:08 +00:00
7cb8b8a2d2 t3du - Camera Render Filter 2025-06-12 22:11:59 +00:00
cd606009e0 t3du - Camera Render Filter 2025-06-12 22:10:19 +00:00
965162b101 t3du - Camera Render Filter 2025-06-12 22:08:21 +00:00
c61a57bfb3 t3du - Camera Render Filter 2025-06-12 22:07:16 +00:00
2434ad07f2 merge upstream 2025-06-10 20:28:46 +00:00
cdc425fbcb Update leenkx/Sources/leenkx/logicnode/GetWorldNode.hx 2025-06-10 20:26:59 +00:00
846bb28c86 Merge pull request 't3du [ Repe ] - World Nodes | Resolution PP | Texture Filtering' (#71) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#71
2025-06-10 20:23:04 +00:00
7fabd77ef8 t3du - Resolution post process 2025-06-10 20:12:18 +00:00
fb1a5c88bf t3du - Resolution post process 2025-06-10 20:11:05 +00:00
e05c83a8bb t3du - Resolution post process 2025-06-10 20:08:54 +00:00
ee4f62e881 t3du - Resolution post process 2025-06-10 20:06:49 +00:00
59f8dff22f t3du - Resolution post process 2025-06-10 20:04:37 +00:00
5572226ac5 t3du - Resolution post process 2025-06-10 20:02:59 +00:00
d04874e0b3 t3du - Set / Get World Nodes 2025-06-10 18:55:35 +00:00
ef8b3a99ab t3du - Set / Get World Nodes 2025-06-10 18:52:53 +00:00
1d3254a237 t3du - Set / Get World Nodes 2025-06-10 18:52:26 +00:00
188af4a50f t3du - Set / Get World Nodes 2025-06-10 18:47:00 +00:00
c45baaf396 t3du - Set / Get World Nodes 2025-06-10 18:44:30 +00:00
4b1da08819 t3du - Set / Get World Nodes 2025-06-10 18:42:12 +00:00
aeb353fb20 t3du - Set / Get World Nodes 2025-06-10 18:40:21 +00:00
65961b1593 t3du - Set / Get World Nodes 2025-06-10 18:38:25 +00:00
1c472155e2 t3du - Add material texture filter node 2025-06-10 18:34:09 +00:00
4238f0b2a0 t3du - Add material texture filter node 2025-06-10 18:32:15 +00:00
b40aadf76c t3du - Add material texture filter node 2025-06-10 18:30:27 +00:00
00493bed9c merge upstream 2025-06-07 21:35:02 +00:00
7277987335 Merge pull request 't3du [ Repe ] - Particle Export Option + Dof reference changes' (#68) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#68
2025-06-07 21:15:56 +00:00
a48ec4d034 t3du - Fix DoF references and small changes 2025-06-07 21:12:31 +00:00
7f0153f816 t3du - Fix DoF references and small changes 2025-06-07 21:07:45 +00:00
40d893e139 t3du - Fix DoF references and small changes 2025-06-07 21:06:35 +00:00
9b9289d27d t3du - Fix DoF references and small changes 2025-06-07 20:42:31 +00:00
8786798edd t3du - Fix DoF references and small changes 2025-06-07 20:39:01 +00:00
fa425a98a5 t3du - Add export option for particles 2025-06-07 20:35:01 +00:00
7b17633c28 Update leenkx/blender/lnx/material/make_cluster.py 2025-06-07 19:47:12 +00:00
1ef805eb0b Update leenkx/blender/lnx/material/make_mesh.py 2025-06-06 20:01:29 +00:00
cb7b041fea merge upstream 2025-06-06 19:44:32 +00:00
5165769088 Merge pull request 'main' (#67) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#67
2025-06-06 08:22:34 +00:00
feabf446db Update leenkx/Shaders/std/tonemap.glsl 2025-06-06 07:23:55 +00:00
e770120f7d Update leenkx/blender/lnx/write_data.py 2025-06-06 06:46:55 +00:00
a0e8e1a1a6 merge upstream 2025-06-05 17:49:54 +00:00
7c1b1f2dd9 Merge pull request 't3du [ Repe ] + Moises - Tonemaps / Debugdrawer / Compositor Fixes' (#64) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#64
2025-06-05 17:41:28 +00:00
88a4f0e76a t3du - Clean Compositor 2025-06-05 17:20:09 +00:00
d9e613b3eb moisesjpelaez - Tonemap Fixes 2025-06-05 17:07:50 +00:00
a0c84dc807 moisesjpelaez - CA Fixes 2025-06-05 17:05:08 +00:00
5a92920b1f moisesjpelaez - Tonemap Fixes 2025-06-05 17:03:38 +00:00
30a624c857 Update leenkx/Sources/leenkx/trait/physics/bullet/PhysicsWorld.hx 2025-06-05 00:54:20 +00:00
8153d67eac Update leenkx/Sources/leenkx/trait/physics/bullet/DebugDrawHelper.hx 2025-06-05 00:52:55 +00:00
9963a42c76 Merge pull request 'Shader Fix + moisesjpelaez Aura Fix' (#62) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#62
2025-06-04 19:18:13 +00:00
885385d7cb Update lib/aura/Sources/aura/Time.hx 2025-06-04 19:14:36 +00:00
c433a7f09e Update lib/aura/Sources/aura/threading/Message.hx 2025-06-04 19:13:12 +00:00
c7e2c7d452 Update lib/aura/Sources/aura/dsp/panner/StereoPanner.hx 2025-06-04 19:11:55 +00:00
2a1235b3d8 Update lib/aura/Sources/aura/channels/Html5StreamChannel.hx 2025-06-04 19:10:07 +00:00
074962d158 Update leenkx/blender/lnx/material/cycles_nodes/nodes_shader.py 2025-06-04 19:02:57 +00:00
846c3b2c11 Update leenkx/blender/lnx/material/make_mesh.py 2025-06-03 16:18:05 +00:00
b5af208766 Update leenkx/Shaders/std/shadows.glsl 2025-06-03 03:09:32 +00:00
63565052e3 Disable BayerMatrix momentaraily 2025-06-02 20:37:45 +00:00
38eb66a0b5 Update leenkx/blender/lnx/material/make_cluster.py 2025-06-02 20:35:28 +00:00
908efdd554 Update leenkx/blender/lnx/material/make_mesh.py 2025-06-02 20:33:49 +00:00
e014484d27 merge upstream 2025-06-02 20:16:04 +00:00
3ea0d7da9d Merge pull request 't3du [ Repe ] - Post process updates - New nodes - Physics - Chromatic AB' (#60) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#60
2025-06-02 20:07:26 +00:00
00b580a4fa Update leenkx/blender/lnx/logicnode/postprocess/LN_get_auto_exposure_settings.py 2025-06-02 20:06:50 +00:00
f779462f36 t3du - Post Process Updates 2025-06-02 19:51:11 +00:00
2c7343aa31 t3du - Post Process Updates 2025-06-02 19:47:15 +00:00
85912d84fb Add leenkx/blender/lnx/logicnode/postprocess/LN_set_volumetric_light_settings.py 2025-06-02 19:45:39 +00:00
ad0d750dd0 Add leenkx/blender/lnx/logicnode/postprocess/LN_set_volumetric_fog_settings.py 2025-06-02 19:43:52 +00:00
9914d53045 Add leenkx/blender/lnx/logicnode/postprocess/LN_set_sharpen_settings.py 2025-06-02 19:42:36 +00:00
9daf6c15ab Update leenkx/blender/lnx/logicnode/postprocess/LN_set_auto_exposure_settings.py 2025-06-02 19:40:33 +00:00
9ac3de67aa Update leenkx/blender/lnx/logicnode/postprocess/LN_get_volumetric_light_settings.py 2025-06-02 19:40:05 +00:00
fd02f6bca3 Add leenkx/blender/lnx/logicnode/LN_set_auto_exposure_settings.py 2025-06-02 19:39:13 +00:00
2cc0d3db3b Add leenkx/blender/lnx/logicnode/LN_get_volumetric_light_settings.py 2025-06-02 19:38:01 +00:00
fe730a65ee Add leenkx/blender/lnx/logicnode/postprocess/LN_get_volumetric_fog_settings.py 2025-06-02 19:35:27 +00:00
18ec9712fd Add leenkx/blender/lnx/logicnode/postprocess/LN_get_sharpen_settings.py 2025-06-02 19:25:19 +00:00
0d80f3fb6d Add leenkx/blender/lnx/logicnode/postprocess/LN_get_auto_exposure_settings.py 2025-06-02 19:21:53 +00:00
be06b222cb t3du - Post Process Updates 2025-06-02 19:14:54 +00:00
3f0984e227 Update leenkx/blender/lnx/props_ui.py 2025-06-02 19:13:12 +00:00
15a10ea3aa t3du - Post Process Updates 2025-06-02 19:12:33 +00:00
012abfeaf6 t3du - Post Process Updates 2025-06-02 19:11:02 +00:00
dd6cd16661 t3du - Post Process Updates 2025-06-02 19:01:21 +00:00
d8b37efe1b Add leenkx/Sources/leenkx/logicnode/VolumetricLightSetNode.hx 2025-06-02 18:57:18 +00:00
a40a035c03 Add leenkx/Sources/leenkx/logicnode/VolumetricLightGetNode.hx 2025-06-02 18:56:31 +00:00
a318758cbf Add leenkx/Sources/leenkx/logicnode/VolumetricFogSetNode.hx 2025-06-02 18:36:55 +00:00
7c13a25caf Add leenkx/Sources/leenkx/logicnode/VolumetricFogGetNode.hx 2025-06-02 18:36:11 +00:00
141567467f Add leenkx/Sources/leenkx/logicnode/SharpenSetNode.hx 2025-06-02 18:35:24 +00:00
047983a280 Add leenkx/Sources/leenkx/logicnode/SharpenGetNode.hx 2025-06-02 18:34:24 +00:00
48ad4322cf t3du - Post Process Updates 2025-06-02 18:33:21 +00:00
eaa34308d0 Add leenkx/Sources/leenkx/logicnode/AutoExposureSetNode.hx 2025-06-02 18:28:33 +00:00
741a12de78 Add leenkx/Sources/leenkx/logicnode/AutoExposureGetNode.hx 2025-06-02 18:27:31 +00:00
9749467cd7 t3du - Post Process Updates 2025-06-02 18:25:19 +00:00
91ae053346 t3du - Post Process Updates 2025-06-02 18:21:47 +00:00
b7b7edb5e2 t3du - Post Process Updates 2025-06-02 18:19:16 +00:00
dfa99fcb14 t3du - Post Process Updates 2025-06-02 18:18:36 +00:00
bc0bf41b91 t3du - Post Process Updates 2025-06-02 18:17:17 +00:00
535e69dcd0 t3du - Post Process Updates 2025-06-02 18:15:45 +00:00
2eaf83d89c t3du - Post Process Updates 2025-06-02 18:09:31 +00:00
6e62917819 t3du - Post Process Updates 2025-06-02 18:08:41 +00:00
03106eff02 t3du - Particle nodes Update 2025-06-02 18:01:58 +00:00
0c5d71ecd2 t3du - Particle nodes Update 2025-06-02 18:00:15 +00:00
d6a7b7e305 t3du - Particle nodes Update 2025-06-02 17:58:15 +00:00
3d91f2f1e7 t3du - Particle nodes Update 2025-06-02 17:54:31 +00:00
d76c295786 t3du - Krom path condition 2025-06-02 17:48:09 +00:00
79422337ae t3du - CA Updates 2025-06-02 17:35:46 +00:00
b0e624ef75 t3du - CA Updates 2025-06-02 17:34:59 +00:00
9d78aabf35 t3du - CA Updates 2025-06-02 17:33:15 +00:00
a3930d7761 t3du - CA Updates 2025-06-02 17:31:13 +00:00
c958113c94 Update leenkx/blender/lnx/logicnode/postprocess/LN_set_ca_settings.py 2025-06-02 17:27:27 +00:00
385c683fe3 t3du - CA Updates 2025-06-02 17:25:33 +00:00
1050337751 t3du - CA Updates 2025-06-02 17:20:59 +00:00
114bf7544a t3du - CA Updates 2025-06-02 17:14:44 +00:00
0199ee9877 t3du - CA Updates 2025-06-02 17:09:28 +00:00
6e02aeee53 t3du - CA Updates 2025-06-02 17:06:56 +00:00
6c3d71c4c9 t3du - CA Updates 2025-06-02 17:05:30 +00:00
78592b245f t3du - CA Updates 2025-06-02 17:04:55 +00:00
80d4422c90 t3du - CA Updates 2025-06-02 17:03:41 +00:00
32df55d636 t3du - CA Updates 2025-06-02 17:00:57 +00:00
eede86e278 Update leenkx/blender/lnx/props_ui.py 2025-06-02 16:47:43 +00:00
1b855f953f t3du - Ies Texture and Cloud Texture: improvements 2025-06-02 16:46:01 +00:00
59df400b0d t3du - Ies Texture and Cloud Texture: improvements 2025-06-02 16:44:08 +00:00
4af244e3e2 Merge pull request 'moisesjpelaez - Fix pausing and resuming updates' (#59) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#59
2025-06-02 16:35:35 +00:00
ae91f8801f moisesjpelaez - Fix pausing and resuming updates 2025-06-02 16:32:28 +00:00
7f5786d47c moisesjpelaez - Fix pausing and resuming updates 2025-06-02 16:24:22 +00:00
ea12d5b951 moisesjpelaez - Fix pausing and resuming updates 2025-06-02 16:21:25 +00:00
d37468a6ab Merge pull request 'moisesjpelaez - FixedUpdate - Physics Improvements - Private Fields' (#58) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#58
2025-06-02 16:01:44 +00:00
d0b3dc2ff8 moisesjpelaez - Physics Improvements 2025-06-02 07:24:53 +00:00
85bbc10d06 moisesjpelaez - Physics Improvements 2025-06-02 06:31:14 +00:00
2fca73aebd moisesjpelaez - Physics Improvements 2025-06-02 06:26:11 +00:00
8b187940ee moisesjpelaez - Physics Improvements 2025-06-02 06:22:23 +00:00
00369aa90b moisesjpelaez - Physics Improvements 2025-06-02 04:18:44 +00:00
26a10020ac moisesjpelaez - Physics Improvements 2025-06-02 04:12:58 +00:00
421463a642 moisesjpelaez - Physics Improvements 2025-06-02 04:11:02 +00:00
8d9f248d2f moisesjpelaez - Physics Improvements 2025-06-02 04:06:31 +00:00
ed72206a26 moisesjpelaez - Physics Improvements 2025-06-01 23:52:22 +00:00
6b7460dd4c moisesjpelaez - Add particles random size
* Revert
2025-06-01 23:46:05 +00:00
447af740be moisesjpelaez - Framerate and delta fixes 2025-06-01 23:33:30 +00:00
3ff6c32ac9 moisesjpelaez - Framerate and delta fixes 2025-06-01 23:31:49 +00:00
b752d70109 moisesjpelaez - Framerate and delta fixes 2025-06-01 23:29:57 +00:00
a6f83e2d37 moisesjpelaez - Framerate and delta fixes 2025-06-01 23:29:09 +00:00
016e223fb8 moisesjpelaez - Add fixedUpdate for Physics 2025-06-01 23:18:35 +00:00
502601e684 moisesjpelaez - Add fixedUpdate for Physics 2025-06-01 23:17:23 +00:00
29a4bb6803 moisesjpelaez - Add fixedUpdate for Physics 2025-06-01 23:14:43 +00:00
cfbe7c83cb moisesjpelaez - Add fixedUpdate for Physics 2025-06-01 23:09:47 +00:00
a6d9cb9201 moisesjpelaez - Physics Private Fields 2025-06-01 23:02:50 +00:00
32cdbd8c54 moisesjpelaez - Physics Private Fields 2025-06-01 22:57:47 +00:00
1a17b646e4 moisesjpelaez - Physics Private Fields 2025-06-01 22:56:48 +00:00
cdf79de36b moisesjpelaez - Physics Private Fields 2025-06-01 22:55:55 +00:00
2aa6be6496 moisesjpelaez - Physics Private Fields 2025-06-01 22:52:16 +00:00
25c391d244 moisesjpelaez - Physics Improvements 2025-06-01 22:17:30 +00:00
a3c2be4e79 moisesjpelaez - Physics Improvements 2025-06-01 22:16:29 +00:00
3413e10134 moisesjpelaez - Physics Improvements 2025-06-01 22:11:11 +00:00
fa91348428 moisesjpelaez - Physics Improvements 2025-06-01 21:58:58 +00:00
d40d3eb96e moisesjpelaez - Physics Improvements 2025-06-01 21:56:06 +00:00
16e019be26 moisesjpelaez - Physics Improvements 2025-06-01 21:53:31 +00:00
2e77f67683 moisesjpelaez - Physics Improvements 2025-06-01 21:51:09 +00:00
9824dc5a44 moisesjpelaez - General Fixes 2025-06-01 20:52:08 +00:00
872433cafb Update leenkx/Shaders/voxel_temporal/voxel_temporal.comp.glsl 2025-06-01 03:42:22 +00:00
74bbb6ca87 Update leenkx/Shaders/voxel_sdf_jumpflood/voxel_sdf_jumpflood.comp.glsl 2025-06-01 03:41:14 +00:00
cbbd6fe495 Update leenkx/Shaders/voxel_offsetprev/voxel_offsetprev.comp.glsl 2025-06-01 03:40:37 +00:00
45a48acf8a Update leenkx/Sources/leenkx/renderpath/Inc.hx 2025-06-01 03:39:35 +00:00
1c20e03e0c Update leenkx/blender/lnx/material/cycles_nodes/nodes_converter.py 2025-05-31 06:07:19 +00:00
c769b3ca26 merge upstream 2025-05-30 21:46:34 +00:00
98f334c883 Merge pull request 'Update get_scene function call' (#57) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#57
2025-05-30 21:43:15 +00:00
8ac8a780e1 Update leenkx/blender/lnx/write_data.py 2025-05-30 21:38:01 +00:00
25e5700084 Update leenkx/blender/lnx/make_renderpath.py 2025-05-30 21:34:37 +00:00
c4378be891 Update leenkx/Shaders/voxel_temporal/voxel_temporal.comp.glsl 2025-05-30 19:19:33 +00:00
6ad615a961 Update leenkx/Shaders/std/constants.glsl 2025-05-30 19:18:06 +00:00
1e4510ba56 Update leenkx/Shaders/std/conetrace.glsl 2025-05-30 19:16:59 +00:00
a2714bf101 merge upstream 2025-05-30 19:10:59 +00:00
5639234eb9 Update leenkx/Shaders/std/light.glsl 2025-05-29 21:22:25 +00:00
1591ccdae5 Update leenkx/Shaders/deferred_light/deferred_light.json 2025-05-29 16:56:38 +00:00
9cb5232187 Update leenkx/Shaders/deferred_light/deferred_light.frag.glsl 2025-05-29 16:53:10 +00:00
28d60a652b Merge pull request 't3du [ Repe ] - New features + Fixes' (#56) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#56
2025-05-28 23:33:34 +00:00
778be03472 t3du - Fix scene exposure setting 2025-05-28 23:04:39 +00:00
fff8b5c29e t3du - Fix scene exposure setting 2025-05-28 23:02:14 +00:00
a70d0bd601 t3du - New Image nodes: Draw Sub Image and Write Image 2025-05-28 22:37:36 +00:00
8fc14ac793 t3du - New Image nodes: Draw Sub Image and Write Image 2025-05-28 22:35:28 +00:00
13add8f60b t3du - New Image nodes: Draw Sub Image and Write Image 2025-05-28 22:32:37 +00:00
2c1605c855 t3du - New Image nodes: Draw Sub Image and Write Image 2025-05-28 22:31:56 +00:00
3524676fcc t3du - New Image nodes: Draw Sub Image and Write Image 2025-05-28 22:30:42 +00:00
a577d57263 t3du - New Image nodes: Draw Sub Image and Write Image 2025-05-28 22:29:07 +00:00
58440bb347 t3du - New Image nodes: Draw Sub Image and Write Image 2025-05-28 22:26:33 +00:00
f3808c4251 t3du - New Image nodes: Draw Sub Image and Write Image 2025-05-28 22:24:50 +00:00
95c08e3424 t3du - Fix draw camera texture node 2025-05-28 22:15:48 +00:00
ce762b3cfa t3du - Fix draw camera texture node 2025-05-28 22:11:50 +00:00
15bcf4a374 t3du - Fix Desc 2025-05-28 22:08:06 +00:00
634aaa0b6a t3du - Fix Desc 2025-05-28 22:07:49 +00:00
69fc090f55 t3du - Conditional Shader Nodes 4.0 + 2025-05-28 21:44:06 +00:00
f42041ccb6 t3du - Delete Traces 2025-05-28 21:35:44 +00:00
a8787bd315 t3du - Delete Traces 2025-05-28 21:34:42 +00:00
b5e77aeef8 t3du - Add Brick Texture 2025-05-28 21:30:38 +00:00
f379685fdd t3du - Add Brick Texture 2025-05-28 21:25:25 +00:00
32ff286691 Merge pull request 't3du [ Repe ] - Lightmapper fix: update ShaderNodeMixRGB to ShaderNodeMix and 4. above support' (#55) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#55
2025-05-28 02:46:47 +00:00
38ab682978 Update leenkx/blender/lnx/lightmapper/utility/utility.py 2025-05-28 02:32:27 +00:00
8efe115698 Update leenkx/blender/lnx/lightmapper/utility/gui/Viewport.py 2025-05-28 02:21:24 +00:00
38f72101eb Update leenkx/blender/lnx/lightmapper/utility/cycles/prepare.py 2025-05-28 02:06:48 +00:00
f6d03b060c Update leenkx/blender/lnx/lightmapper/utility/cycles/nodes.py 2025-05-28 02:05:04 +00:00
f450c00ff1 Merge pull request 't3du (Repe) - New Particle Nodes!' (#54) from Onek8/LNXSDK:main into main
Reviewed-on: LeenkxTeam/LNXSDK#54
2025-05-28 01:54:21 +00:00
6b25d8c8ad revert 13ca31f480
revert Update leenkx/Sources/leenkx/renderpath/Inc.hx
2025-05-28 01:36:04 +00:00
13ca31f480 Update leenkx/Sources/leenkx/renderpath/Inc.hx 2025-05-28 01:28:14 +00:00
d102e59040 Update leenkx/blender/lnx/material/make_voxel.py 2025-05-27 18:53:36 +00:00
df0e24c307 Update leenkx/Shaders/voxel_temporal/voxel_temporal.comp.glsl 2025-05-27 18:42:41 +00:00
2df86850f8 Update leenkx/Shaders/std/constants.glsl 2025-05-27 17:51:56 +00:00
02ff259860 Update leenkx/blender/lnx/material/make_finalize.py 2025-05-27 17:23:03 +00:00
2e6de515ef Update leenkx/Shaders/voxel_temporal/voxel_temporal.comp.glsl 2025-05-26 23:29:54 +00:00
41b840212c Update leenkx/blender/lnx/props_ui.py 2025-05-26 23:25:50 +00:00
751f960b82 Update leenkx/blender/lnx/logicnode/__init__.py 2025-05-22 22:06:41 +00:00
9558ded5c4 Update leenkx/Sources/iron/object/ParticleSystem.hx 2025-05-22 22:03:44 +00:00
8066756605 Update leenkx/Sources/iron/object/ParticleSystem.hx 2025-05-22 22:02:56 +00:00
ac2507e0ae Update leenkx/Sources/iron/object/MeshObject.hx 2025-05-22 22:00:56 +00:00
205d4ccc41 Update leenkx/Sources/iron/Scene.hx 2025-05-22 21:52:06 +00:00
7565818d0e Upload files to "leenkx/Sources/leenkx/logicnode" 2025-05-22 21:47:32 +00:00
fc093eca3e Upload files to "leenkx/Sources/leenkx/logicnode" 2025-05-22 21:46:21 +00:00
61b8f21037 Update leenkx/Sources/leenkx/logicnode/SetParticleSpeedNode.hx 2025-05-22 21:42:53 +00:00
d988ce8c99 Delete leenkx/blender/lnx/logicnode/animation/LN_set_particle_speed.py 2025-05-22 21:39:32 +00:00
727d82f268 Upload files to "leenkx/blender/lnx/logicnode/particle" 2025-05-22 21:39:10 +00:00
c3c89c320b Upload files to "leenkx/blender/lnx/logicnode/particle" 2025-05-22 21:36:22 +00:00
0b5bb877fb Add leenkx/blender/lnx/logicnode/particle/__init__.py 2025-05-22 21:35:22 +00:00
429e6d6768 Update leenkx/Shaders/std/constants.glsl 2025-05-22 19:30:19 +00:00
2d8bfbf181 Update leenkx/Sources/leenkx/renderpath/RenderPathForward.hx 2025-05-22 03:07:01 +00:00
1ad7e0eaf4 Update leenkx/Sources/leenkx/renderpath/RenderPathDeferred.hx 2025-05-22 03:03:50 +00:00
ae72401657 Update leenkx/Sources/leenkx/renderpath/Inc.hx 2025-05-22 02:57:45 +00:00
58b9000305 Update leenkx/Shaders/voxel_temporal/voxel_temporal.comp.glsl 2025-05-22 02:27:46 +00:00
0cc86c41b8 Update leenkx/Shaders/voxel_resolve_specular/voxel_resolve_specular.comp.glsl 2025-05-22 02:25:46 +00:00
25f8c5f64c Update leenkx/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl 2025-05-22 02:24:58 +00:00
109544cea9 Update leenkx/Shaders/std/light.glsl 2025-05-22 02:20:28 +00:00
4c92c4bcc9 Update leenkx/Shaders/std/conetrace.glsl 2025-05-22 02:16:35 +00:00
3433afb1c3 Update leenkx/Shaders/ssrefr_pass/ssrefr_pass.frag.glsl 2025-05-22 02:14:06 +00:00
e22b522059 Update leenkx/Shaders/deferred_light/deferred_light.frag.glsl 2025-05-22 02:10:45 +00:00
200af34740 Update leenkx/Shaders/blur_edge_pass/blur_edge_pass.frag.glsl 2025-05-22 02:07:44 +00:00
6d7b0078b4 Update leenkx/blender/lnx/props_renderpath.py 2025-05-21 23:26:42 +00:00
fa501cb09b Update leenkx/blender/lnx/write_data.py 2025-05-21 23:18:53 +00:00
62a4bbb714 Update leenkx/blender/lnx/props_ui.py 2025-05-21 23:14:37 +00:00
eab3e3b30c Update leenkx/blender/lnx/props_renderpath.py 2025-05-21 23:07:11 +00:00
3be7528a6c Update leenkx/blender/lnx/material/make_voxel.py 2025-05-21 22:58:06 +00:00
c9dd46c5e3 Update leenkx/blender/lnx/material/make_shader.py 2025-05-21 22:56:05 +00:00
99806b8069 revert e98bfb125d
revert Update leenkx/blender/lnx/material/make_shader.py
2025-05-21 22:51:16 +00:00
e98bfb125d Update leenkx/blender/lnx/material/make_shader.py 2025-05-21 22:47:03 +00:00
c4c0e2beaa Delete leenkx/blender/lnx/material/make_refraction_buffer.py 2025-05-21 22:43:18 +00:00
36cbc934ba Update leenkx/blender/lnx/material/make_finalize.py 2025-05-21 22:42:11 +00:00
210d5ea532 Update leenkx/blender/lnx/material/make_finalize.py 2025-05-21 22:39:52 +00:00
dab9a38424 Update leenkx/blender/lnx/material/make_mesh.py 2025-05-21 22:37:15 +00:00
b7bbe40348 Update leenkx/blender/lnx/material/make_cluster.py 2025-05-21 22:33:01 +00:00
8b084156ff Update leenkx/blender/lnx/make_world.py 2025-05-21 22:29:40 +00:00
538c364f33 Update leenkx/blender/lnx/make_renderpath.py 2025-05-21 22:26:58 +00:00
09eee93ac9 Update leenkx/Sources/iron/object/Uniforms.hx 2025-05-21 16:25:58 +00:00
8b5a77c001 Update leenkx/Sources/leenkx/renderpath/RenderPathForward.hx 2025-05-21 16:23:20 +00:00
436b7fac02 Update leenkx/Sources/leenkx/renderpath/RenderPathDeferred.hx 2025-05-21 16:21:05 +00:00
9ef9f5a637 Update leenkx/Sources/leenkx/renderpath/Inc.hx 2025-05-21 16:15:50 +00:00
b8ca4be56a Update leenkx/Shaders/voxel_temporal/voxel_temporal.comp.glsl 2025-05-21 16:08:14 +00:00
29e4993f06 Update leenkx/Shaders/voxel_sdf_jumpflood/voxel_sdf_jumpflood.comp.glsl 2025-05-21 16:05:53 +00:00
4134352688 Update leenkx/Shaders/voxel_resolve_specular/voxel_resolve_specular.comp.glsl 2025-05-21 02:10:21 +00:00
25cf758a33 Update leenkx/Shaders/voxel_resolve_diffuse/voxel_resolve_diffuse.comp.glsl 2025-05-21 02:08:50 +00:00
23af038a16 Update leenkx/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl 2025-05-21 02:07:21 +00:00
7f7878aaa6 Update leenkx/Shaders/voxel_offsetprev/voxel_offsetprev.comp.glsl 2025-05-21 02:05:33 +00:00
d7e076fb56 Add leenkx/Shaders/voxel_light/voxel_light.comp.glsl 2025-05-21 02:02:05 +00:00
dab915b60d Delete leenkx/Shaders/voxel_light.comp.glsl 2025-05-21 02:01:43 +00:00
74389ba76a Add leenkx/Shaders/voxel_light.comp.glsl 2025-05-21 02:01:35 +00:00
bd5afc797d Update leenkx/Shaders/std/shadows.glsl 2025-05-21 01:05:37 +00:00
27b4ec42a8 Update leenkx/Shaders/std/light.glsl 2025-05-21 01:04:30 +00:00
ab7edaa9e3 Update leenkx/Shaders/std/constants.glsl 2025-05-21 01:02:56 +00:00
27540ac7e9 Update leenkx/Shaders/std/conetrace.glsl 2025-05-21 01:01:47 +00:00
a5b512f20b Update leenkx/Shaders/ssrefr_pass/ssrefr_pass.frag.glsl 2025-05-21 00:55:14 +00:00
f8d0e67f33 Update leenkx/Shaders/ssr_pass/ssr_pass.frag.glsl 2025-05-21 00:51:33 +00:00
915118617d Update leenkx/Shaders/ssgi_pass/ssgi_pass.json 2025-05-21 00:50:45 +00:00
ea69511e67 Update leenkx/Shaders/ssgi_pass/ssgi_pass.frag.glsl 2025-05-21 00:47:22 +00:00
3926a7f83e Update leenkx/Shaders/deferred_light/deferred_light.json 2025-05-21 00:42:00 +00:00
0eafd14ae2 Update leenkx/Shaders/deferred_light/deferred_light.frag.glsl 2025-05-21 00:40:56 +00:00
08614512d7 Update leenkx/Shaders/blur_edge_pass/blur_edge_pass.frag.glsl 2025-05-21 00:19:31 +00:00
08261a9335 Update leenkx/Shaders/blur_edge_pass/blur_edge_pass.frag.glsl 2025-05-21 00:16:55 +00:00
ce3c1cea6a Delete leenkx/Shaders/voxel_resolve_shadows/voxel_resolve_shadows.comp.glsl 2025-05-21 00:00:40 +00:00
392d12a816 Delete leenkx/Shaders/voxel_resolve_refraction/voxel_resolve_refraction.comp.glsl 2025-05-21 00:00:32 +00:00
6b423038d4 Delete leenkx/Shaders/voxel_light/voxel_light.comp.glsl 2025-05-21 00:00:02 +00:00
76628fc010 Add leenkx/Shaders/std/aabb.glsl 2025-05-20 23:57:25 +00:00
99f687b10c Update leenkx/Shaders/std/constants.glsl 2025-05-20 23:55:32 +00:00
1019 changed files with 19722 additions and 4227 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
*.hdr binary
blender/lnx/props.py ident

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
__pycache__/
*.pyc
*.DS_Store
**/workspace.xml
**/vcs.xml

View File

@ -227,7 +227,7 @@ class SystemImpl {
} }
static inline var maxGamepads: Int = 4; static inline var maxGamepads: Int = 4;
static var frame: Framebuffer; public static var frame: Framebuffer;
static var keyboard: Keyboard = null; static var keyboard: Keyboard = null;
static var mouse: kha.input.Mouse; static var mouse: kha.input.Mouse;
static var surface: Surface; static var surface: Surface;
@ -388,7 +388,8 @@ class SystemImpl {
{ {
alpha: false, alpha: false,
antialias: options.framebuffer.samplesPerPixel > 1, antialias: options.framebuffer.samplesPerPixel > 1,
stencil: true stencil: true,
xrCompatible: true
}); // preserveDrawingBuffer: true } ); Warning: preserveDrawingBuffer can cause huge performance issues on mobile browsers }); // preserveDrawingBuffer: true } ); Warning: preserveDrawingBuffer can cause huge performance issues on mobile browsers
SystemImpl.gl.pixelStorei(GL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1); SystemImpl.gl.pixelStorei(GL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
@ -417,7 +418,8 @@ class SystemImpl {
{ {
alpha: false, alpha: false,
antialias: options.framebuffer.samplesPerPixel > 1, antialias: options.framebuffer.samplesPerPixel > 1,
stencil: true stencil: true,
xrCompatible: true
}); // preserveDrawingBuffer: true } ); WARNING: preserveDrawingBuffer causes huge performance issues (on mobile browser)! }); // preserveDrawingBuffer: true } ); WARNING: preserveDrawingBuffer causes huge performance issues (on mobile browser)!
SystemImpl.gl.pixelStorei(GL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1); SystemImpl.gl.pixelStorei(GL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
SystemImpl.gl.getExtension("OES_texture_float"); SystemImpl.gl.getExtension("OES_texture_float");
@ -547,6 +549,12 @@ class SystemImpl {
]; ];
function animate(timestamp) { function animate(timestamp) {
if (untyped Browser.window._khaSkipWindowRender == true) {
if (requestAnimationFrame != null)
requestAnimationFrame(animate);
return;
}
if (requestAnimationFrame == null) if (requestAnimationFrame == null)
Browser.window.setTimeout(animate, 1000.0 / 60.0); Browser.window.setTimeout(animate, 1000.0 / 60.0);
else else

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -157,4 +157,5 @@ extern class Krom {
static function getConstantLocationCompute(shader: Dynamic, name: String): Dynamic; static function getConstantLocationCompute(shader: Dynamic, name: String): Dynamic;
static function getTextureUnitCompute(shader: Dynamic, name: String): Dynamic; static function getTextureUnitCompute(shader: Dynamic, name: String): Dynamic;
static function compute(x: Int, y: Int, z: Int): Void; static function compute(x: Int, y: Int, z: Int): Void;
static function viewportSetCamera(posX: Float, posY: Float, posZ: Float, rotX: Float, rotY: Float, rotZ: Float, rotW: Float): Void;
} }

Binary file not shown.

View File

@ -2,10 +2,12 @@
-cp ../Kha/Backends/Krom -cp ../Kha/Backends/Krom
-cp ../leenkx/Sources -cp ../leenkx/Sources
-cp ../iron/Sources -cp ../iron/Sources
-cp ../lib/aura/Sources
-cp ../lib/haxebullet/Sources -cp ../lib/haxebullet/Sources
-cp ../lib/haxerecast/Sources -cp ../lib/haxerecast/Sources
-cp ../lib/zui/Sources -cp ../lib/zui/Sources
--macro include('iron', true, null, ['../iron/Sources']) --macro include('iron', true, null, ['../iron/Sources'])
--macro include('aura', true, null, ['../lib/aura/Sources'])
--macro include('haxebullet', true, null, ['../lib/haxebullet/Sources']) --macro include('haxebullet', true, null, ['../lib/haxebullet/Sources'])
--macro include('haxerecast', true, null, ['../lib/haxerecast/Sources']) --macro include('haxerecast', true, null, ['../lib/haxerecast/Sources'])
--macro include('leenkx', true, ['leenkx.network'], ['../leenkx/Sources','../iron/Sources']) --macro include('leenkx', true, ['leenkx.network'], ['../leenkx/Sources','../iron/Sources'])

View File

@ -24,7 +24,7 @@ import textwrap
import threading import threading
import traceback import traceback
import typing import typing
from typing import Callable, Optional from typing import Callable, Optional, List
import webbrowser import webbrowser
import bpy import bpy
@ -33,6 +33,12 @@ from bpy.props import *
from bpy.types import Operator, AddonPreferences from bpy.types import Operator, AddonPreferences
if bpy.app.version < (2, 90, 0):
ListType = List
else:
ListType = list
class SDKSource(IntEnum): class SDKSource(IntEnum):
PREFS = 0 PREFS = 0
LOCAL = 1 LOCAL = 1
@ -73,9 +79,10 @@ def detect_sdk_path():
area = win.screen.areas[0] area = win.screen.areas[0]
area_type = area.type area_type = area.type
area.type = "INFO" area.type = "INFO"
with bpy.context.temp_override(window=win, screen=win.screen, area=area): if bpy.app.version >= (2, 92, 0):
bpy.ops.info.select_all(action='SELECT') with bpy.context.temp_override(window=win, screen=win.screen, area=area):
bpy.ops.info.report_copy() bpy.ops.info.select_all(action='SELECT')
bpy.ops.info.report_copy()
area.type = area_type area.type = area_type
clipboard = bpy.context.window_manager.clipboard clipboard = bpy.context.window_manager.clipboard
@ -85,6 +92,7 @@ def detect_sdk_path():
if match: if match:
addon_prefs.sdk_path = os.path.dirname(match[-1]) addon_prefs.sdk_path = os.path.dirname(match[-1])
def get_link_web_server(self): def get_link_web_server(self):
return self.get('link_web_server', 'http://localhost/') return self.get('link_web_server', 'http://localhost/')
@ -558,7 +566,7 @@ def remove_readonly(func, path, excinfo):
func(path) func(path)
def run_proc(cmd: list[str], done: Optional[Callable[[bool], None]] = None): def run_proc(cmd: ListType[str], done: Optional[Callable[[bool], None]] = None):
def fn(p, done): def fn(p, done):
p.wait() p.wait()
if done is not None: if done is not None:
@ -840,7 +848,13 @@ def update_leenkx_py(sdk_path: str, force_relink=False):
else: else:
raise err raise err
else: else:
lnx_module_file.unlink(missing_ok=True) if bpy.app.version < (2, 92, 0):
try:
lnx_module_file.unlink()
except FileNotFoundError:
pass
else:
lnx_module_file.unlink(missing_ok=True)
shutil.copy(Path(sdk_path) / 'leenkx.py', lnx_module_file) shutil.copy(Path(sdk_path) / 'leenkx.py', lnx_module_file)

View File

@ -3,6 +3,10 @@
#include "compiled.inc" #include "compiled.inc"
#ifdef _CPostprocess
uniform vec4 PPComp17;
#endif
uniform sampler2D tex; uniform sampler2D tex;
uniform vec2 dir; uniform vec2 dir;
uniform vec2 screenSize; uniform vec2 screenSize;
@ -45,6 +49,12 @@ void main() {
res += factor * col; res += factor * col;
} }
#ifdef _CPostprocess
vec3 AirColor = vec3(PPComp17.x, PPComp17.y, PPComp17.z);
#else
vec3 AirColor = volumAirColor;
#endif
res /= sumfactor; res /= sumfactor;
fragColor = vec4(volumAirColor * res, 1.0); fragColor = vec4(AirColor * res, 1.0);
} }

View File

@ -19,6 +19,11 @@
{ {
"name": "screenSize", "name": "screenSize",
"link": "_screenSize" "link": "_screenSize"
},
{
"name": "PPComp17",
"link": "_PPComp17",
"ifdef": ["_CPostprocess"]
} }
], ],
"texture_params": [], "texture_params": [],

View File

@ -5,7 +5,7 @@
uniform sampler2D tex; uniform sampler2D tex;
#ifdef _CPostprocess #ifdef _CPostprocess
uniform vec3 PPComp13; uniform vec4 PPComp13;
#endif #endif
in vec2 texCoord; in vec2 texCoord;
@ -14,7 +14,7 @@ out vec4 fragColor;
vec2 barrelDistortion(vec2 coord, float amt) { vec2 barrelDistortion(vec2 coord, float amt) {
vec2 cc = coord - 0.5; vec2 cc = coord - 0.5;
float dist = dot(cc, cc); float dist = dot(cc, cc);
return coord + cc * dist * amt; return coord - cc * dist * amt;
} }
float sat(float value) float sat(float value)
{ {
@ -43,17 +43,19 @@ void main() {
#ifdef _CPostprocess #ifdef _CPostprocess
float max_distort = PPComp13.x; float max_distort = PPComp13.x;
int num_iter = int(PPComp13.y); int num_iter = int(PPComp13.y);
int CAType = int(PPComp13.z);
int on = int(PPComp13.w);
#else #else
float max_distort = compoChromaticStrength; float max_distort = compoChromaticStrength;
int num_iter = compoChromaticSamples; int num_iter = compoChromaticSamples;
int CAType = compoChromaticType;
int on = 1;
#endif #endif
// Spectral // Spectral
if (compoChromaticType == 1) { if (CAType == 1) {
float reci_num_iter_f = 1.0 / float(num_iter); float reci_num_iter_f = 1.0 / float(num_iter);
vec2 resolution = vec2(1,1);
vec2 uv = (texCoord.xy/resolution.xy);
vec4 sumcol = vec4(0.0); vec4 sumcol = vec4(0.0);
vec4 sumw = vec4(0.0); vec4 sumw = vec4(0.0);
for (int i=0; i < num_iter; ++i) for (int i=0; i < num_iter; ++i)
@ -61,18 +63,21 @@ void main() {
float t = float(i) * reci_num_iter_f; float t = float(i) * reci_num_iter_f;
vec4 w = spectrum_offset(t); vec4 w = spectrum_offset(t);
sumw += w; sumw += w;
sumcol += w * texture(tex, barrelDistortion(uv, 0.6 * max_distort * t)); vec2 distortedUV = barrelDistortion(texCoord, 0.6 * max_distort * t);
sumcol += w * texture(tex, distortedUV);
} }
fragColor = sumcol / sumw; if (on == 1) fragColor = sumcol / sumw; else fragColor = texture(tex, texCoord);
} }
// Simple // inward sampling to avoid edge artifacts
else { else {
vec3 col = vec3(0.0); vec3 col = vec3(0.0);
col.x = texture(tex, texCoord + ((vec2(0.0, 1.0) * max_distort) / vec2(1000.0))).x; vec2 toCenter = (vec2(0.5) - texCoord) * max_distort / 500.0;
col.y = texture(tex, texCoord + ((vec2(-0.85, -0.5) * max_distort) / vec2(1000.0))).y; col.x = texture(tex, texCoord + toCenter * 0.0).x;
col.z = texture(tex, texCoord + ((vec2(0.85, -0.5) * max_distort) / vec2(1000.0))).z; col.y = texture(tex, texCoord + toCenter * 0.5).y;
fragColor = vec4(col.x, col.y, col.z, fragColor.w); col.z = texture(tex, texCoord + toCenter * 1.0).z;
if (on == 1) fragColor = vec4(col.x, col.y, col.z, 1.0);
else fragColor = texture(tex, texCoord);
} }
} }

View File

@ -62,8 +62,11 @@ uniform vec3 PPComp5;
uniform vec3 PPComp6; uniform vec3 PPComp6;
uniform vec3 PPComp7; uniform vec3 PPComp7;
uniform vec3 PPComp8; uniform vec3 PPComp8;
uniform vec3 PPComp11;
uniform vec3 PPComp14; uniform vec3 PPComp14;
uniform vec4 PPComp15; uniform vec4 PPComp15;
uniform vec4 PPComp16;
uniform vec4 PPComp18;
#endif #endif
// #ifdef _CPos // #ifdef _CPos
@ -106,6 +109,16 @@ in vec2 texCoord;
out vec4 fragColor; out vec4 fragColor;
#ifdef _CFog #ifdef _CFog
#ifdef _CPostprocess
vec3 FogColor = vec3(PPComp18.x, PPComp18.y, PPComp18.z);
float FogAmountA = PPComp18.w;
float FogAmountB = PPComp11.z;
#else
vec3 FogColor = compoFogColor;
float FogAmountA = compoFogAmountA;
float FogAmountB = compoFogAmountB;
#endif
// const vec3 compoFogColor = vec3(0.5, 0.6, 0.7); // const vec3 compoFogColor = vec3(0.5, 0.6, 0.7);
// const float compoFogAmountA = 1.0; // b = 0.01 // const float compoFogAmountA = 1.0; // b = 0.01
// const float compoFogAmountB = 1.0; // c = 0.1 // const float compoFogAmountB = 1.0; // c = 0.1
@ -118,8 +131,8 @@ out vec4 fragColor;
// } // }
vec3 applyFog(vec3 rgb, float distance) { vec3 applyFog(vec3 rgb, float distance) {
// float fogAmount = 1.0 - exp(-distance * compoFogAmountA); // float fogAmount = 1.0 - exp(-distance * compoFogAmountA);
float fogAmount = 1.0 - exp(-distance * (compoFogAmountA / 100)); float fogAmount = 1.0 - exp(-distance * (FogAmountA / 100));
return mix(rgb, compoFogColor, fogAmount); return mix(rgb, FogColor, fogAmount);
} }
#endif #endif
@ -131,7 +144,7 @@ float ConvertEV100ToExposure(float EV100) {
return 1/0.8 * exp2(-EV100); return 1/0.8 * exp2(-EV100);
} }
float ComputeEV(float avgLuminance) { float ComputeEV(float avgLuminance) {
const float sqAperture = PPComp1[0].x * PPComp1.x; const float sqAperture = PPComp1.x * PPComp1.x;
const float shutterTime = 1.0 / PPComp1.y; const float shutterTime = 1.0 / PPComp1.y;
const float ISO = PPComp1.z; const float ISO = PPComp1.z;
const float EC = PPComp2.x; const float EC = PPComp2.x;
@ -344,21 +357,33 @@ void main() {
#else #else
fragColor = textureLod(tex, texCo, 0.0); fragColor = textureLod(tex, texCo, 0.0);
#endif #endif
// TODO: re-investigate white artifacts
fragColor.rgb = clamp(fragColor.rgb, vec3(0.0), vec3(65504.0));
if (any(isnan(fragColor.rgb)) || any(isinf(fragColor.rgb))) {
fragColor.rgb = vec3(0.0);
}
#endif #endif
#ifdef _CSharpen #ifdef _CSharpen
#ifdef _CPostprocess #ifdef _CPostprocess
float strengthSharpen = PPComp14.y; float strengthSharpen = PPComp14.y;
vec3 SharpenColor = vec3(PPComp16.x, PPComp16.y, PPComp16.z);
float SharpenSize = PPComp16.w;
#else #else
float strengthSharpen = compoSharpenStrength; float strengthSharpen = compoSharpenStrength;
vec3 SharpenColor = compoSharpenColor;
float SharpenSize = compoSharpenSize;
#endif #endif
vec3 col1 = textureLod(tex, texCo + vec2(-texStep.x, -texStep.y) * 1.5, 0.0).rgb; vec3 col1 = textureLod(tex, texCo + vec2(-texStep.x, -texStep.y) * SharpenSize, 0.0).rgb;
vec3 col2 = textureLod(tex, texCo + vec2(texStep.x, -texStep.y) * 1.5, 0.0).rgb; vec3 col2 = textureLod(tex, texCo + vec2(texStep.x, -texStep.y) * SharpenSize, 0.0).rgb;
vec3 col3 = textureLod(tex, texCo + vec2(-texStep.x, texStep.y) * 1.5, 0.0).rgb; vec3 col3 = textureLod(tex, texCo + vec2(-texStep.x, texStep.y) * SharpenSize, 0.0).rgb;
vec3 col4 = textureLod(tex, texCo + vec2(texStep.x, texStep.y) * 1.5, 0.0).rgb; vec3 col4 = textureLod(tex, texCo + vec2(texStep.x, texStep.y) * SharpenSize, 0.0).rgb;
vec3 colavg = (col1 + col2 + col3 + col4) * 0.25; vec3 colavg = (col1 + col2 + col3 + col4) * 0.25;
fragColor.rgb += (fragColor.rgb - colavg) * strengthSharpen;
float edgeMagnitude = length(fragColor.rgb - colavg);
fragColor.rgb = mix(fragColor.rgb, SharpenColor, min(edgeMagnitude * strengthSharpen * 2.0, 1.0));
#endif #endif
#ifdef _CFog #ifdef _CFog
@ -407,7 +432,11 @@ void main() {
#endif #endif
#ifdef _CExposure #ifdef _CExposure
fragColor.rgb += fragColor.rgb * compoExposureStrength; #ifdef _CPostprocess
fragColor.rgb+=fragColor.rgb*PPComp8.x;
#else
fragColor.rgb+= fragColor.rgb*compoExposureStrength;
#endif
#endif #endif
#ifdef _CPostprocess #ifdef _CPostprocess
@ -415,8 +444,13 @@ void main() {
#endif #endif
#ifdef _AutoExposure #ifdef _AutoExposure
#ifdef _CPostprocess
float AEStrength = PPComp8.y;
#else
float AEStrength = autoExposureStrength;
#endif
float expo = 2.0 - clamp(length(textureLod(histogram, vec2(0.5, 0.5), 0).rgb), 0.0, 1.0); float expo = 2.0 - clamp(length(textureLod(histogram, vec2(0.5, 0.5), 0).rgb), 0.0, 1.0);
fragColor.rgb *= pow(expo, autoExposureStrength * 2.0); fragColor.rgb *= pow(expo, AEStrength * 2.0);
#endif #endif
// Clamp color to get rid of INF values that don't work for the tone mapping below // Clamp color to get rid of INF values that don't work for the tone mapping below
@ -480,9 +514,7 @@ fragColor.rgb = min(fragColor.rgb, 65504 * 0.5);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
} else if (PPComp4.x == 10){ } else if (PPComp4.x == 10){
fragColor.rgb = tonemapAgXFull(fragColor.rgb); fragColor.rgb = tonemapAgXFull(fragColor.rgb);
} else { } //else { fragColor.rgb = vec3(0,1,0); //ERROR}
fragColor.rgb = vec3(0,1,0); //ERROR
}
#endif #endif
#else #else

View File

@ -235,6 +235,16 @@
"name": "PPComp15", "name": "PPComp15",
"link": "_PPComp15", "link": "_PPComp15",
"ifdef": ["_CPostprocess"] "ifdef": ["_CPostprocess"]
},
{
"name": "PPComp16",
"link": "_PPComp16",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp18",
"link": "_PPComp18",
"ifdef": ["_CPostprocess"]
} }
], ],
"texture_params": [], "texture_params": [],

View File

@ -20,7 +20,7 @@ uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1; uniform sampler2D gbuffer1;
#ifdef _gbuffer2 #ifdef _gbuffer2
//!uniform sampler2D gbuffer2; uniform sampler2D gbuffer2;
#endif #endif
#ifdef _EmissionShaded #ifdef _EmissionShaded
uniform sampler2D gbufferEmission; uniform sampler2D gbufferEmission;
@ -29,10 +29,11 @@ uniform sampler2D gbuffer1;
#ifdef _VoxelGI #ifdef _VoxelGI
uniform sampler2D voxels_diffuse; uniform sampler2D voxels_diffuse;
uniform sampler2D voxels_specular; uniform sampler2D voxels_specular;
#endif #else
#ifdef _VoxelAOvar #ifdef _VoxelAOvar
uniform sampler2D voxels_ao; uniform sampler2D voxels_ao;
#endif #endif
#endif
#ifdef _VoxelShadow #ifdef _VoxelShadow
uniform sampler3D voxels; uniform sampler3D voxels;
uniform sampler3D voxelsSDF; uniform sampler3D voxelsSDF;
@ -58,6 +59,10 @@ uniform vec3 backgroundCol;
uniform sampler2D ssaotex; uniform sampler2D ssaotex;
#endif #endif
#ifdef _SSGI
uniform sampler2D ssgitex;
#endif
#ifdef _SSS #ifdef _SSS
uniform vec2 lightPlane; uniform vec2 lightPlane;
#endif #endif
@ -97,8 +102,23 @@ uniform mat4 invVP;
#endif #endif
uniform vec2 cameraProj; uniform vec2 cameraProj;
#ifdef _VRStereo
uniform vec3 eye; // center camera position
uniform vec3 eyeLook; // center camera look
uniform vec3 eyeLeft;
uniform vec3 eyeRight;
uniform vec3 eyeLookLeft;
uniform vec3 eyeLookRight;
uniform mat4 invVPLeft;
uniform mat4 invVPRight;
#ifdef _SinglePoint
uniform vec3 pointPosLeft;
uniform vec3 pointPosRight;
#endif
#else
uniform vec3 eye; uniform vec3 eye;
uniform vec3 eyeLook; uniform vec3 eyeLook;
#endif
#ifdef _Clusters #ifdef _Clusters
uniform vec4 lightsArray[maxLights * 3]; uniform vec4 lightsArray[maxLights * 3];
@ -113,11 +133,15 @@ uniform vec2 cameraPlane;
#ifdef _SinglePoint #ifdef _SinglePoint
#ifdef _Spot #ifdef _Spot
//!uniform sampler2DShadow shadowMapSpot[1]; //!uniform sampler2DShadow shadowMapSpot[1];
#ifdef _ShadowMapTransparent
//!uniform sampler2D shadowMapSpotTransparent[1]; //!uniform sampler2D shadowMapSpotTransparent[1];
#endif
//!uniform mat4 LWVPSpot[1]; //!uniform mat4 LWVPSpot[1];
#else #else
//!uniform samplerCubeShadow shadowMapPoint[1]; //!uniform samplerCubeShadow shadowMapPoint[1];
#ifdef _ShadowMapTransparent
//!uniform samplerCube shadowMapPointTransparent[1]; //!uniform samplerCube shadowMapPointTransparent[1];
#endif
//!uniform vec2 lightProj; //!uniform vec2 lightProj;
#endif #endif
#endif #endif
@ -125,30 +149,40 @@ uniform vec2 cameraPlane;
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
#ifdef _SingleAtlas #ifdef _SingleAtlas
uniform sampler2DShadow shadowMapAtlas; uniform sampler2DShadow shadowMapAtlas;
#ifdef _ShadowMapTransparent
uniform sampler2D shadowMapAtlasTransparent; uniform sampler2D shadowMapAtlasTransparent;
#endif #endif
#endif
#endif #endif
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
#ifndef _SingleAtlas #ifndef _SingleAtlas
//!uniform sampler2DShadow shadowMapAtlasPoint; //!uniform sampler2DShadow shadowMapAtlasPoint;
#ifdef _ShadowMapTransparent
//!uniform sampler2D shadowMapAtlasPointTransparent; //!uniform sampler2D shadowMapAtlasPointTransparent;
#endif #endif
//!uniform vec4 pointLightDataArray[4]; #endif
//!uniform vec4 pointLightDataArray[maxLightsCluster * 6];
#else #else
//!uniform samplerCubeShadow shadowMapPoint[4]; //!uniform samplerCubeShadow shadowMapPoint[4];
#ifdef _ShadowMapTransparent
//!uniform samplerCube shadowMapPointTransparent[4]; //!uniform samplerCube shadowMapPointTransparent[4];
#endif
#endif #endif
//!uniform vec2 lightProj; //!uniform vec2 lightProj;
#ifdef _Spot #ifdef _Spot
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
#ifndef _SingleAtlas #ifndef _SingleAtlas
//!uniform sampler2DShadow shadowMapAtlasSpot; //!uniform sampler2DShadow shadowMapAtlasSpot;
#ifdef _ShadowMapTransparent
//!uniform sampler2D shadowMapAtlasSpotTransparent; //!uniform sampler2D shadowMapAtlasSpotTransparent;
#endif #endif
#endif
#else #else
//!uniform sampler2DShadow shadowMapSpot[4]; //!uniform sampler2DShadow shadowMapSpot[4];
#ifdef _ShadowMapTransparent
//!uniform sampler2D shadowMapSpotTransparent[4]; //!uniform sampler2D shadowMapSpotTransparent[4];
#endif #endif
#endif
//!uniform mat4 LWVPSpotArray[maxLightsCluster]; //!uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif #endif
#endif #endif
@ -161,12 +195,16 @@ uniform vec3 sunCol;
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
#ifndef _SingleAtlas #ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasSun; uniform sampler2DShadow shadowMapAtlasSun;
#ifdef _ShadowMapTransparent
uniform sampler2D shadowMapAtlasSunTransparent; uniform sampler2D shadowMapAtlasSunTransparent;
#endif #endif
#endif
#else #else
uniform sampler2DShadow shadowMap; uniform sampler2DShadow shadowMap;
#ifdef _ShadowMapTransparent
uniform sampler2D shadowMapTransparent; uniform sampler2D shadowMapTransparent;
#endif #endif
#endif
uniform float shadowsBias; uniform float shadowsBias;
#ifdef _CSM #ifdef _CSM
//!uniform vec4 casData[shadowmapCascades * 4 + 4]; //!uniform vec4 casData[shadowmapCascades * 4 + 4];
@ -177,7 +215,9 @@ uniform vec3 sunCol;
#endif #endif
#ifdef _SinglePoint // Fast path for single light #ifdef _SinglePoint // Fast path for single light
#ifndef _VRStereo
uniform vec3 pointPos; uniform vec3 pointPos;
#endif
uniform vec3 pointCol; uniform vec3 pointCol;
#ifdef _ShadowMap #ifdef _ShadowMap
uniform float pointBias; uniform float pointBias;
@ -202,6 +242,8 @@ out vec4 fragColor;
void main() { void main() {
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, roughness, metallic/matid vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, roughness, metallic/matid
vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
vec3 n; vec3 n;
n.z = 1.0 - abs(g0.x) - abs(g0.y); n.z = 1.0 - abs(g0.x) - abs(g0.y);
@ -213,31 +255,50 @@ void main() {
uint matid; uint matid;
unpackFloatInt16(g0.a, metallic, matid); unpackFloatInt16(g0.a, metallic, matid);
vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ
vec2 occspec = unpackFloat2(g1.a); vec2 occspec = unpackFloat2(g1.a);
vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor // re-investigate clamp basecolor to prevent extreme values causing glitches
vec3 f0 = surfaceF0(g1.rgb, metallic); vec3 basecolor = min(g1.rgb, vec3(2.0));
vec3 albedo = surfaceAlbedo(basecolor, metallic);
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; vec3 f0 = surfaceF0(basecolor, metallic);
#ifdef _VRStereo
bool isLeftEye = texCoord.x < 0.5;
vec3 eyePos = isLeftEye ? eyeLeft : eyeRight;
mat4 invVP_eye = isLeftEye ? invVPLeft : invVPRight;
vec2 eyeTexCoord = vec2(
isLeftEye ? texCoord.x * 2.0 : (texCoord.x - 0.5) * 2.0,
texCoord.y
);
vec3 p = getPos2(invVP_eye, depth, eyeTexCoord);
vec3 v = normalize(eyePos - p);
#else
vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj); vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
vec3 v = normalize(eye - p); vec3 v = normalize(eye - p);
#endif
float dotNV = max(dot(n, v), 0.0); float dotNV = max(dot(n, v), 0.0);
#ifdef _gbuffer2 #ifdef _gbuffer2
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0); vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
#endif #endif
#ifdef _MicroShadowing #ifdef _MicroShadowing
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
#endif #endif
#ifdef _Brdf #ifdef _Brdf
vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy; vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
vec3 F = f0 * envBRDF.x + envBRDF.y;
#else
vec3 F = f0;
#endif #endif
#ifndef _VoxelAOvar
#ifndef _VoxelGI
// Envmap // Envmap
#ifdef _Irr #ifdef _Irr
vec3 envl = shIrradiance(n, shirr); vec3 envl = shIrradiance(n, shirr);
#ifdef _gbuffer2 #ifdef _gbuffer2
@ -259,6 +320,7 @@ void main() {
vec3 reflectionWorld = reflect(-v, n); vec3 reflectionWorld = reflect(-v, n);
float lod = getMipFromRoughness(roughness, envmapNumMipmaps); float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb; vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
prefilteredColor = min(prefilteredColor, vec3(20.0));
#endif #endif
#ifdef _EnvLDR #ifdef _EnvLDR
@ -271,33 +333,33 @@ void main() {
envl.rgb *= albedo; envl.rgb *= albedo;
#ifdef _Brdf #ifdef _Brdf
envl.rgb *= 1.0 - (f0 * envBRDF.x + envBRDF.y); //LV: We should take refracted light into account envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
#endif #endif
#ifdef _Rad // Indirect specular #ifdef _Rad // Indirect specular
envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y); //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
#else #else
#ifdef _EnvCol #ifdef _EnvCol
envl.rgb += backgroundCol * (f0 * envBRDF.x + envBRDF.y); //LV: Eh, what's the point of weighting it only by F0? envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
#endif #endif
#endif #endif
envl.rgb *= envmapStrength * occspec.x; envl.rgb *= envmapStrength * occspec.x;
#ifdef _VoxelGI
vec4 indirect_diffuse = textureLod(voxels_diffuse, texCoord, 0.0);
fragColor.rgb = (indirect_diffuse.rgb + envl.rgb * (1.0 - indirect_diffuse.a)) * albedo * voxelgiDiff;
if(roughness < 1.0 && occspec.y > 0.0)
fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * occspec.y * voxelgiRefl;
#endif
#ifdef _VoxelAOvar
envl.rgb *= textureLod(voxels_ao, texCoord, 0.0).r;
#endif
#ifndef _VoxelGI
fragColor.rgb = envl; fragColor.rgb = envl;
#endif #endif
#endif
#ifdef _VoxelGI
fragColor.rgb = textureLod(voxels_diffuse, texCoord, 0.0).rgb * voxelgiDiff;
if(roughness < 1.0 && occspec.y > 0.0)
fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * occspec.y * voxelgiRefl;
#else
#ifdef _VoxelAOvar
fragColor.rgb = textureLod(voxels_ao, texCoord, 0.0).rgb * voxelgiOcc;
#endif
#endif
// Show voxels // Show voxels
// vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99); // vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99);
// vec3 direction = vec3(0.0, 0.0, -1.0); // vec3 direction = vec3(0.0, 0.0, -1.0);
@ -312,11 +374,12 @@ void main() {
// fragColor.rgb = texture(ssaotex, texCoord).rrr; // fragColor.rgb = texture(ssaotex, texCoord).rrr;
#ifdef _SSAO #ifdef _SSAO
// #ifdef _RTGI
// fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).rgb;
// #else
fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r; fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r;
// #endif #endif
#ifdef _SSGI
vec3 ssgiColor = textureLod(ssgitex, texCoord, 0.0).rgb;
fragColor.rgb += ssgiColor * albedo;
#endif #endif
#ifdef _EmissionShadeless #ifdef _EmissionShadeless
@ -350,39 +413,69 @@ void main() {
#ifdef _CSM #ifdef _CSM
svisibility = shadowTestCascade( svisibility = shadowTestCascade(
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas #ifndef _SingleAtlas
shadowMapAtlasSun, shadowMapAtlasSunTransparent shadowMapAtlasSun, shadowMapAtlasSunTransparent
#else #else
shadowMapAtlas, shadowMapAtlasTransparent shadowMapAtlas, shadowMapAtlasTransparent
#endif #endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSun
#else
shadowMapAtlas
#endif
#endif
#else #else
shadowMap, shadowMapTransparent #ifdef _ShadowMapTransparent
shadowMap, shadowMapTransparent
#else
shadowMap
#endif
#endif #endif
, eye, p + n * shadowsBias * 10, shadowsBias, false , eye, p + n * shadowsBias * 2, shadowsBias
); #ifdef _ShadowMapTransparent
, false
#endif
);
#else #else
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0); vec4 lPos = LWVP * vec4(p + n * shadowsBias * 2, 1.0);
if (lPos.w > 0.0) { if (lPos.w > 0.0) {
svisibility = shadowTest( svisibility = shadowTest(
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas #ifndef _SingleAtlas
shadowMapAtlasSun, shadowMapAtlasSunTransparent shadowMapAtlasSun, shadowMapAtlasSunTransparent
#else #else
shadowMapAtlas, shadowMapAtlasTransparent shadowMapAtlas, shadowMapAtlasTransparent
#endif #endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSun
#else
shadowMapAtlas
#endif
#endif
#else #else
#ifdef _ShadowMapTransparent
shadowMap, shadowMapTransparent shadowMap, shadowMapTransparent
#else
shadowMap
#endif #endif
, lPos.xyz / lPos.w, shadowsBias, false #endif
); , lPos.xyz / lPos.w, shadowsBias
#ifdef _ShadowMapTransparent
, false
#endif
);
} }
#endif #endif
#endif #endif
#ifdef _VoxelShadow #ifdef _VoxelShadow
svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy, g2.rg).r) * voxelgiShad; svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy, -g2.rg).r) * voxelgiShad;
#endif #endif
#ifdef _SSRS #ifdef _SSRS
// vec2 coords = getProjectedCoord(hitCoord); // vec2 coords = getProjectedCoord(hitCoord);
// vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy); // vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
@ -436,16 +529,25 @@ void main() {
#ifdef _SinglePoint #ifdef _SinglePoint
#ifdef _VRStereo
vec3 lightPos = pointPosLeft;
#else
vec3 lightPos = pointPos;
#endif
fragColor.rgb += sampleLight( fragColor.rgb += sampleLight(
p, n, v, dotNV, pointPos, pointCol, albedo, roughness, occspec.y, f0 p, n, v, dotNV, lightPos, pointCol, albedo, roughness, occspec.y, f0
#ifdef _ShadowMap #ifdef _ShadowMap
, 0, pointBias, true, false , 0, pointBias, true
#ifdef _ShadowMapTransparent
, false
#endif
#endif #endif
#ifdef _Spot #ifdef _Spot
, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight , true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight
#endif #endif
#ifdef _VoxelShadow #ifdef _VoxelShadow
, voxels, voxelsSDF, clipmaps , voxels, voxelsSDF, clipmaps, -g2.rg
#endif #endif
#ifdef _MicroShadowing #ifdef _MicroShadowing
, occspec.x , occspec.x
@ -457,7 +559,9 @@ void main() {
#ifdef _Spot #ifdef _Spot
#ifdef _SSS #ifdef _SSS
if (matid == 2) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot[0], p, n, normalize(pointPos - p), lightPlane.y, shadowMapSpot[0]);//TODO implement transparent shadowmaps into the SSSSTransmittance() #ifdef _ShadowMap
if (matid == 2) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot[0], p, n, normalize(lightPos - p), lightPlane.y, shadowMapSpot[0]);//TODO implement transparent shadowmaps into the SSSSTransmittance()
#endif
#endif #endif
#endif #endif
@ -492,7 +596,10 @@ void main() {
f0 f0
#ifdef _ShadowMap #ifdef _ShadowMap
// light index, shadow bias, cast_shadows // light index, shadow bias, cast_shadows
, li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0, false , li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0
#ifdef _ShadowMapTransparent
, false
#endif
#endif #endif
#ifdef _Spot #ifdef _Spot
, lightsArray[li * 3 + 2].y != 0.0 , lightsArray[li * 3 + 2].y != 0.0
@ -503,7 +610,7 @@ void main() {
, lightsArraySpot[li * 2 + 1].xyz // right , lightsArraySpot[li * 2 + 1].xyz // right
#endif #endif
#ifdef _VoxelShadow #ifdef _VoxelShadow
, voxels, voxelsSDF, clipmaps , voxels, voxelsSDF, clipmaps, -g2.rg
#endif #endif
#ifdef _MicroShadowing #ifdef _MicroShadowing
, occspec.x , occspec.x
@ -514,14 +621,11 @@ void main() {
); );
} }
#endif // _Clusters #endif // _Clusters
/* fragColor.rgb = clamp(fragColor.rgb, vec3(0.0), vec3(65504.0));
#ifdef _VoxelRefract if (any(isnan(fragColor.rgb)) || any(isinf(fragColor.rgb))) {
if(opac < 1.0) { fragColor.rgb = vec3(0.0);
vec3 refraction = traceRefraction(p, n, voxels, v, ior, roughness, eye) * voxelgiRefr; }
fragColor.rgb = mix(refraction, fragColor.rgb, opac);
}
#endif
*/
fragColor.a = 1.0; // Mark as opaque fragColor.a = 1.0; // Mark as opaque
} }

View File

@ -20,6 +20,36 @@
"name": "eyeLook", "name": "eyeLook",
"link": "_cameraLook" "link": "_cameraLook"
}, },
{
"name": "eyeLeft",
"link": "_eyeLeft",
"ifdef": ["_VRStereo"]
},
{
"name": "eyeRight",
"link": "_eyeRight",
"ifdef": ["_VRStereo"]
},
{
"name": "eyeLookLeft",
"link": "_eyeLookLeft",
"ifdef": ["_VRStereo"]
},
{
"name": "eyeLookRight",
"link": "_eyeLookRight",
"ifdef": ["_VRStereo"]
},
{
"name": "invVPLeft",
"link": "_inverseViewProjectionMatrixLeft",
"ifdef": ["_VRStereo"]
},
{
"name": "invVPRight",
"link": "_inverseViewProjectionMatrixRight",
"ifdef": ["_VRStereo"]
},
{ {
"name": "clipmaps", "name": "clipmaps",
"link": "_clipmaps", "link": "_clipmaps",
@ -176,8 +206,19 @@
{ {
"name": "pointPos", "name": "pointPos",
"link": "_pointPosition", "link": "_pointPosition",
"ifndef": ["_VRStereo"],
"ifdef": ["_SinglePoint"] "ifdef": ["_SinglePoint"]
}, },
{
"name": "pointPosLeft",
"link": "_pointPositionLeft",
"ifdef": ["_VRStereo", "_SinglePoint"]
},
{
"name": "pointPosRight",
"link": "_pointPositionRight",
"ifdef": ["_VRStereo", "_SinglePoint"]
},
{ {
"name": "pointCol", "name": "pointCol",
"link": "_pointColor", "link": "_pointColor",

View File

@ -97,6 +97,31 @@
"link": "_cascadeData", "link": "_cascadeData",
"ifdef": ["_Sun", "_ShadowMap", "_CSM"] "ifdef": ["_Sun", "_ShadowMap", "_CSM"]
}, },
{
"name": "eyeLookRight",
"link": "_eyeLookRight",
"ifdef": ["_VRStereo"]
},
{
"name": "invVPLeft",
"link": "_inverseViewProjectionMatrixLeft",
"ifdef": ["_VRStereo"]
},
{
"name": "invVPRight",
"link": "_inverseViewProjectionMatrixRight",
"ifdef": ["_VRStereo"]
},
{
"name": "invVP",
"link": "_viewProjectionMatrix",
"ifdef": ["_SSRS"]
},
{
"name": "smSizeUniform",
"link": "_shadowMapSize",
"ifdef": ["_SMSizeUniform"]
},
{ {
"name": "lightPlane", "name": "lightPlane",
"link": "_lightPlane", "link": "_lightPlane",
@ -108,8 +133,6 @@
"ifdef": ["_SSRS"] "ifdef": ["_SSRS"]
}, },
{ {
"name": "smSizeUniform",
"link": "_shadowMapSize",
"ifdef": ["_SMSizeUniform"] "ifdef": ["_SMSizeUniform"]
}, },
{ {
@ -120,8 +143,19 @@
{ {
"name": "pointPos", "name": "pointPos",
"link": "_pointPosition", "link": "_pointPosition",
"ifndef": ["_VRStereo"],
"ifdef": ["_SinglePoint"] "ifdef": ["_SinglePoint"]
}, },
{
"name": "pointPosLeft",
"link": "_pointPositionLeft",
"ifdef": ["_VRStereo", "_SinglePoint"]
},
{
"name": "pointPosRight",
"link": "_pointPositionRight",
"ifdef": ["_VRStereo", "_SinglePoint"]
},
{ {
"name": "pointCol", "name": "pointCol",
"link": "_pointColor", "link": "_pointColor",

View File

@ -0,0 +1,9 @@
https://gpuopen.com/manuals/fidelityfx_sdk/license/
Copyright © 2024 Advanced Micro Devices, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and /or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,157 @@
#version 450
// AMD FidelityFX Super Resolution 1.0.2 - EASU (Edge Adaptive Spatial Upsampling)
#include "compiled.inc"
uniform sampler2D tex;
uniform vec2 screenSize;
in vec2 texCoord;
out vec4 fragColor;
// Helper functions from AMD ffx_a.h
float APrxLoRcpF1(float a) {
return uintBitsToFloat(uint(0x7ef07ebb) - floatBitsToUint(a));
}
float AMax3F1(float x, float y, float z) {
return max(x, max(y, z));
}
float AMin3F1(float x, float y, float z) {
return min(x, min(y, z));
}
// Attempt to use textureGather for efficiency when available
#if __VERSION__ >= 400
void FsrEasuTap(
inout vec3 aC,
inout float aW,
vec2 off,
vec2 dir,
vec2 len,
float lob,
float clp,
vec3 c
) {
vec2 v = off * dir;
float d2 = v.x + v.y;
d2 = clamp(d2 * APrxLoRcpF1(max(abs(v.x), abs(v.y))), 0.0, 1.0);
d2 = d2 * d2;
d2 = d2 * len.x + len.y;
float wB = 2.0 / 5.0 * d2 - 1.0;
float wA = lob * d2 - 1.0;
wB *= wB;
wA *= wA;
float w = 25.0 / 16.0 * wA * wB;
w = min(w, clp);
w = max(w, 0.0);
aC += c * w;
aW += w;
}
vec3 FsrEasuF(vec2 ip) {
vec2 inputSize = textureSize(tex, 0);
vec2 inputRcp = 1.0 / inputSize;
// Position in input pixels
vec2 pp = ip * inputSize - 0.5;
vec2 fp = floor(pp);
pp -= fp;
// 12-tap kernel
// b c
// e f g h
// i j k l
// n o
ivec2 sp = ivec2(fp);
vec3 b = texelFetch(tex, sp + ivec2(0, -1), 0).rgb;
vec3 c = texelFetch(tex, sp + ivec2(1, -1), 0).rgb;
vec3 e = texelFetch(tex, sp + ivec2(-1, 0), 0).rgb;
vec3 f = texelFetch(tex, sp + ivec2(0, 0), 0).rgb;
vec3 g = texelFetch(tex, sp + ivec2(1, 0), 0).rgb;
vec3 h = texelFetch(tex, sp + ivec2(2, 0), 0).rgb;
vec3 i = texelFetch(tex, sp + ivec2(-1, 1), 0).rgb;
vec3 j = texelFetch(tex, sp + ivec2(0, 1), 0).rgb;
vec3 k = texelFetch(tex, sp + ivec2(1, 1), 0).rgb;
vec3 l = texelFetch(tex, sp + ivec2(2, 1), 0).rgb;
vec3 n = texelFetch(tex, sp + ivec2(0, 2), 0).rgb;
vec3 o = texelFetch(tex, sp + ivec2(1, 2), 0).rgb;
// Luma for edge detection (using green channel approximation)
float bL = b.g + 0.5 * (b.r + b.b);
float cL = c.g + 0.5 * (c.r + c.b);
float eL = e.g + 0.5 * (e.r + e.b);
float fL = f.g + 0.5 * (f.r + f.b);
float gL = g.g + 0.5 * (g.r + g.b);
float hL = h.g + 0.5 * (h.r + h.b);
float iL = i.g + 0.5 * (i.r + i.b);
float jL = j.g + 0.5 * (j.r + j.b);
float kL = k.g + 0.5 * (k.r + k.b);
float lL = l.g + 0.5 * (l.r + l.b);
float nL = n.g + 0.5 * (n.r + n.b);
float oL = o.g + 0.5 * (o.r + o.b);
// Gradient detection
float dirX = (cL - bL) + (gL - fL) + (kL - jL) + (oL - nL);
float dirY = (eL - iL) + (fL - jL) + (gL - kL) + (hL - lL);
// Normalize direction
float dirR = APrxLoRcpF1(max(abs(dirX), abs(dirY)));
dirX *= dirR;
dirY *= dirR;
// Calculate stretch based on edge direction
float len = length(vec2(dirX, dirY));
len = len * 0.5;
len *= len;
float stretch = (dirX * dirX + dirY * dirY) * APrxLoRcpF1(max(abs(dirX), abs(dirY)));
vec2 len2 = vec2(1.0 + (stretch - 1.0) * len, 1.0 - 0.5 * len);
float lob = 0.5 + (0.25 - 0.04 - 0.5) * len;
float clp = APrxLoRcpF1(lob);
// Accumulate samples
vec3 aC = vec3(0.0);
float aW = 0.0;
vec2 dir = vec2(dirX, dirY);
FsrEasuTap(aC, aW, vec2(0.0, -1.0) - pp, dir, len2, lob, clp, b);
FsrEasuTap(aC, aW, vec2(1.0, -1.0) - pp, dir, len2, lob, clp, c);
FsrEasuTap(aC, aW, vec2(-1.0, 0.0) - pp, dir, len2, lob, clp, e);
FsrEasuTap(aC, aW, vec2(0.0, 0.0) - pp, dir, len2, lob, clp, f);
FsrEasuTap(aC, aW, vec2(1.0, 0.0) - pp, dir, len2, lob, clp, g);
FsrEasuTap(aC, aW, vec2(2.0, 0.0) - pp, dir, len2, lob, clp, h);
FsrEasuTap(aC, aW, vec2(-1.0, 1.0) - pp, dir, len2, lob, clp, i);
FsrEasuTap(aC, aW, vec2(0.0, 1.0) - pp, dir, len2, lob, clp, j);
FsrEasuTap(aC, aW, vec2(1.0, 1.0) - pp, dir, len2, lob, clp, k);
FsrEasuTap(aC, aW, vec2(2.0, 1.0) - pp, dir, len2, lob, clp, l);
FsrEasuTap(aC, aW, vec2(0.0, 2.0) - pp, dir, len2, lob, clp, n);
FsrEasuTap(aC, aW, vec2(1.0, 2.0) - pp, dir, len2, lob, clp, o);
// Normalize
vec3 pix = aC / aW;
// Clamp to neighborhood min/max to prevent ringing
vec3 mn = min(min(min(f, g), j), k);
vec3 mx = max(max(max(f, g), j), k);
pix = clamp(pix, mn, mx);
return pix;
}
#else
// Fallback for older GLSL - simple bilinear
vec3 FsrEasuF(vec2 ip) {
return texture(tex, ip).rgb;
}
#endif
void main() {
vec3 col = FsrEasuF(texCoord);
fragColor = vec4(col, 1.0);
}

View File

@ -0,0 +1,19 @@
{
"contexts": [
{
"name": "fsr1_easu_pass",
"depth_write": false,
"compare_mode": "always",
"cull_mode": "none",
"links": [
{
"name": "screenSize",
"link": "_screenSize"
}
],
"texture_params": [],
"vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "fsr1_easu_pass.frag.glsl"
}
]
}

View File

@ -0,0 +1,9 @@
https://gpuopen.com/manuals/fidelityfx_sdk/license/
Copyright © 2024 Advanced Micro Devices, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and /or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,116 @@
#version 450
// AMD FidelityFX Super Resolution 1.0.2 - RCAS (Robust Contrast Adaptive Sharpening)
#include "compiled.inc"
uniform sampler2D tex;
// Sharpness in "stops": 0.0 = maximum sharpness, higher = less sharp
// Converted to linear via exp2(-sharpness)
#ifdef _FSR1_Ultra_Quality
const float SHARPNESS_STOPS = 0.0;
#elif defined(_FSR1_Balanced)
const float SHARPNESS_STOPS = 1.0;
#elif defined(_FSR1_Performance)
const float SHARPNESS_STOPS = 2.0;
#elif defined(_FSR1_Custom)
uniform vec4 PPComp15;
#define SHARPNESS_STOPS (PPComp15.x * 2.0)
#else
const float SHARPNESS_STOPS = 0.5; // Quality (default)
#endif
// FSR RCAS limit - prevents unnatural sharpening artifacts
#define FSR_RCAS_LIMIT (0.25 - (1.0 / 16.0))
in vec2 texCoord;
out vec4 fragColor;
// AMD helper functions from ffx_a.h
float AMin3F1(float x, float y, float z) { return min(x, min(y, z)); }
float AMax3F1(float x, float y, float z) { return max(x, max(y, z)); }
// High precision reciprocal (required for limiters per AMD docs)
// Added epsilon to prevent division by zero in dark areas
float ARcpF1(float a) {
return 1.0 / max(a, 1e-8);
}
// Medium precision reciprocal approximation (from AMD ffx_a.h)
// Only used for noise detection and final resolve
float APrxMedRcpF1(float a) {
return uintBitsToFloat(uint(0x7ef19fff) - floatBitsToUint(a));
}
void main() {
// Get texture size and texel offset
vec2 texSize = vec2(textureSize(tex, 0));
vec2 texelSize = 1.0 / texSize;
// Algorithm uses minimal 3x3 pixel neighborhood
// b
// d e f
// h
// Clamp inputs to [0,1] - FSR expects sRGB normalized input
vec3 b = clamp(texture(tex, texCoord + vec2(0.0, -texelSize.y)).rgb, 0.0, 1.0);
vec3 d = clamp(texture(tex, texCoord + vec2(-texelSize.x, 0.0)).rgb, 0.0, 1.0);
vec4 ee = texture(tex, texCoord);
vec3 e = clamp(ee.rgb, 0.0, 1.0);
vec3 f = clamp(texture(tex, texCoord + vec2(texelSize.x, 0.0)).rgb, 0.0, 1.0);
vec3 h = clamp(texture(tex, texCoord + vec2(0.0, texelSize.y)).rgb, 0.0, 1.0);
// Luma times 2 (AMD's luma calculation: B*0.5 + R*0.5 + G)
float bL = b.b * 0.5 + (b.r * 0.5 + b.g);
float dL = d.b * 0.5 + (d.r * 0.5 + d.g);
float eL = e.b * 0.5 + (e.r * 0.5 + e.g);
float fL = f.b * 0.5 + (f.r * 0.5 + f.g);
float hL = h.b * 0.5 + (h.r * 0.5 + h.g);
// Noise detection (official AMD algorithm with safety for flat areas)
float nz = 0.25 * bL + 0.25 * dL + 0.25 * fL + 0.25 * hL - eL;
float range = AMax3F1(AMax3F1(bL, dL, eL), fL, hL) - AMin3F1(AMin3F1(bL, dL, eL), fL, hL);
// Use safe division instead of APrxMedRcpF1 for range to avoid NaN in flat areas
nz = clamp(abs(nz) / max(range, 1e-5), 0.0, 1.0);
nz = -0.5 * nz + 1.0;
// Min and max of ring (per channel)
float mn4R = min(AMin3F1(b.r, d.r, f.r), h.r);
float mn4G = min(AMin3F1(b.g, d.g, f.g), h.g);
float mn4B = min(AMin3F1(b.b, d.b, f.b), h.b);
float mx4R = max(AMax3F1(b.r, d.r, f.r), h.r);
float mx4G = max(AMax3F1(b.g, d.g, f.g), h.g);
float mx4B = max(AMax3F1(b.b, d.b, f.b), h.b);
// Immediate constants for peak range
vec2 peakC = vec2(1.0, -4.0);
// Limiters - these need HIGH PRECISION reciprocals (per AMD docs)
float hitMinR = min(mn4R, e.r) * ARcpF1(4.0 * mx4R);
float hitMinG = min(mn4G, e.g) * ARcpF1(4.0 * mx4G);
float hitMinB = min(mn4B, e.b) * ARcpF1(4.0 * mx4B);
float hitMaxR = (peakC.x - max(mx4R, e.r)) * ARcpF1(4.0 * mn4R + peakC.y);
float hitMaxG = (peakC.x - max(mx4G, e.g)) * ARcpF1(4.0 * mn4G + peakC.y);
float hitMaxB = (peakC.x - max(mx4B, e.b)) * ARcpF1(4.0 * mn4B + peakC.y);
float lobeR = max(-hitMinR, hitMaxR);
float lobeG = max(-hitMinG, hitMaxG);
float lobeB = max(-hitMinB, hitMaxB);
// Apply sharpness (convert from stops to linear)
float sharpness = exp2(-SHARPNESS_STOPS);
float lobe = max(-FSR_RCAS_LIMIT, min(AMax3F1(lobeR, lobeG, lobeB), 0.0)) * sharpness;
// Apply noise removal
lobe *= nz;
// Resolve using safe reciprocal to avoid any edge case issues
float denom = 4.0 * lobe + 1.0;
float rcpL = 1.0 / max(denom, 0.25); // denom should be in [0.25, 1.0] range
vec3 pix;
pix.r = (lobe * b.r + lobe * d.r + lobe * h.r + lobe * f.r + e.r) * rcpL;
pix.g = (lobe * b.g + lobe * d.g + lobe * h.g + lobe * f.g + e.g) * rcpL;
pix.b = (lobe * b.b + lobe * d.b + lobe * h.b + lobe * f.b + e.b) * rcpL;
// Ensure output is clamped to valid range
fragColor = vec4(clamp(pix, 0.0, 1.0), ee.a);
}

View File

@ -0,0 +1,24 @@
{
"contexts": [
{
"name": "fsr1_rcas_pass",
"depth_write": false,
"compare_mode": "always",
"cull_mode": "none",
"links": [
{
"name": "screenSize",
"link": "_screenSize"
},
{
"name": "PPComp15",
"link": "_PPComp15",
"ifdef": ["_FSR1_Custom"]
}
],
"texture_params": [],
"vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "fsr1_rcas_pass.frag.glsl"
}
]
}

View File

@ -2,13 +2,22 @@
#include "compiled.inc" #include "compiled.inc"
#ifdef _CPostprocess
uniform vec3 PPComp8;
#endif
uniform sampler2D tex; uniform sampler2D tex;
in vec2 texCoord; in vec2 texCoord;
out vec4 fragColor; out vec4 fragColor;
void main() { void main() {
fragColor.a = 0.01 * autoExposureSpeed; #ifdef _CPostprocess
fragColor.a = 0.01 * PPComp8.z;
#else
fragColor.a = 0.01 * autoExposureSpeed;
#endif
fragColor.rgb = textureLod(tex, vec2(0.5, 0.5), 0.0).rgb + fragColor.rgb = textureLod(tex, vec2(0.5, 0.5), 0.0).rgb +
textureLod(tex, vec2(0.2, 0.2), 0.0).rgb + textureLod(tex, vec2(0.2, 0.2), 0.0).rgb +
textureLod(tex, vec2(0.8, 0.2), 0.0).rgb + textureLod(tex, vec2(0.8, 0.2), 0.0).rgb +

View File

@ -8,7 +8,13 @@
"blend_source": "source_alpha", "blend_source": "source_alpha",
"blend_destination": "inverse_source_alpha", "blend_destination": "inverse_source_alpha",
"blend_operation": "add", "blend_operation": "add",
"links": [], "links": [
{
"name": "PPComp8",
"link": "_PPComp8",
"ifdef": ["_CPostprocess"]
}
],
"texture_params": [], "texture_params": [],
"vertex_shader": "../include/pass.vert.glsl", "vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "histogram_pass.frag.glsl" "fragment_shader": "histogram_pass.frag.glsl"

View File

@ -8,6 +8,7 @@ uniform sampler2D gbufferD;
uniform sampler2D gbuffer0; uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1; uniform sampler2D gbuffer1;
uniform mat4 invVP; uniform mat4 invVP;
uniform mat4 invW;
uniform vec3 probep; uniform vec3 probep;
uniform vec3 eye; uniform vec3 eye;
@ -25,19 +26,27 @@ void main() {
float roughness = g0.b; float roughness = g0.b;
if (roughness > 0.95) { if (roughness > 0.95) {
fragColor.rgb = vec3(0.0); fragColor = vec4(0.0);
return; return;
} }
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a); float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
if (spec == 0.0) { if (spec == 0.0) {
fragColor.rgb = vec3(0.0); fragColor = vec4(0.0);
return; return;
} }
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
vec3 wp = getPos2(invVP, depth, texCoord); vec3 wp = getPos2(invVP, depth, texCoord);
vec3 localPos = (invW * vec4(wp, 1.0)).xyz;
// return if surface is inside probe volume bounds
if (abs(localPos.x) > 1.0 || abs(localPos.y) > 1.0 || abs(localPos.z) > 1.0) {
fragColor = vec4(0.0);
return;
}
vec2 enc = g0.rg; vec2 enc = g0.rg;
vec3 n; vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y); n.z = 1.0 - abs(enc.x) - abs(enc.y);
@ -50,5 +59,5 @@ void main() {
r.y = -r.y; r.y = -r.y;
#endif #endif
float intensity = clamp((1.0 - roughness) * dot(wp - probep, n), 0.0, 1.0); float intensity = clamp((1.0 - roughness) * dot(wp - probep, n), 0.0, 1.0);
fragColor.rgb = texture(probeTex, r).rgb * intensity; fragColor = vec4(texture(probeTex, r).rgb * intensity, 1.0);
} }

View File

@ -20,6 +20,10 @@
"name": "invVP", "name": "invVP",
"link": "_inverseViewProjectionMatrix" "link": "_inverseViewProjectionMatrix"
}, },
{
"name": "invW",
"link": "_inverseWorldMatrix"
},
{ {
"name": "probep", "name": "probep",
"link": "_probePosition" "link": "_probePosition"

View File

@ -25,13 +25,13 @@ void main() {
float roughness = g0.b; float roughness = g0.b;
if (roughness > 0.95) { if (roughness > 0.95) {
fragColor.rgb = vec3(0.0); fragColor = vec4(0.0);
return; return;
} }
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a); float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
if (spec == 0.0) { if (spec == 0.0) {
fragColor.rgb = vec3(0.0); fragColor = vec4(0.0);
return; return;
} }
@ -50,5 +50,5 @@ void main() {
n = normalize(n); n = normalize(n);
float intensity = clamp((1.0 - roughness) * dot(n, proben), 0.0, 1.0); float intensity = clamp((1.0 - roughness) * dot(n, proben), 0.0, 1.0);
fragColor.rgb = texture(probeTex, tc).rgb * intensity; fragColor = vec4(texture(probeTex, tc).rgb * intensity, 1.0);
} }

View File

@ -5,42 +5,56 @@
uniform sampler2D tex; uniform sampler2D tex;
uniform sampler2D gbuffer0; uniform sampler2D gbuffer0;
uniform sampler2D gbufferD;
uniform vec2 dirInv; // texStep uniform vec2 dirInv; // texStep
in vec2 texCoord; in vec2 texCoord;
out float fragColor; out vec3 fragColor;
const float blurWeights[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216); const int KERNEL_SIZE = 13;
// const float blurWeights[10] = float[] (0.132572, 0.125472, 0.106373, 0.08078, 0.05495, 0.033482, 0.018275, 0.008934, 0.003912, 0.001535); const float blurWeights[13] = float[](0.1, 0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.025, 0.02, 0.015, 0.01, 0.005);
const float discardThreshold = 0.95;
float doBlur(const float blurWeight, const int pos, const vec3 nor, const vec2 texCoord) {
const float posadd = pos + 0.5;
vec3 nor2 = getNor(textureLod(gbuffer0, texCoord + pos * dirInv, 0.0).rg);
float influenceFactor = step(discardThreshold, dot(nor2, nor));
float col = textureLod(tex, texCoord + posadd * dirInv, 0.0).r;
fragColor += col * blurWeight * influenceFactor;
float weight = blurWeight * influenceFactor;
nor2 = getNor(textureLod(gbuffer0, texCoord - pos * dirInv, 0.0).rg);
influenceFactor = step(discardThreshold, dot(nor2, nor));
col = textureLod(tex, texCoord - posadd * dirInv, 0.0).r;
fragColor += col * blurWeight * influenceFactor;
weight += blurWeight * influenceFactor;
return weight;
}
void main() { void main() {
vec3 nor = getNor(textureLod(gbuffer0, texCoord, 0.0).rg); vec3 centerNor = getNor(textureLod(gbuffer0, texCoord, 0.0).rg);
float centerDepth = textureLod(gbufferD, texCoord, 0.0).r;
fragColor = textureLod(tex, texCoord, 0.0).r * blurWeights[0]; // skip sky pixels
float weight = blurWeights[0]; if (centerDepth == 1.0) {
for (int i = 1; i < 5; i++) { fragColor = vec3(0.0);
weight += doBlur(blurWeights[i], i, nor, texCoord); return;
}
fragColor = textureLod(tex, texCoord, 0.0).rgb * blurWeights[0];
float totalWeight = blurWeights[0];
for (int i = 1; i < KERNEL_SIZE; i++) {
vec2 offset = float(i) * dirInv;
vec2 uvPos = texCoord + offset;
vec3 norPos = getNor(textureLod(gbuffer0, uvPos, 0.0).rg);
float depthPos = textureLod(gbufferD, uvPos, 0.0).r;
float normalWeight = max(0.0, dot(norPos, centerNor));
normalWeight = pow(normalWeight, 8.0); // Softer normal falloff for better blending
float depthWeight = 1.0 - smoothstep(0.0, 0.02, abs(depthPos - centerDepth));
float w = blurWeights[i] * normalWeight * depthWeight;
fragColor += textureLod(tex, uvPos, 0.0).rgb * w;
totalWeight += w;
vec2 uvNeg = texCoord - offset;
vec3 norNeg = getNor(textureLod(gbuffer0, uvNeg, 0.0).rg);
float depthNeg = textureLod(gbufferD, uvNeg, 0.0).r;
normalWeight = max(0.0, dot(norNeg, centerNor));
normalWeight = pow(normalWeight, 8.0);
depthWeight = 1.0 - smoothstep(0.0, 0.02, abs(depthNeg - centerDepth));
w = blurWeights[i] * normalWeight * depthWeight;
fragColor += textureLod(tex, uvNeg, 0.0).rgb * w;
totalWeight += w;
} }
fragColor = fragColor / weight; fragColor /= totalWeight;
} }

View File

@ -4,37 +4,34 @@
#include "std/math.glsl" #include "std/math.glsl"
#include "std/gbuffer.glsl" #include "std/gbuffer.glsl"
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
uniform sampler2D gbufferD; uniform sampler2D gbufferD;
uniform sampler2D gbuffer0; // Normal #ifdef _EmissionShaded
// #ifdef _RTGI uniform sampler2D gbufferEmission;
// uniform sampler2D gbuffer1; // Basecol #endif
// #endif
uniform mat4 P; uniform mat4 P;
uniform mat3 V3; uniform mat4 invP;
uniform mat3 V3;
uniform vec2 cameraProj;
#ifdef _Sun
const float angleMix = 0.5f; uniform vec3 sunDir;
#ifdef _SSGICone9 uniform vec3 sunCol;
const float strength = 2.0 * (1.0 / ssgiStrength); #endif
#else
const float strength = 2.0 * (1.0 / ssgiStrength) * 1.8; #ifdef _CPostprocess
uniform vec3 PPComp12;
#endif #endif
in vec3 viewRay;
in vec2 texCoord; in vec2 texCoord;
out float fragColor; out vec4 fragColor;
vec3 hitCoord; const float GOLDEN_ANGLE = 2.39996323;
vec2 coord; const int RAY_STEPS = 12;
float depth;
// #ifdef _RTGI
// vec3 col = vec3(0.0);
// #endif
vec3 vpos;
vec2 getProjectedCoord(vec3 hitCoord) { vec2 getProjectedCoord(const vec3 viewPos) {
vec4 projectedCoord = P * vec4(hitCoord, 1.0); vec4 projectedCoord = P * vec4(viewPos, 1.0);
projectedCoord.xy /= projectedCoord.w; projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5; projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
#ifdef _InvY #ifdef _InvY
@ -43,65 +40,149 @@ vec2 getProjectedCoord(vec3 hitCoord) {
return projectedCoord.xy; return projectedCoord.xy;
} }
float getDeltaDepth(vec3 hitCoord) { vec3 cosineSampleHemisphere(vec3 n, vec2 rand) {
coord = getProjectedCoord(hitCoord); float phi = PI * 2.0 * rand.x;
depth = textureLod(gbufferD, coord, 0.0).r * 2.0 - 1.0; float cosTheta = sqrt(1.0 - rand.y);
vec3 p = getPosView(viewRay, depth, cameraProj); float sinTheta = sqrt(rand.y);
return p.z - hitCoord.z;
} vec3 h = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
void rayCast(vec3 dir) { vec3 tangent, bitangent;
hitCoord = vpos; vec3 absN = abs(n);
dir *= ssgiRayStep * 2;
float dist = 0.15; if (absN.x <= absN.y && absN.x <= absN.z) {
for (int i = 0; i < ssgiMaxSteps; i++) { tangent = normalize(cross(n, vec3(1.0, 0.0, 0.0)));
hitCoord += dir; } else if (absN.y <= absN.z) {
float delta = getDeltaDepth(hitCoord); tangent = normalize(cross(n, vec3(0.0, 1.0, 0.0)));
if (delta > 0.0 && delta < 0.2) { } else {
dist = distance(vpos, hitCoord); tangent = normalize(cross(n, vec3(0.0, 0.0, 1.0)));
break;
}
} }
fragColor += dist; bitangent = cross(n, tangent);
// #ifdef _RTGI
// col += textureLod(gbuffer1, coord, 0.0).rgb * ((ssgiRayStep * ssgiMaxSteps) - dist); return normalize(tangent * h.x + bitangent * h.y + n * h.z);
// #endif
} }
vec3 tangent(const vec3 n) { vec3 traceRay(vec3 origin, vec3 dir, float maxDist, float minDist) {
vec3 t1 = cross(n, vec3(0, 0, 1)); float stepSize = maxDist / float(RAY_STEPS);
vec3 t2 = cross(n, vec3(0, 1, 0)); vec3 pos = origin + dir * minDist;
if (length(t1) > length(t2)) return normalize(t1);
else return normalize(t2); float prevDepthDiff = 0.0;
float hadValidPrev = 0.0;
for (int i = 1; i <= RAY_STEPS; i++) {
pos += dir * stepSize;
vec2 uv = getProjectedCoord(pos);
vec2 sampleUV = clamp(uv, vec2(0.001), vec2(0.999));
float sampleDepth = textureLod(gbufferD, sampleUV, 0.0).r * 2.0 - 1.0;
if (sampleDepth == 1.0) {
hadValidPrev = 0.0;
continue;
}
vec3 sampleViewPos = getPosView2(invP, sampleDepth, sampleUV);
float depthDiff = pos.z - sampleViewPos.z;
float rayDist = length(pos - origin);
float thickness = 0.15 + rayDist * 0.25;
float crossed = hadValidPrev * step(0.0, prevDepthDiff) * step(depthDiff, 0.0);
float withinThickness = step(abs(depthDiff), thickness);
if (crossed > 0.5 || withinThickness > 0.5) {
float distWeight = 1.0 - (rayDist / maxDist);
distWeight = max(0.0, distWeight * distWeight);
return vec3(sampleUV, distWeight);
}
prevDepthDiff = depthDiff;
hadValidPrev = 1.0;
}
return vec3(-1.0);
} }
void main() { void main() {
fragColor = 0; float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); if (depth == 1.0) {
float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; fragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
vec2 enc = g0.rg; vec2 enc = g0.rg;
vec3 n; vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y); n.z = 1.0 - abs(enc.x) - abs(enc.y);
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy); n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
n = normalize(V3 * n); n = normalize(n);
vpos = getPosView(viewRay, d, cameraProj); vec3 viewNormal = V3 * n;
vec3 viewPos = getPosView2(invP, depth, texCoord);
rayCast(n); #ifdef _CPostprocess
vec3 o1 = normalize(tangent(n)); float radius = PPComp12.y;
vec3 o2 = (cross(o1, n)); float strength = PPComp12.x;
vec3 c1 = 0.5f * (o1 + o2); #else
vec3 c2 = 0.5f * (o1 - o2); float radius = ssgiRadius;
rayCast(mix(n, o1, angleMix)); float strength = ssgiStrength;
rayCast(mix(n, o2, angleMix));
rayCast(mix(n, -c1, angleMix));
rayCast(mix(n, -c2, angleMix));
#ifdef _SSGICone9
rayCast(mix(n, -o1, angleMix));
rayCast(mix(n, -o2, angleMix));
rayCast(mix(n, c1, angleMix));
rayCast(mix(n, c2, angleMix));
#endif #endif
float noise = fract(52.9829189 * fract(0.06711056 * texCoord.x * 1000.0 + 0.00583715 * texCoord.y * 1000.0));
vec3 gi = vec3(0.0);
int validSamples = 0;
// min distance to avoid self shadowing artiffacts
float minDist = radius * 0.05;
for (int i = 0; i < ssgiSamples; i++) {
float fi = float(i) + noise;
vec2 rand = vec2(
fract(fi * 0.7548776662 + noise),
fract(fi * 0.5698402909 + noise * 1.5)
);
vec3 rayDir = cosineSampleHemisphere(viewNormal, rand);
vec3 hitResult = traceRay(viewPos, rayDir, radius, minDist);
if (hitResult.x < 0.0) continue;
vec2 hitUV = hitResult.xy;
float distWeight = hitResult.z;
vec3 hitAlbedo = textureLod(gbuffer1, hitUV, 1.0).rgb;
#ifdef _Sun
vec4 hitG0 = textureLod(gbuffer0, hitUV, 0.0);
vec2 hitEnc = hitG0.rg;
vec3 hitN;
hitN.z = 1.0 - abs(hitEnc.x) - abs(hitEnc.y);
hitN.xy = hitN.z >= 0.0 ? hitEnc.xy : octahedronWrap(hitEnc.xy);
hitN = normalize(hitN);
float hitNdotL = max(0.0, dot(hitN, sunDir));
vec3 hitRadiance = hitAlbedo * sunCol * hitNdotL;
#else
vec3 hitRadiance = hitAlbedo * 0.5;
#endif
#ifdef _EmissionShaded
hitRadiance += textureLod(gbufferEmission, hitUV, 0.0).rgb;
#endif
gi += hitRadiance * distWeight;
validSamples++;
}
if (validSamples > 0) {
gi /= float(validSamples);
}
gi *= strength;
#ifdef _EmissionShaded
gi += textureLod(gbufferEmission, texCoord, 0.0).rgb * 0.3;
#endif
fragColor = vec4(min(gi, vec3(2.0)), 1.0);
} }

View File

@ -10,21 +10,32 @@
"name": "P", "name": "P",
"link": "_projectionMatrix" "link": "_projectionMatrix"
}, },
{
"name": "V3",
"link": "_viewMatrix3"
},
{ {
"name": "invP", "name": "invP",
"link": "_inverseProjectionMatrix" "link": "_inverseProjectionMatrix"
}, },
{ {
"name": "cameraProj", "name": "V3",
"link": "_cameraPlaneProj" "link": "_viewMatrix3"
},
{
"name": "sunDir",
"link": "_sunDirection",
"ifdef": ["_Sun"]
},
{
"name": "sunCol",
"link": "_sunColor",
"ifdef": ["_Sun"]
},
{
"name": "PPComp12",
"link": "_PPComp12",
"ifdef": ["_CPostprocess"]
} }
], ],
"texture_params": [], "texture_params": [],
"vertex_shader": "../include/pass_viewray2.vert.glsl", "vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "ssgi_pass.frag.glsl" "fragment_shader": "ssgi_pass.frag.glsl"
} }
] ]

View File

@ -92,7 +92,7 @@ void main() {
vec3 viewNormal = V3 * n; vec3 viewNormal = V3 * n;
vec3 viewPos = getPosView(viewRay, d, cameraProj); vec3 viewPos = getPosView(viewRay, d, cameraProj);
vec3 reflected = reflect(normalize(viewPos), viewNormal); vec3 reflected = reflect(viewPos, viewNormal);
hitCoord = viewPos; hitCoord = viewPos;
#ifdef _CPostprocess #ifdef _CPostprocess

View File

@ -57,30 +57,33 @@ vec4 binarySearch(vec3 dir) {
} }
vec4 rayCast(vec3 dir) { vec4 rayCast(vec3 dir) {
float ddepth; float ddepth;
dir *= ss_refractionRayStep; dir *= ss_refractionRayStep;
for (int i = 0; i < maxSteps; i++) { for (int i = 0; i < maxSteps; i++) {
hitCoord += dir; hitCoord += dir;
ddepth = getDeltaDepth(hitCoord); ddepth = getDeltaDepth(hitCoord);
if (ddepth > 0.0) if (ddepth > 0.0) return binarySearch(dir);
return binarySearch(dir); }
} return vec4(texCoord, 0.0, 0.0);
// No hit — fallback to projecting the ray to UV space
vec2 fallbackUV = getProjectedCoord(hitCoord);
return vec4(fallbackUV, 0.0, 0.5); // We set .w lower to indicate fallback
} }
void main() { void main() {
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
float roughness = g0.z;
vec4 gr = textureLod(gbuffer_refraction, texCoord, 0.0); vec4 gr = textureLod(gbuffer_refraction, texCoord, 0.0);
float ior = gr.x; float ior = gr.x;
float opac = gr.y; float transmittance = gr.y;
float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; float surfaceDepth = gr.z;
if (d == 0.0 || opac == 1.0 || ior == 1.0) { float d = surfaceDepth * 2.0 - 1.0;
fragColor.rgb = textureLod(tex1, texCoord, 0.0).rgb;
vec4 sceneSample = textureLod(tex, texCoord, 0.0);
if (surfaceDepth == 0.0 || transmittance == 0.0 || ior == 1.0) {
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
fragColor.rgb = sceneSample.rgb + background * (1.0 - sceneSample.a);
fragColor.a = 1.0;
return; return;
} }
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
float roughness = g0.z;
vec2 enc = g0.rg; vec2 enc = g0.rg;
vec3 n; vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y); n.z = 1.0 - abs(enc.x) - abs(enc.y);
@ -89,21 +92,32 @@ void main() {
vec3 viewNormal = V3 * n; vec3 viewNormal = V3 * n;
vec3 viewPos = getPosView(viewRay, d, cameraProj); vec3 viewPos = getPosView(viewRay, d, cameraProj);
vec3 refracted = refract(normalize(viewPos), viewNormal, 1.0 / ior); vec3 incident = normalize(viewPos);
vec3 refracted = refract(incident, viewNormal, 1.0 / ior);
if (length(refracted) < 0.001) {
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
fragColor.rgb = sceneSample.rgb + background * (1.0 - sceneSample.a);
fragColor.a = 1.0;
return;
}
hitCoord = viewPos; hitCoord = viewPos;
vec3 dir = refracted * (1.0 - rand(texCoord) * ss_refractionJitter * roughness) * 2.0; vec3 dir = refracted * (1.0 - rand(texCoord) * ss_refractionJitter * roughness) * 2.0;
vec4 coords = rayCast(dir); vec4 coords = rayCast(dir);
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0); vec2 screenEdge = smoothstep(0.0, 0.1, coords.xy) * smoothstep(0.0, 0.1, 1.0 - coords.xy);
float screenEdgeFactor = screenEdge.x * screenEdge.y;
float refractivity = 1.0 - roughness; float refractivity = 1.0 - roughness;
float intensity = pow(refractivity, ss_refractionFalloffExp) * screenEdgeFactor * \
clamp(-refracted.z, 0.0, 1.0) * clamp((length(viewPos - hitCoord)), 0.0, 1.0) * coords.w; float intensity = pow(refractivity, ss_refractionFalloffExp) * screenEdgeFactor * coords.w;
intensity = clamp(intensity, 0.0, 1.0); intensity = clamp(intensity, 0.0, 1.0);
vec3 refractionCol = textureLod(tex1, coords.xy, 0.0).rgb; vec3 refractedBackground = textureLod(tex1, coords.xy, 0.0).rgb;
refractionCol *= intensity; vec3 straightBackground = textureLod(tex1, texCoord, 0.0).rgb;
vec3 color = textureLod(tex, texCoord.xy, 0.0).rgb;
vec3 behindColor = mix(straightBackground, refractedBackground, intensity);
fragColor.rgb = mix(refractionCol, color, opac);
fragColor.rgb = sceneSample.rgb + behindColor * (1.0 - sceneSample.a);
fragColor.a = 1.0;
} }

View File

@ -5,6 +5,9 @@
"depth_write": false, "depth_write": false,
"compare_mode": "always", "compare_mode": "always",
"cull_mode": "none", "cull_mode": "none",
"blend_source": "blend_one",
"blend_destination": "blend_zero",
"blend_operation": "add",
"links": [ "links": [
{ {
"name": "P", "name": "P",

View File

@ -36,6 +36,7 @@
#version 450 #version 450
#include "compiled.inc" #include "compiled.inc"
#include "std/gbuffer.glsl"
uniform sampler2D gbufferD; uniform sampler2D gbufferD;
uniform sampler2D gbuffer0; uniform sampler2D gbuffer0;
@ -47,69 +48,92 @@ uniform vec2 cameraProj;
in vec2 texCoord; in vec2 texCoord;
out vec4 fragColor; out vec4 fragColor;
const float SSSS_FOVY = 108.0; const vec3 SKIN_SSS_RADIUS = vec3(4.8, 2.4, 1.5);
const float SSS_DISTANCE_SCALE = 0.001;
// Temp hash func -
float hash13(vec3 p3) {
p3 = fract(p3 * vec3(0.1031, 0.1030, 0.0973));
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}
// Separable SSS Reflectance
// const float sssWidth = 0.005;
vec4 SSSSBlur() { vec4 SSSSBlur() {
// Quality = 0 const int SSSS_N_SAMPLES = 15;
const int SSSS_N_SAMPLES = 11; vec4 kernel[SSSS_N_SAMPLES];
vec4 kernel[SSSS_N_SAMPLES];
kernel[0] = vec4(0.560479, 0.669086, 0.784728, 0); kernel[0] = vec4(0.233, 0.455, 0.649, 0.0); // Center sample
kernel[1] = vec4(0.00471691, 0.000184771, 5.07566e-005, -2); kernel[1] = vec4(0.100, 0.336, 0.344, 0.37); // +0.37mm
kernel[2] = vec4(0.0192831, 0.00282018, 0.00084214, -1.28); kernel[2] = vec4(0.118, 0.198, 0.0, 0.97); // +0.97mm
kernel[3] = vec4(0.03639, 0.0130999, 0.00643685, -0.72); kernel[3] = vec4(0.113, 0.007, 0.007, 1.93); // +1.93mm
kernel[4] = vec4(0.0821904, 0.0358608, 0.0209261, -0.32); kernel[4] = vec4(0.358, 0.004, 0.0, 3.87); // +3.87mm
kernel[5] = vec4(0.0771802, 0.113491, 0.0793803, -0.08); kernel[5] = vec4(0.078, 0.0, 0.0, 6.53); // +6.53mm (red only)
kernel[6] = vec4(0.0771802, 0.113491, 0.0793803, 0.08); kernel[6] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
kernel[7] = vec4(0.0821904, 0.0358608, 0.0209261, 0.32); kernel[7] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
kernel[8] = vec4(0.03639, 0.0130999, 0.00643685, 0.72); kernel[8] = vec4(0.100, 0.336, 0.344, -0.37); // -0.37mm
kernel[9] = vec4(0.0192831, 0.00282018, 0.00084214, 1.28); kernel[9] = vec4(0.118, 0.198, 0.0, -0.97); // -0.97mm
kernel[10] = vec4(0.00471691, 0.000184771, 5.07565e-005, 2); kernel[10] = vec4(0.113, 0.007, 0.007, -1.93); // -1.93mm
kernel[11] = vec4(0.358, 0.004, 0.0, -3.87); // -3.87mm
kernel[12] = vec4(0.078, 0.0, 0.0, -6.53); // -6.53mm (red only)
kernel[13] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
kernel[14] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
vec4 colorM = textureLod(tex, texCoord, 0.0); vec4 colorM = textureLod(tex, texCoord, 0.0);
// Fetch linear depth of current pixel
float depth = textureLod(gbufferD, texCoord, 0.0).r; float depth = textureLod(gbufferD, texCoord, 0.0).r;
float depthM = cameraProj.y / (depth - cameraProj.x); float depthM = cameraProj.y / (depth - cameraProj.x);
// Calculate the sssWidth scale (1.0 for a unit plane sitting on the projection window) float distanceScale = 1.0 / max(depthM, 0.1);
float distanceToProjectionWindow = 1.0 / tan(0.5 * radians(SSSS_FOVY));
float scale = distanceToProjectionWindow / depthM; vec2 finalStep = sssWidth * distanceScale * dir * SSS_DISTANCE_SCALE;
// Calculate the final step to fetch the surrounding pixels vec3 jitterSeed = vec3(texCoord.xy * 1000.0, fract(cameraProj.x * 0.0001));
vec2 finalStep = sssWidth * scale * dir; float jitterOffset = (hash13(jitterSeed) * 2.0 - 1.0) * 0.15;
finalStep *= 1.0;//SSSS_STREGTH_SOURCE; // Modulate it using the alpha channel.
finalStep *= 1.0 / 3.0; // Divide by 3 as the kernels range from -3 to 3. finalStep *= (1.0 + jitterOffset);
finalStep *= 0.05; // vec3 colorBlurred = vec3(0.0);
vec3 weightSum = vec3(0.0);
// Accumulate the center sample: colorBlurred += colorM.rgb * kernel[0].rgb;
vec4 colorBlurred = colorM; weightSum += kernel[0].rgb;
colorBlurred.rgb *= kernel[0].rgb;
// Accumulate the other samples
for (int i = 1; i < SSSS_N_SAMPLES; i++) { for (int i = 1; i < SSSS_N_SAMPLES; i++) {
// Fetch color and depth for current sample float sampleJitter = hash13(vec3(texCoord.xy * 720.0, float(i) * 37.45)) * 0.1 - 0.05;
vec2 offset = texCoord + kernel[i].a * finalStep; vec2 offset = texCoord + (kernel[i].a + sampleJitter) * finalStep;
vec4 color = textureLod(tex, offset, 0.0); vec4 color = textureLod(tex, offset, 0.0);
//#if SSSS_FOLLOW_SURFACE == 1 const float DEPTH_THRESHOLD = 0.05;
// If the difference in depth is huge, we lerp color back to "colorM": float sampleDepth = textureLod(gbufferD, offset, 0.0).r;
//float depth = textureLod(tex, offset, 0.0).r; float sampleDepthM = cameraProj.y / (sampleDepth - cameraProj.x);
//float s = clamp(300.0f * distanceToProjectionWindow * sssWidth * abs(depthM - depth),0.0,1.0);
//color.rgb = mix(color.rgb, colorM.rgb, s); float depthDiff = abs(depthM - sampleDepthM);
//#endif float depthWeight = exp(-depthDiff * 10.0);
// Accumulate
colorBlurred.rgb += kernel[i].rgb * color.rgb; if (depthDiff > DEPTH_THRESHOLD) {
color.rgb = mix(colorM.rgb, color.rgb, depthWeight);
}
colorBlurred += color.rgb * kernel[i].rgb;
weightSum += kernel[i].rgb;
} }
vec3 normalizedColor = colorBlurred / max(weightSum, vec3(0.00001));
return colorBlurred; float dither = hash13(vec3(texCoord * 1333.0, 0.0)) * 0.003 - 0.0015;
normalizedColor = max(normalizedColor + vec3(dither), vec3(0.0));
return vec4(normalizedColor, colorM.a);
} }
void main() { void main() {
if (textureLod(gbuffer0, texCoord, 0.0).a == 8192.0) { vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
fragColor = clamp(SSSSBlur(), 0.0, 1.0); float metallic;
} uint matid;
else { unpackFloatInt16(g0.a, metallic, matid);
if (matid == 2u) {
vec4 originalColor = textureLod(tex, texCoord, 0.0);
vec4 blurredColor = SSSSBlur();
vec4 sssContribution = blurredColor - originalColor;
vec4 combined = originalColor + max(vec4(0.0), sssContribution) * 0.8;
fragColor = max(vec4(0.0), min(combined, vec4(10.0)));
} else {
fragColor = textureLod(tex, texCoord, 0.0); fragColor = textureLod(tex, texCoord, 0.0);
} }
} }

View File

@ -0,0 +1,18 @@
#ifndef _AABB_GLSL
#define _AABB_GLSL
bool IntersectAABB(vec3[2] a, vec3[2] b) {
const float EPSILON = 0.001; // Small tolerance to prevent false negatives
if (abs(a[0].x - b[0].x) > (a[1].x + b[1].x + EPSILON)) return false;
if (abs(a[0].y - b[0].y) > (a[1].y + b[1].y + EPSILON)) return false;
if (abs(a[0].z - b[0].z) > (a[1].z + b[1].z + EPSILON)) return false;
return true;
}
void AABBfromMinMax(inout vec3[2] aabb, vec3 _min, vec3 _max)
{
aabb[0] = (_min + _max) * 0.5f;
aabb[1] = abs(_max - aabb[0]);
}
#endif

View File

@ -36,7 +36,8 @@ float d_ggx(const float nh, const float a) {
vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) { vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) {
float a = roughness * roughness; float a = roughness * roughness;
return d_ggx(nh, a) * g2_approx(nl, nv, a) * f_schlick(f0, vh) / max(4.0 * nv, 1e-5); //NdotL cancels out later vec3 result = d_ggx(nh, a) * g2_approx(nl, nv, a) * f_schlick(f0, vh) / max(4.0 * nv, 1e-5); //NdotL cancels out later
return min(result, vec3(200.0));
} }
// John Hable - Optimizing GGX Shaders // John Hable - Optimizing GGX Shaders

View File

@ -22,7 +22,7 @@ THE SOFTWARE.
#ifndef _CONETRACE_GLSL_ #ifndef _CONETRACE_GLSL_
#define _CONETRACE_GLSL_ #define _CONETRACE_GLSL_
#include "std/voxels_constants.glsl" #include "std/constants.glsl"
// References // References
// https://github.com/Friduric/voxel-cone-tracing // https://github.com/Friduric/voxel-cone-tracing
@ -92,14 +92,14 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
float dist = voxelSize0; float dist = voxelSize0;
float step_dist = dist; float step_dist = dist;
vec3 samplePos; vec3 samplePos;
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset; vec3 start_pos = origin + n * voxelSize0;
int clipmap_index0 = 0; int clipmap_index0 = 0;
vec3 aniso_direction = -dir; vec3 aniso_direction = -dir;
vec3 face_offset = vec3( vec3 face_offset = vec3(
aniso_direction.x > 0.0 ? 0 : 1, aniso_direction.x > 0.0 ? 0.0 : 1.0,
aniso_direction.y > 0.0 ? 2 : 3, aniso_direction.y > 0.0 ? 2.0 : 3.0,
aniso_direction.z > 0.0 ? 4 : 5 aniso_direction.z > 0.0 ? 4.0 : 5.0
) / (6 + DIFFUSE_CONE_COUNT); ) / (6 + DIFFUSE_CONE_COUNT);
vec3 direction_weight = abs(dir); vec3 direction_weight = abs(dir);
@ -125,7 +125,7 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) { if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
vec4 mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight); vec4 mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
mipSample = mix(mipSample, mipSampleNext, smoothstep(0.0, 1.0, clipmap_blend)); mipSample = mix(mipSample, mipSampleNext, clipmap_blend);
} }
sampleCol += (1.0 - sampleCol.a) * mipSample; sampleCol += (1.0 - sampleCol.a) * mipSample;
@ -148,8 +148,9 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) { vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
float sum = 0.0; float sum = 0.0;
vec4 amount = vec4(0.0); vec4 amount = vec4(0.0);
mat3 TBN = makeTangentBasis(normal);
for (int i = 0; i < DIFFUSE_CONE_COUNT; ++i) { for (int i = 0; i < DIFFUSE_CONE_COUNT; ++i) {
vec3 coneDir = DIFFUSE_CONE_DIRECTIONS[i]; vec3 coneDir = TBN * DIFFUSE_CONE_DIRECTIONS[i];
const float cosTheta = dot(normal, coneDir); const float cosTheta = dot(normal, coneDir);
if (cosTheta <= 0) if (cosTheta <= 0)
continue; continue;
@ -196,14 +197,14 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
float dist = voxelSize0; float dist = voxelSize0;
float step_dist = dist; float step_dist = dist;
vec3 samplePos; vec3 samplePos;
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset; vec3 start_pos = origin + n * voxelSize0;
int clipmap_index0 = 0; int clipmap_index0 = 0;
vec3 aniso_direction = -dir; vec3 aniso_direction = -dir;
vec3 face_offset = vec3( vec3 face_offset = vec3(
aniso_direction.x > 0.0 ? 0 : 1, aniso_direction.x > 0.0 ? 0.0 : 1.0,
aniso_direction.y > 0.0 ? 2 : 3, aniso_direction.y > 0.0 ? 2.0 : 3.0,
aniso_direction.z > 0.0 ? 4 : 5 aniso_direction.z > 0.0 ? 4.0 : 5.0
) / (6 + DIFFUSE_CONE_COUNT); ) / (6 + DIFFUSE_CONE_COUNT);
vec3 direction_weight = abs(dir); vec3 direction_weight = abs(dir);
@ -259,7 +260,6 @@ float traceAO(const vec3 origin, const vec3 normal, const sampler3D voxels, cons
} }
#endif #endif
#ifdef _VoxelShadow #ifdef _VoxelShadow
float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 origin, const vec3 n, const vec3 dir, const float aperture, const float step_size, const float clipmaps[voxelgiClipmapCount * 10]) { float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 origin, const vec3 n, const vec3 dir, const float aperture, const float step_size, const float clipmaps[voxelgiClipmapCount * 10]) {
float sampleCol = 0.0; float sampleCol = 0.0;
@ -267,14 +267,14 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
float dist = voxelSize0; float dist = voxelSize0;
float step_dist = dist; float step_dist = dist;
vec3 samplePos; vec3 samplePos;
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset; vec3 start_pos = origin + n * voxelSize0;
int clipmap_index0 = 0; int clipmap_index0 = 0;
vec3 aniso_direction = -dir; vec3 aniso_direction = -dir;
vec3 face_offset = vec3( vec3 face_offset = vec3(
aniso_direction.x > 0.0 ? 0 : 1, aniso_direction.x > 0.0 ? 0.0 : 1.0,
aniso_direction.y > 0.0 ? 2 : 3, aniso_direction.y > 0.0 ? 2.0 : 3.0,
aniso_direction.z > 0.0 ? 4 : 5 aniso_direction.z > 0.0 ? 4.0 : 5.0
) / (6 + DIFFUSE_CONE_COUNT); ) / (6 + DIFFUSE_CONE_COUNT);
vec3 direction_weight = abs(dir); vec3 direction_weight = abs(dir);
float coneCoefficient = 2.0 * tan(aperture * 0.5); float coneCoefficient = 2.0 * tan(aperture * 0.5);
@ -287,7 +287,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
float clipmap_blend = fract(lod); float clipmap_blend = fract(lod);
vec3 p0 = start_pos + dir * dist; vec3 p0 = start_pos + dir * dist;
samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution.x); samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
samplePos = samplePos * 0.5 + 0.5; samplePos = samplePos * 0.5 + 0.5;
if ((any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0))))) { if ((any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0))))) {
@ -330,7 +330,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) { float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
vec3 P = origin + dir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep; vec3 P = origin + dir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, DIFFUSE_CONE_APERTURE, voxelgiStep, clipmaps); float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, SHADOW_CONE_APERTURE, voxelgiStep, clipmaps);
amount = clamp(amount, 0.0, 1.0); amount = clamp(amount, 0.0, 1.0);
return amount * voxelgiOcc; return amount * voxelgiOcc;
} }

View File

@ -0,0 +1,88 @@
/*
Copyright (c) 2024 Turánszki János
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
const int DIFFUSE_CONE_COUNT = 16;
const float SHADOW_CONE_APERTURE = radians(15.0);
const float DIFFUSE_CONE_APERTURE = 0.872665;
mat3 makeTangentBasis(const vec3 normal) {
// Create a tangent basis from normal vector
vec3 tangent;
vec3 bitangent;
// Compute tangent (Frisvad's method)
if (abs(normal.z) < 0.999) {
tangent = normalize(cross(vec3(0, 1, 0), normal));
} else {
tangent = normalize(cross(normal, vec3(1, 0, 0)));
}
bitangent = cross(normal, tangent);
return mat3(tangent, bitangent, normal);
}
// 16 optimized cone directions for hemisphere sampling (Z-up, normalized)
const vec3 DIFFUSE_CONE_DIRECTIONS[16] = vec3[](
vec3(0.707107, 0.000000, 0.707107), // Front
vec3(-0.707107, 0.000000, 0.707107), // Back
vec3(0.000000, 0.707107, 0.707107), // Right
vec3(0.000000, -0.707107, 0.707107), // Left
vec3(0.500000, 0.500000, 0.707107), // Front-right
vec3(-0.500000, 0.500000, 0.707107), // Back-right
vec3(0.500000, -0.500000, 0.707107), // Front-left
vec3(-0.500000, -0.500000, 0.707107),// Back-left
vec3(0.353553, 0.000000, 0.935414), // Narrow front
vec3(-0.353553, 0.000000, 0.935414), // Narrow back
vec3(0.000000, 0.353553, 0.935414), // Narrow right
vec3(0.000000, -0.353553, 0.935414), // Narrow left
vec3(0.270598, 0.270598, 0.923880), // Narrow front-right
vec3(-0.270598, 0.270598, 0.923880), // Narrow back-right
vec3(0.270598, -0.270598, 0.923880), // Narrow front-left
vec3(-0.270598, -0.270598, 0.923880) // Narrow back-left
);
// TO DO - Disabled momentarily instead of changing formulas
const float off_BayerMatrix8[8][8] =
{
{ 1.0 / 65.0, 49.0 / 65.0, 13.0 / 65.0, 61.0 / 65.0, 4.0 / 65.0, 52.0 / 65.0, 16.0 / 65.0, 64.0 / 65.0 },
{ 33.0 / 65.0, 17.0 / 65.0, 45.0 / 65.0, 29.0 / 65.0, 36.0 / 65.0, 20.0 / 65.0, 48.0 / 65.0, 32.0 / 65.0 },
{ 9.0 / 65.0, 57.0 / 65.0, 5.0 / 65.0, 53.0 / 65.0, 12.0 / 65.0, 60.0 / 65.0, 8.0 / 65.0, 56.0 / 65.0 },
{ 41.0 / 65.0, 25.0 / 65.0, 37.0 / 65.0, 21.0 / 65.0, 44.0 / 65.0, 28.0 / 65.0, 40.0 / 65.0, 24.0 / 65.0 },
{ 3.0 / 65.0, 51.0 / 65.0, 15.0 / 65.0, 63.0 / 65.0, 2.0 / 65.0, 50.0 / 65.0, 14.0 / 65.0, 62.0 / 65.0 },
{ 35.0 / 65.0, 19.0 / 65.0, 47.0 / 65.0, 31.0 / 65.0, 34.0 / 65.0, 18.0 / 65.0, 46.0 / 65.0, 30.0 / 65.0 },
{ 11.0 / 65.0, 59.0 / 65.0, 7.0 / 65.0, 55.0 / 65.0, 10.0 / 65.0, 58.0 / 65.0, 6.0 / 65.0, 54.0 / 65.0 },
{ 43.0 / 65.0, 27.0 / 65.0, 39.0 / 65.0, 23.0 / 65.0, 42.0 / 65.0, 26.0 / 65.0, 38.0 / 65.0, 22.0 / 65.0 }
};
const float BayerMatrix8[8][8] =
{
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 }
};

View File

@ -8,10 +8,10 @@
// const float compoDOFLength = 160.0; // Focal length in mm 18-200 // const float compoDOFLength = 160.0; // Focal length in mm 18-200
// const float compoDOFFstop = 128.0; // F-stop value // const float compoDOFFstop = 128.0; // F-stop value
const int samples = 6; // Samples on the first ring const int samples = 8; // Samples on the first ring
const int rings = 6; // Ring count const int rings = 6; // Ring count
const vec2 focus = vec2(0.5, 0.5); const vec2 focus = vec2(0.5, 0.5);
const float coc = 0.11; // Circle of confusion size in mm (35mm film = 0.03mm) const float coc = 0.03; // Circle of confusion size in mm (35mm film = 0.03mm)
const float maxblur = 1.0; const float maxblur = 1.0;
const float threshold = 0.5; // Highlight threshold const float threshold = 0.5; // Highlight threshold
const float gain = 2.0; // Highlight gain const float gain = 2.0; // Highlight gain
@ -55,21 +55,26 @@ vec3 dof(
float f = DOFLength; // Focal length in mm float f = DOFLength; // Focal length in mm
float d = fDepth * 1000.0; // Focal plane in mm float d = fDepth * 1000.0; // Focal plane in mm
float o = depth * 1000.0; // Depth in mm float o = depth * 1000.0; // Depth in mm
float a = (o * f) / (o - f); float a = (o > f) ? (o * f) / (o - f) : 0.0;
float b = (d * f) / (d - f); float b = (d > f) ? (d * f) / (d - f) : 0.0;
float c = (d - f) / (d * DOFFStop * coc); float sensorSize = max(DOFFStop, 10.0);
float c = (d - f) / (d * sensorSize * coc);
float blur = abs(a - b) * c; float blur = abs(a - b) * c;
blur = clamp(blur, 0.0, 1.0); blur = clamp(blur, 0.0, 1.0);
vec2 noise = rand2(texCoord) * namount * blur; vec2 noise = rand2(texCoord) * namount * blur;
float w = (texStep.x) * blur * maxblur + noise.x; float w = (texStep.x) * blur * maxblur + noise.x;
float h = (texStep.y) * blur * maxblur + noise.y; float h = (texStep.y) * blur * maxblur + noise.y;
vec3 col = vec3(0.0); vec3 sharpCol = textureLod(tex, texCoord, 0.0).rgb;
if (blur < 0.05) { vec3 col = sharpCol;
col = textureLod(tex, texCoord, 0.0).rgb; float blurThreshold = 0.02;
} float blurRange = 0.06;
else {
col = textureLod(tex, texCoord, 0.0).rgb; if (blur > blurThreshold) {
float blurAmount = smoothstep(blurThreshold, blurThreshold + blurRange, blur);
vec3 blurredCol = sharpCol;
float s = 1.0; float s = 1.0;
int ringsamples; int ringsamples;
@ -81,11 +86,12 @@ vec3 dof(
float ph = (sin(float(j) * step) * float(i)); float ph = (sin(float(j) * step) * float(i));
float p = 1.0; float p = 1.0;
// if (pentagon) p = penta(vec2(pw, ph)); // if (pentagon) p = penta(vec2(pw, ph));
col += color(texCoord + vec2(pw * w, ph * h), blur, tex, texStep) * mix(1.0, (float(i)) / (float(rings)), bias) * p; blurredCol += color(texCoord + vec2(pw * w, ph * h), blur, tex, texStep) * mix(1.0, (float(i)) / (float(rings)), bias) * p;
s += 1.0 * mix(1.0, (float(i)) / (float(rings)), bias) * p; s += 1.0 * mix(1.0, (float(i)) / (float(rings)), bias) * p;
} }
} }
col /= s; blurredCol /= s;
col = mix(sharpCol, blurredCol, blurAmount);
} }
return col; return col;
} }

View File

@ -1,11 +1,11 @@
#ifndef _GBUFFER_GLSL_ #ifndef _GBUFFER_GLSL_
#define _GBUFFER_GLSL_ #define _GBUFFER_GLSL_
vec2 octahedronWrap(const vec2 v) { vec2 octahedronWrap(vec2 v) {
return (1.0 - abs(v.yx)) * (vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0)); return (1.0 - abs(v.yx)) * (vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0));
} }
vec3 getNor(const vec2 enc) { vec3 getNor(vec2 enc) {
vec3 n; vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y); n.z = 1.0 - abs(enc.x) - abs(enc.y);
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy); n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
@ -13,13 +13,13 @@ vec3 getNor(const vec2 enc) {
return n; return n;
} }
vec3 getPosView(const vec3 viewRay, const float depth, const vec2 cameraProj) { vec3 getPosView(vec3 viewRay, float depth, vec2 cameraProj) {
float linearDepth = cameraProj.y / (cameraProj.x - depth); float linearDepth = cameraProj.y / (cameraProj.x - depth);
//float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x); //float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
return viewRay * linearDepth; return viewRay * linearDepth;
} }
vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) { vec3 getPos(vec3 eye, vec3 eyeLook, vec3 viewRay, float depth, vec2 cameraProj) {
// eyeLook, viewRay should be normalized // eyeLook, viewRay should be normalized
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x); float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
float viewZDist = dot(eyeLook, viewRay); float viewZDist = dot(eyeLook, viewRay);
@ -27,7 +27,7 @@ vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float
return wposition; return wposition;
} }
vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) { vec3 getPosNoEye(vec3 eyeLook, vec3 viewRay, float depth, vec2 cameraProj) {
// eyeLook, viewRay should be normalized // eyeLook, viewRay should be normalized
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x); float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
float viewZDist = dot(eyeLook, viewRay); float viewZDist = dot(eyeLook, viewRay);
@ -36,10 +36,10 @@ vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, cons
} }
#if defined(HLSL) || defined(METAL) #if defined(HLSL) || defined(METAL)
vec3 getPos2(const mat4 invVP, const float depth, vec2 coord) { vec3 getPos2(mat4 invVP, float depth, vec2 coord) {
coord.y = 1.0 - coord.y; coord.y = 1.0 - coord.y;
#else #else
vec3 getPos2(const mat4 invVP, const float depth, const vec2 coord) { vec3 getPos2(mat4 invVP, float depth, vec2 coord) {
#endif #endif
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0); vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
pos = invVP * pos; pos = invVP * pos;
@ -48,10 +48,10 @@ vec3 getPos2(const mat4 invVP, const float depth, const vec2 coord) {
} }
#if defined(HLSL) || defined(METAL) #if defined(HLSL) || defined(METAL)
vec3 getPosView2(const mat4 invP, const float depth, vec2 coord) { vec3 getPosView2(mat4 invP, float depth, vec2 coord) {
coord.y = 1.0 - coord.y; coord.y = 1.0 - coord.y;
#else #else
vec3 getPosView2(const mat4 invP, const float depth, const vec2 coord) { vec3 getPosView2(mat4 invP, float depth, vec2 coord) {
#endif #endif
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0); vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
pos = invP * pos; pos = invP * pos;
@ -60,10 +60,10 @@ vec3 getPosView2(const mat4 invP, const float depth, const vec2 coord) {
} }
#if defined(HLSL) || defined(METAL) #if defined(HLSL) || defined(METAL)
vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, vec2 coord) { vec3 getPos2NoEye(vec3 eye, mat4 invVP, float depth, vec2 coord) {
coord.y = 1.0 - coord.y; coord.y = 1.0 - coord.y;
#else #else
vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, const vec2 coord) { vec3 getPos2NoEye(vec3 eye, mat4 invVP, float depth, vec2 coord) {
#endif #endif
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0); vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
pos = invVP * pos; pos = invVP * pos;
@ -71,24 +71,24 @@ vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, const vec
return pos.xyz - eye; return pos.xyz - eye;
} }
float packFloat(const float f1, const float f2) { float packFloat(float f1, float f2) {
return floor(f1 * 100.0) + min(f2, 1.0 - 1.0 / 100.0); return floor(f1 * 100.0) + min(f2, 1.0 - 1.0 / 100.0);
} }
vec2 unpackFloat(const float f) { vec2 unpackFloat(float f) {
return vec2(floor(f) / 100.0, fract(f)); return vec2(floor(f) / 100.0, fract(f));
} }
float packFloat2(const float f1, const float f2) { float packFloat2(float f1, float f2) {
// Higher f1 = less precise f2 // Higher f1 = less precise f2
return floor(f1 * 255.0) + min(f2, 1.0 - 1.0 / 100.0); return floor(f1 * 255.0) + min(f2, 1.0 - 1.0 / 100.0);
} }
vec2 unpackFloat2(const float f) { vec2 unpackFloat2(float f) {
return vec2(floor(f) / 255.0, fract(f)); return vec2(floor(f) / 255.0, fract(f));
} }
vec4 encodeRGBM(const vec3 rgb) { vec4 encodeRGBM(vec3 rgb) {
const float maxRange = 6.0; const float maxRange = 6.0;
float maxRGB = max(rgb.x, max(rgb.g, rgb.b)); float maxRGB = max(rgb.x, max(rgb.g, rgb.b));
float m = maxRGB / maxRange; float m = maxRGB / maxRange;
@ -96,7 +96,7 @@ vec4 encodeRGBM(const vec3 rgb) {
return vec4(rgb / (m * maxRange), m); return vec4(rgb / (m * maxRange), m);
} }
vec3 decodeRGBM(const vec4 rgbm) { vec3 decodeRGBM(vec4 rgbm) {
const float maxRange = 6.0; const float maxRange = 6.0;
return rgbm.rgb * rgbm.a * maxRange; return rgbm.rgb * rgbm.a * maxRange;
} }
@ -150,7 +150,7 @@ vec3 decNor(uint val) {
/** /**
Packs a float in [0, 1] and an integer in [0..15] into a single 16 bit float value. Packs a float in [0, 1] and an integer in [0..15] into a single 16 bit float value.
**/ **/
float packFloatInt16(const float f, const uint i) { float packFloatInt16(float f, uint i) {
const uint numBitFloat = 12; const uint numBitFloat = 12;
const float maxValFloat = float((1 << numBitFloat) - 1); const float maxValFloat = float((1 << numBitFloat) - 1);
@ -160,7 +160,7 @@ float packFloatInt16(const float f, const uint i) {
return float(bitsInt | bitsFloat); return float(bitsInt | bitsFloat);
} }
void unpackFloatInt16(const float val, out float f, out uint i) { void unpackFloatInt16(float val, out float f, out uint i) {
const uint numBitFloat = 12; const uint numBitFloat = 12;
const float maxValFloat = float((1 << numBitFloat) - 1); const float maxValFloat = float((1 << numBitFloat) - 1);

View File

@ -10,9 +10,6 @@
#ifdef _VoxelShadow #ifdef _VoxelShadow
#include "std/conetrace.glsl" #include "std/conetrace.glsl"
#endif #endif
#ifdef _gbuffer2
uniform sampler2D gbuffer2;
#endif
#ifdef _LTC #ifdef _LTC
#include "std/ltc.glsl" #include "std/ltc.glsl"
#endif #endif
@ -25,46 +22,63 @@ uniform sampler2D gbuffer2;
#ifdef _Spot #ifdef _Spot
#include "std/light_common.glsl" #include "std/light_common.glsl"
#endif #endif
#ifdef _VoxelShadow
#include "std/conetrace.glsl"
#endif
#ifdef _ShadowMap #ifdef _ShadowMap
#ifdef _SinglePoint #ifdef _SinglePoint
#ifdef _Spot #ifdef _Spot
#ifndef _LTC #ifndef _LTC
uniform sampler2DShadow shadowMapSpot[1]; uniform sampler2DShadow shadowMapSpot[1];
#ifdef _ShadowMapTransparent
uniform sampler2D shadowMapSpotTransparent[1]; uniform sampler2D shadowMapSpotTransparent[1];
uniform mat4 LWVPSpot[1]; #endif
uniform mat4 LWVPSpotArray[1];
#endif #endif
#else #else
uniform samplerCubeShadow shadowMapPoint[1]; uniform samplerCubeShadow shadowMapPoint[1];
#ifdef _ShadowMapTransparent
uniform samplerCube shadowMapPointTransparent[1]; uniform samplerCube shadowMapPointTransparent[1];
#endif
uniform vec2 lightProj; uniform vec2 lightProj;
#endif #endif
#endif #endif
#ifdef _Clusters #ifdef _Clusters
#ifdef _SingleAtlas #ifdef _SingleAtlas
//!uniform sampler2DShadow shadowMapAtlas; //!uniform sampler2DShadow shadowMapAtlas;
#ifdef _ShadowMapTransparent
//!uniform sampler2D shadowMapAtlasTransparent; //!uniform sampler2D shadowMapAtlasTransparent;
#endif #endif
#endif
uniform vec2 lightProj; uniform vec2 lightProj;
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
#ifndef _SingleAtlas #ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasPoint; uniform sampler2DShadow shadowMapAtlasPoint;
#ifdef _ShadowMapTransparent
uniform sampler2D shadowMapAtlasPointTransparent; uniform sampler2D shadowMapAtlasPointTransparent;
#endif #endif
#endif
#else #else
uniform samplerCubeShadow shadowMapPoint[4]; uniform samplerCubeShadow shadowMapPoint[4];
#ifdef _ShadowMapTransparent
uniform samplerCube shadowMapPointTransparent[4]; uniform samplerCube shadowMapPointTransparent[4];
#endif #endif
#endif
#ifdef _Spot #ifdef _Spot
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
#ifndef _SingleAtlas #ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasSpot; uniform sampler2DShadow shadowMapAtlasSpot;
#ifdef _ShadowMapTransparent
uniform sampler2D shadowMapAtlasSpotTransparent; uniform sampler2D shadowMapAtlasSpotTransparent;
#endif #endif
#endif
#else #else
uniform sampler2DShadow shadowMapSpot[4]; uniform sampler2DShadow shadowMapSpot[4];
#ifdef _ShadowMapTransparent
uniform sampler2D shadowMapSpotTransparent[4]; uniform sampler2D shadowMapSpotTransparent[4];
#endif #endif
#endif
uniform mat4 LWVPSpotArray[maxLightsCluster]; uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif #endif
#endif #endif
@ -81,28 +95,35 @@ uniform sampler2D sltcMag;
#ifndef _Spot #ifndef _Spot
#ifdef _SinglePoint #ifdef _SinglePoint
uniform sampler2DShadow shadowMapSpot[1]; uniform sampler2DShadow shadowMapSpot[1];
#ifdef _ShadowMapTransparent
uniform sampler2D shadowMapSpotTransparent[1]; uniform sampler2D shadowMapSpotTransparent[1];
uniform mat4 LWVPSpot[1]; #endif
uniform mat4 LWVPSpotArray[1];
#endif #endif
#ifdef _Clusters #ifdef _Clusters
uniform sampler2DShadow shadowMapSpot[maxLightsCluster]; uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
#ifdef _ShadowMapTransparent
uniform sampler2D shadowMapSpotTransparent[maxLightsCluster]; uniform sampler2D shadowMapSpotTransparent[maxLightsCluster];
#endif
uniform mat4 LWVPSpotArray[maxLightsCluster]; uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif #endif
#endif #endif
#endif #endif
#endif #endif
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol, vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
const vec3 albedo, const float rough, const float spec, const vec3 f0 const vec3 albedo, const float rough, const float spec, const vec3 f0
#ifdef _ShadowMap #ifdef _ShadowMap
, int index, float bias, bool receiveShadow, bool transparent , int index, float bias, bool receiveShadow
#ifdef _ShadowMapTransparent
, bool transparent
#endif
#endif #endif
#ifdef _Spot #ifdef _Spot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right , const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif #endif
#ifdef _VoxelShadow #ifdef _VoxelShadow
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount] , sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount], vec2 velocity
#endif #endif
#ifdef _MicroShadowing #ifdef _MicroShadowing
, float occ , float occ
@ -137,7 +158,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#endif #endif
direct *= attenuate(distance(p, lp)); direct *= attenuate(distance(p, lp));
direct *= lightCol; direct *= min(lightCol, vec3(100.0));
#ifdef _MicroShadowing #ifdef _MicroShadowing
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0); direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
@ -148,23 +169,67 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#endif #endif
#ifdef _VoxelShadow #ifdef _VoxelShadow
vec4 g2 = textureLod(gbuffer2, gl_FragCoord.xy, 0.0); vec3 lightDir = l;
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps, gl_FragCoord.xy, g2.rg).r) * voxelgiShad; #ifdef _Spot
if (isSpot)
lightDir = spotDir;
#endif
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, lightDir, clipmaps, gl_FragCoord.xy, velocity).r) * voxelgiShad;
#endif #endif
#ifdef _LTC #ifdef _LTC
#ifdef _ShadowMap #ifdef _ShadowMap
if (receiveShadow) { if (receiveShadow) {
#ifdef _SinglePoint #ifdef _SinglePoint
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0); vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 2, 1.0);
direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent); direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif #endif
#ifdef _Clusters #ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0); vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 2, 1.0);
if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent); if (index == 0) direct *= shadowTest(shadowMapSpot[0],
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent); #ifdef _ShadowMapTransparent
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent); shadowMapSpotTransparent[0],
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent); #endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[1],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[2],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[3],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif #endif
} }
#endif #endif
@ -178,25 +243,76 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#ifdef _ShadowMap #ifdef _ShadowMap
if (receiveShadow) { if (receiveShadow) {
#ifdef _SinglePoint #ifdef _SinglePoint
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0); vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 2, 1.0);
direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent); direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif #endif
#ifdef _Clusters #ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0); vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 2, 1.0);
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
direct *= shadowTest( direct *= shadowTest(
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas #ifndef _SingleAtlas
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
#else #else
shadowMapAtlas, shadowMapAtlasTransparent shadowMapAtlas, shadowMapAtlasTransparent
#endif #endif
, lPos.xyz / lPos.w, bias, transparent #else
); #ifndef _SingleAtlas
shadowMapAtlasSpot
#else
shadowMapAtlas
#endif
#endif
, lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else #else
if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent); if (index == 0) direct *= shadowTest(shadowMapSpot[0],
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent); #ifdef _ShadowMapTransparent
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent); shadowMapSpotTransparent[0],
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent); #endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[1],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[2],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[3],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif #endif
#endif #endif
} }
@ -213,24 +329,75 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
if (receiveShadow) { if (receiveShadow) {
#ifdef _SinglePoint #ifdef _SinglePoint
#ifndef _Spot #ifndef _Spot
direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent); direct *= PCFCube(shadowMapPoint[0],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[0],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif #endif
#endif #endif
#ifdef _Clusters #ifdef _Clusters
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
direct *= PCFFakeCube( direct *= PCFFakeCube(
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas #ifndef _SingleAtlas
shadowMapAtlasPoint, shadowMapAtlasPointTransparent shadowMapAtlasPoint, shadowMapAtlasPointTransparent
#else #else
shadowMapAtlas, shadowMapAtlasTransparent shadowMapAtlas, shadowMapAtlasTransparent
#endif #endif
, ld, -l, bias, lightProj, n, index, transparent #else
); #ifndef _SingleAtlas
shadowMapAtlasPoint
#else
shadowMapAtlas
#endif
#endif
, ld, -l, bias, lightProj, n, index
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else #else
if (index == 0) direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent); if (index == 0) direct *= PCFCube(shadowMapPoint[0],
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], shadowMapPointTransparent[1], ld, -l, bias, lightProj, n, transparent); #ifdef _ShadowMapTransparent
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], shadowMapPointTransparent[2], ld, -l, bias, lightProj, n, transparent); shadowMapPointTransparent[0],
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], shadowMapPointTransparent[3], ld, -l, bias, lightProj, n, transparent); #endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 1) direct *= PCFCube(shadowMapPoint[1],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[1],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 2) direct *= PCFCube(shadowMapPoint[2],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[2],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 3) direct *= PCFCube(shadowMapPoint[3],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[3],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif #endif
#endif #endif
} }
@ -239,4 +406,275 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
return direct; return direct;
} }
#ifdef _VoxelGI
vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
const vec3 albedo, const float rough, const float spec, const vec3 f0
#ifdef _ShadowMap
, int index, float bias, bool receiveShadow
#ifdef _ShadowMapTransparent
, bool transparent
#endif
#endif
#ifdef _Spot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
) {
vec3 ld = lp - p;
vec3 l = normalize(ld);
vec3 h = normalize(v + l);
float dotNH = max(0.0, dot(n, h));
float dotVH = max(0.0, dot(v, h));
float dotNL = max(0.0, dot(n, l));
#ifdef _LTC
float theta = acos(dotNV);
vec2 tuv = vec2(rough, theta / (0.5 * PI));
tuv = tuv * LUT_SCALE + LUT_BIAS;
vec4 t = textureLod(sltcMat, tuv, 0.0);
mat3 invM = mat3(
vec3(1.0, 0.0, t.y),
vec3(0.0, t.z, 0.0),
vec3(t.w, 0.0, t.x));
float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3);
ltcspec *= textureLod(sltcMag, tuv, 0.0).a;
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
#else
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
#endif
direct *= attenuate(distance(p, lp));
// CRITICAL: Clamp light color to prevent extreme HDR values causing white sphere artifacts
direct *= min(lightCol, vec3(100.0));
#ifdef _LTC
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 2, 1.0);
direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 2, 1.0);
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[1],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[2],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[3],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
}
#endif
return direct;
#endif
#ifdef _Spot
if (isSpot) {
direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 2, 1.0);
direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 2, 1.0);
#ifdef _ShadowMapAtlas
direct *= shadowTest(
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSpot
#else
shadowMapAtlas
#endif
#endif
, lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[1],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[2],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[3],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#endif
}
#endif
return direct;
}
#endif
#ifdef _LightIES
direct *= iesAttenuation(-l);
#endif
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
#ifndef _Spot
direct *= PCFCube(shadowMapPoint[0],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[0],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#endif
#ifdef _Clusters
#ifdef _ShadowMapAtlas
direct *= PCFFakeCube(
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasPoint, shadowMapAtlasPointTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasPoint
#else
shadowMapAtlas
#endif
#endif
, ld, -l, bias, lightProj, n, index
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else
if (index == 0) direct *= PCFCube(shadowMapPoint[0],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[0],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 1) direct *= PCFCube(shadowMapPoint[1],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[1],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 2) direct *= PCFCube(shadowMapPoint[2],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[2],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 3) direct *= PCFCube(shadowMapPoint[3],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[3],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#endif
}
#endif
return direct;
}
#endif
#endif #endif

View File

@ -5,6 +5,7 @@ uniform vec2 morphDataDim;
uniform vec4 morphWeights[8]; uniform vec4 morphWeights[8];
void getMorphedVertex(vec2 uvCoord, inout vec3 A){ void getMorphedVertex(vec2 uvCoord, inout vec3 A){
vec3 totalDelta = vec3(0.0);
for(int i = 0; i<8; i++ ) for(int i = 0; i<8; i++ )
{ {
vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y, vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y,
@ -13,21 +14,28 @@ void getMorphedVertex(vec2 uvCoord, inout vec3 A){
uvCoord.y - (i * 4 + 3) * morphDataDim.y); uvCoord.y - (i * 4 + 3) * morphDataDim.y);
vec3 morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.x)).rgb * morphScaleOffset.x + morphScaleOffset.y; vec3 morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.x)).rgb * morphScaleOffset.x + morphScaleOffset.y;
A += morphWeights[i].x * morph; totalDelta += morphWeights[i].x * morph;
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.y)).rgb * morphScaleOffset.x + morphScaleOffset.y; morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.y)).rgb * morphScaleOffset.x + morphScaleOffset.y;
A += morphWeights[i].y * morph; totalDelta += morphWeights[i].y * morph;
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.z)).rgb * morphScaleOffset.x + morphScaleOffset.y; morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.z)).rgb * morphScaleOffset.x + morphScaleOffset.y;
A += morphWeights[i].z * morph; totalDelta += morphWeights[i].z * morph;
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.w)).rgb * morphScaleOffset.x + morphScaleOffset.y; morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.w)).rgb * morphScaleOffset.x + morphScaleOffset.y;
A += morphWeights[i].w * morph; totalDelta += morphWeights[i].w * morph;
} }
//float deltaLength = length(totalDelta);
//if (deltaLength > 5.0) {
// clamp corrupted data
//totalDelta = normalize(totalDelta) * 5.0;
//}
A += totalDelta;
} }
void getMorphedNormal(vec2 uvCoord, vec3 oldNor, inout vec3 morphNor){ void getMorphedNormal(vec2 uvCoord, vec3 oldNor, inout vec3 morphNor){
vec3 normalDelta = vec3(0.0);
for(int i = 0; i<8; i++ ) for(int i = 0; i<8; i++ )
{ {
vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y, vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y,
@ -35,19 +43,11 @@ void getMorphedNormal(vec2 uvCoord, vec3 oldNor, inout vec3 morphNor){
uvCoord.y - (i * 4 + 2) * morphDataDim.y, uvCoord.y - (i * 4 + 2) * morphDataDim.y,
uvCoord.y - (i * 4 + 3) * morphDataDim.y); uvCoord.y - (i * 4 + 3) * morphDataDim.y);
vec3 norm = oldNor + morphWeights[i].x * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.x)).rgb * 2.0 - 1.0); normalDelta += morphWeights[i].x * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.x)).rgb * 2.0 - 1.0);
morphNor += norm; normalDelta += morphWeights[i].y * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.y)).rgb * 2.0 - 1.0);
normalDelta += morphWeights[i].z * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.z)).rgb * 2.0 - 1.0);
norm = oldNor + morphWeights[i].y * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.y)).rgb * 2.0 - 1.0); normalDelta += morphWeights[i].w * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.w)).rgb * 2.0 - 1.0);
morphNor += norm;
norm = oldNor + morphWeights[i].z * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.z)).rgb * 2.0 - 1.0);
morphNor += norm;
norm = oldNor + morphWeights[i].w * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.w)).rgb * 2.0 - 1.0);
morphNor += norm;
} }
morphNor = normalize(morphNor); morphNor = normalize(oldNor + normalDelta);
} }

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD>shader_datas<EFBFBD><EFBFBD><EFBFBD>name<EFBFBD>copy_pass<EFBFBD>contexts<EFBFBD><EFBFBD><EFBFBD>name<EFBFBD>copy_pass<EFBFBD>constants<EFBFBD><EFBFBD>texture_units<EFBFBD><EFBFBD><EFBFBD>name<EFBFBD>tex<EFBFBD>vertex_elements<EFBFBD><EFBFBD><EFBFBD>data<EFBFBD>float2<EFBFBD>name<EFBFBD>pos<EFBFBD>vertex_shader<EFBFBD>pass.vert<72>fragment_shader<65>pass_copy.frag<61>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E><65>name<6D>compositor_pass<73>contexts<74><73><EFBFBD>name<6D>compositor_pass<73>constants<74><73>texture_units<74><73><EFBFBD>name<6D>tex<65>vertex_elements<74><73><EFBFBD>data<74>float2<74>name<6D>pos<6F>vertex_shader<65>compositor_pass.vert<72>fragment_shader<65>compositor_pass.frag<61>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E><65>name<6D>deferred_light<68>contexts<74><73><EFBFBD>name<6D>deferred_light<68>constants<74><73><EFBFBD>type<70>mat4<74>name<6D>invVP<56>link<6E>_inverseViewProjectionMatrix<69><78>type<70>vec3<63>name<6D>eye<79>link<6E>_cameraPosition<6F><6E>type<70>float<61>name<6D>envmapStrength<74>link<6E>_envmapStrength<74><68>type<70>floats<74>name<6D>shirr<72>link<6E>_envmapIrradiance<63><65>type<70>int<6E>name<6D>envmapNumMipmaps<70>link<6E>_envmapNumMipmaps<70><73>type<70>vec2<63>name<6D>cameraProj<6F>link<6E>_cameraPlaneProj<6F><6A>type<70>vec3<63>name<6D>eyeLook<6F>link<6E>_cameraLook<6F><6B>type<70>vec2<63>name<6D>lightProj<6F>link<6E>_lightPlaneProj<6F><6A>type<70>vec3<63>name<6D>pointPos<6F>link<6E>_pointPosition<6F><6E>type<70>vec3<63>name<6D>pointCol<6F>link<6E>_pointColor<6F><72>type<70>float<61>name<6D>pointBias<61>link<6E>_pointShadowsBias<61>texture_units<74><73><EFBFBD>name<6D>gbufferD<72><44>name<6D>gbuffer0<72><30>name<6D>gbuffer1<72><31>name<6D>senvmapBrdf<64>link<6E>$brdf.png<6E><67>name<6D>senvmapRadiance<63>link<6E>_envmapRadiance<63><65>name<6D>shadowMapPoint[0]<5D>vertex_elements<74><73><EFBFBD>data<74>float2<74>name<6D>pos<6F>vertex_shader<65>pass_viewray.vert<72>fragment_shader<65>deferred_light.frag<61>color_attachments<74><73>RGBA64<36>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E><65>name<6D>water_pass<73>contexts<74><73><EFBFBD>name<6D>water_pass<73>constants<74><73><EFBFBD>type<70>mat4<74>name<6D>invVP<56><50>type<70>vec3<63>name<6D>eye<79>link<6E>_cameraPosition<6F><6E>type<70>float<61>name<6D>time<6D>link<6E>_time<6D><65>type<70>float<61>name<6D>holoOverallStrength<74><68>type<70>vec2<63>name<6D>cameraProj<6F>link<6E>_cameraPlaneProj<6F><6A>type<70>vec3<63>name<6D>eyeLook<6F>link<6E>_cameraLook<6F><6B>type<70>vec3<63>name<6D>ld<6C>link<6E>_lightDirection<6F>texture_units<74><73><EFBFBD>name<6D>tex<65><78>name<6D>gbufferD<72><44>name<6D>gbuffer0<72>vertex_elements<74><73><EFBFBD>data<74>float2<74>name<6D>pos<6F>vertex_shader<65>pass_viewray.vert<72>fragment_shader<65>water_pass.frag<61>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E>blend_source<63>source_alpha<68>blend_destination<6F>inverse_source_alpha<68>blend_operation<6F>add<64>alpha_blend_source<63>blend_one<6E>alpha_blend_destination<6F>blend_one<6E>alpha_blend_operation<6F>add<64><64>contexts<74><73><EFBFBD>name<6D>World_World<6C>depth_write¬compare_mode<64>less<73>cull_mode<64>clockwise<73>vertex_elements<74><73><EFBFBD>name<6D>pos<6F>data<74>float3<74><33>name<6D>nor<6F>data<74>float3<74>color_attachments<74><73>_HDR<44>texture_units<74><73>constants<74><73><EFBFBD>name<6D>SMVP<56>type<70>mat4<74>link<6E>_skydomeMatrix<69>vertex_shader<65>World_World.vert<72>fragment_shader<65>World_World.frag<61>name<6D>World_World

View File

@ -23,6 +23,59 @@ uniform vec2 smSizeUniform;
#endif #endif
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
// PCF that clamps samples to tile boundaries to prevent bleeding
vec3 PCFTileAware(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec2 uv, const float compare, const vec2 smSize,
const vec2 tileMin, const vec2 tileMax
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
vec3 result = vec3(0.0);
vec2 offset;
offset = vec2(-1.0, -1.0) / smSize;
result.x = texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(-1.0, 0.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(-1.0, 1.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(0.0, -1.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
result.x += texture(shadowMap, vec3(uv, compare));
offset = vec2(0.0, 1.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(1.0, -1.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(1.0, 0.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(1.0, 1.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
result = result.xxx / 9.0;
#ifdef _ShadowMapTransparent
if (transparent == false) {
vec4 shadowmap_transparent = texture(shadowMapTransparent, uv);
if (shadowmap_transparent.a < compare)
result *= shadowmap_transparent.rgb;
}
#endif
return result;
}
// https://www.khronos.org/registry/OpenGL/specs/gl/glspec20.pdf // p:168 // https://www.khronos.org/registry/OpenGL/specs/gl/glspec20.pdf // p:168
// https://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/5337472/ // https://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/5337472/
vec2 sampleCube(vec3 dir, out int faceIndex) { vec2 sampleCube(vec3 dir, out int faceIndex) {
@ -58,7 +111,15 @@ vec2 sampleCube(vec3 dir, out int faceIndex) {
} }
#endif #endif
vec3 PCF(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec2 uv, const float compare, const vec2 smSize, const bool transparent) { vec3 PCF(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec2 uv, const float compare, const vec2 smSize
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
vec3 result = vec3(0.0); vec3 result = vec3(0.0);
result.x = texture(shadowMap, vec3(uv + (vec2(-1.0, -1.0) / smSize), compare)); result.x = texture(shadowMap, vec3(uv + (vec2(-1.0, -1.0) / smSize), compare));
result.x += texture(shadowMap, vec3(uv + (vec2(-1.0, 0.0) / smSize), compare)); result.x += texture(shadowMap, vec3(uv + (vec2(-1.0, 0.0) / smSize), compare));
@ -71,11 +132,13 @@ vec3 PCF(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec2 u
result.x += texture(shadowMap, vec3(uv + (vec2(1.0, 1.0) / smSize), compare)); result.x += texture(shadowMap, vec3(uv + (vec2(1.0, 1.0) / smSize), compare));
result = result.xxx / 9.0; result = result.xxx / 9.0;
#ifdef _ShadowMapTransparent
if (transparent == false) { if (transparent == false) {
vec4 shadowmap_transparent = texture(shadowMapTransparent, uv); vec4 shadowmap_transparent = texture(shadowMapTransparent, uv);
if (shadowmap_transparent.a < compare) if (shadowmap_transparent.a < compare)
result *= shadowmap_transparent.rgb; result *= shadowmap_transparent.rgb;
} }
#endif
return result; return result;
} }
@ -87,7 +150,15 @@ float lpToDepth(vec3 lp, const vec2 lightProj) {
return zcomp * 0.5 + 0.5; return zcomp * 0.5 + 0.5;
} }
vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const bool transparent) { vec3 PCFCube(samplerCubeShadow shadowMapCube,
#ifdef _ShadowMapTransparent
samplerCube shadowMapCubeTransparent,
#endif
const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
const float s = shadowmapCubePcfSize; // TODO: incorrect... const float s = shadowmapCubePcfSize; // TODO: incorrect...
float compare = lpToDepth(lp, lightProj) - bias * 1.5; float compare = lpToDepth(lp, lightProj) - bias * 1.5;
ml = ml + n * bias * 20; ml = ml + n * bias * 20;
@ -106,11 +177,13 @@ vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTranspare
result.x += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare)); result.x += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare));
result = result.xxx / 9.0; result = result.xxx / 9.0;
#ifdef _ShadowMapTransparent
if (transparent == false) { if (transparent == false) {
vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml); vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml);
if (shadowmap_transparent.a < compare) if (shadowmap_transparent.a < compare)
result *= shadowmap_transparent.rgb; result *= shadowmap_transparent.rgb;
} }
#endif
return result; return result;
} }
@ -209,21 +282,31 @@ vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 uv) {
return uv; return uv;
} }
vec3 PCFFakeCube(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const int index, const bool transparent) { vec3 PCFFakeCube(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const int index
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
const vec2 smSize = smSizeUniform; // TODO: incorrect... const vec2 smSize = smSizeUniform; // TODO: incorrect...
const float compare = lpToDepth(lp, lightProj) - bias * 1.5; const float compare = lpToDepth(lp, lightProj) - bias * 1.5;
ml = ml + n * bias * 20; ml = ml + n * bias * 20;
int faceIndex = 0; int faceIndex = 0;
const int lightIndex = index * 6; const int lightIndex = index * 6;
const vec2 uv = sampleCube(ml, faceIndex); const vec2 uv = sampleCube(ml, faceIndex);
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy; vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
#ifdef _FlipY #ifdef _FlipY
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
#endif #endif
if (any(lessThan(uvtiled, vec2(0.0))) || any(greaterThan(uvtiled, vec2(1.0)))) {
return vec3(1.0);
}
vec3 result = vec3(0.0); vec3 result = vec3(0.0);
result.x += texture(shadowMap, vec3(uvtiled, compare)); result.x += texture(shadowMap, vec3(uvtiled, compare));
// soft shadowing // soft shadowing
@ -236,14 +319,6 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, cons
#endif #endif
result.x += texture(shadowMap, vec3(uvtiled, compare)); result.x += texture(shadowMap, vec3(uvtiled, compare));
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, 1.0) / smSize)));
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
#ifdef _FlipY
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
#endif
result.x += texture(shadowMap, vec3(uvtiled, compare));
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.0, -1.0) / smSize))); uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.0, -1.0) / smSize)));
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex]; pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy; uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
@ -300,30 +375,72 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, cons
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
#endif #endif
#ifdef _ShadowMapTransparent
if (transparent == false) { if (transparent == false) {
vec4 shadowmap_transparent = texture(shadowMapTransparent, uvtiled); vec4 shadowmap_transparent = texture(shadowMapTransparent, uvtiled);
if (shadowmap_transparent.a < compare) if (shadowmap_transparent.a < compare)
result *= shadowmap_transparent.rgb; result *= shadowmap_transparent.rgb;
} }
#endif
return result; return result;
} }
#endif #endif
vec3 shadowTest(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 lPos, const float shadowsBias, const bool transparent) { #ifdef _ShadowMapAtlas
uniform vec4 tileBounds;
#endif
vec3 shadowTest(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec3 lPos, const float shadowsBias
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return vec3(1.0);
#ifdef _ShadowMapAtlas
// use tile PCF
#ifdef _SMSizeUniform
vec2 smSizeAtlas = smSizeUniform;
#else
const vec2 smSizeAtlas = shadowmapSize;
#endif
return PCFTileAware(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSizeAtlas,
tileBounds.xy, tileBounds.zw
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else
// use PCF for non-atlas shadows
#ifdef _SMSizeUniform #ifdef _SMSizeUniform
vec2 smSize = smSizeUniform; vec2 smSize = smSizeUniform;
#else #else
const vec2 smSize = shadowmapSize; const vec2 smSize = shadowmapSize;
#endif #endif
if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return vec3(1.0); return PCF(shadowMap,
return PCF(shadowMap, shadowMapTransparent, lPos.xy, lPos.z - shadowsBias, smSize, transparent); #ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
} }
#ifdef _CSM #ifdef _CSM
mat4 getCascadeMat(const float d, out int casi, out int casIndex) { mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
const int c = shadowmapCascades; const int c = shadowmapCascades;
// Get cascade index // Get cascade index
// TODO: use bounding box slice selection instead of sphere // TODO: use bounding box slice selection instead of sphere
const vec4 ci = vec4(float(c > 0), float(c > 1), float(c > 2), float(c > 3)); const vec4 ci = vec4(float(c > 0), float(c > 1), float(c > 2), float(c > 3));
@ -339,21 +456,26 @@ mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
float(d > casData[c * 4].z), float(d > casData[c * 4].z),
float(d > casData[c * 4].w)); float(d > casData[c * 4].w));
casi = int(min(dot(ci, comp), c)); casi = int(min(dot(ci, comp), c));
// Get cascade mat // Get cascade mat
casIndex = casi * 4; casIndex = casi * 4;
return mat4( return mat4(
casData[casIndex ], casData[casIndex ],
casData[casIndex + 1], casData[casIndex + 1],
casData[casIndex + 2], casData[casIndex + 2],
casData[casIndex + 3]); casData[casIndex + 3]);
// if (casIndex == 0) return mat4(casData[0], casData[1], casData[2], casData[3]); // if (casIndex == 0) return mat4(casData[0], casData[1], casData[2], casData[3]);
// .. // ..
} }
vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 eye, const vec3 p, const float shadowsBias, const bool transparent) { vec3 shadowTestCascade(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec3 eye, const vec3 p, const float shadowsBias
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
#ifdef _SMSizeUniform #ifdef _SMSizeUniform
vec2 smSize = smSizeUniform; vec2 smSize = smSizeUniform;
#else #else
@ -361,16 +483,22 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent
#endif #endif
const int c = shadowmapCascades; const int c = shadowmapCascades;
float d = distance(eye, p); float d = distance(eye, p);
int casi; int casi;
int casIndex; int casIndex;
mat4 LWVP = getCascadeMat(d, casi, casIndex); mat4 LWVP = getCascadeMat(d, casi, casIndex);
vec4 lPos = LWVP * vec4(p, 1.0); vec4 lPos = LWVP * vec4(p, 1.0);
lPos.xyz /= lPos.w; lPos.xyz /= lPos.w;
vec3 visibility = vec3(1.0); vec3 visibility = vec3(1.0);
if (lPos.w > 0.0) visibility = PCF(shadowMap, shadowMapTransparent, lPos.xy, lPos.z - shadowsBias, smSize, transparent); if (lPos.w > 0.0) visibility = PCF(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
// Blend cascade // Blend cascade
// https://github.com/TheRealMJP/Shadows // https://github.com/TheRealMJP/Shadows
@ -389,13 +517,21 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent
vec4 lPos2 = LWVP2 * vec4(p, 1.0); vec4 lPos2 = LWVP2 * vec4(p, 1.0);
lPos2.xyz /= lPos2.w; lPos2.xyz /= lPos2.w;
vec3 visibility2 = vec3(1.0); vec3 visibility2 = vec3(1.0);
if (lPos2.w > 0.0) visibility2 = PCF(shadowMap, shadowMapTransparent, lPos2.xy, lPos2.z - shadowsBias, smSize, transparent); // use lPos2 coordinates for second cascade, not lPos
if (lPos2.w > 0.0) visibility2 = PCF(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos2.xy, lPos2.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
float lerpAmt = smoothstep(0.0, blendThres, splitDist); float lerpAmt = smoothstep(0.0, blendThres, splitDist);
return mix(visibility2, visibility, lerpAmt); return mix(visibility2, visibility, lerpAmt);
} }
return visibility; return visibility;
// Visualize cascades // Visualize cascades
// if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0); // if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0);
// if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0); // if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0);
@ -403,4 +539,4 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent
// if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0); // if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0);
} }
#endif #endif
#endif #endif

View File

@ -11,6 +11,8 @@ vec3 uncharted2Tonemap(const vec3 x) {
vec3 tonemapUncharted2(const vec3 color) { vec3 tonemapUncharted2(const vec3 color) {
const float W = 11.2; const float W = 11.2;
const float exposureBias = 2.0; const float exposureBias = 2.0;
// TODO - Find out why black world value of 0.0,0.0,0.0 turns to white pixels
if (dot(color, color) < 0.001) return vec3(0.001);
vec3 curr = uncharted2Tonemap(exposureBias * color); vec3 curr = uncharted2Tonemap(exposureBias * color);
vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W)); vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
return curr * whiteScale; return curr * whiteScale;

View File

@ -13,32 +13,80 @@ out vec4 fragColor;
const float SMAA_REPROJECTION_WEIGHT_SCALE = 30.0; const float SMAA_REPROJECTION_WEIGHT_SCALE = 30.0;
// TODO: Move to a utility
bool isInvalidValue(float v) {
return (v != v) || (v > 65000.0) || (v < -65000.0);
}
bool hasInvalidValues(vec3 v) {
return isInvalidValue(v.x) || isInvalidValue(v.y) || isInvalidValue(v.z);
}
void main() { void main() {
vec4 current = textureLod(tex, texCoord, 0.0); vec4 current = textureLod(tex, texCoord, 0.0);
current.rgb = clamp(current.rgb, vec3(0.0), vec3(10.0));
current.a = clamp(current.a, 0.0, 1.0);
if (hasInvalidValues(current.rgb)) {
current = vec4(0.0, 0.0, 0.0, 1.0);
}
#ifdef _Veloc #ifdef _Veloc
// Velocity is assumed to be calculated for motion blur, so we need to inverse it for reprojection // Velocity is assumed to be calculated for motion blur, so we need to inverse it for reprojection
vec2 velocity = -textureLod(sveloc, texCoord, 0.0).rg; vec2 velocity = -textureLod(sveloc, texCoord, 0.0).rg;
velocity = clamp(velocity, vec2(-1.0), vec2(1.0));
if (isInvalidValue(velocity.x) || isInvalidValue(velocity.y)) {
velocity = vec2(0.0);
}
#ifdef _InvY #ifdef _InvY
velocity.y = -velocity.y; velocity.y = -velocity.y;
#endif #endif
// Reproject current coordinates and fetch previous pixel // Reproject current coordinates and fetch previous pixel
vec4 previous = textureLod(tex2, texCoord + velocity, 0.0); vec2 prevCoord = texCoord + velocity;
prevCoord = clamp(prevCoord, vec2(0.0), vec2(1.0));
vec4 previous = textureLod(tex2, prevCoord, 0.0);
previous.rgb = clamp(previous.rgb, vec3(0.0), vec3(10.0));
previous.a = clamp(previous.a, 0.0, 1.0);
if (hasInvalidValues(previous.rgb)) {
previous = current; // Fallback to current frame if previous is corrupted
}
// Attenuate the previous pixel if the velocity is different
#ifdef _SMAA #ifdef _SMAA
float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0; float currentAlpha = clamp(current.a, 0.0, 1.0);
float previousAlpha = clamp(previous.a, 0.0, 1.0);
float delta = abs(currentAlpha * currentAlpha - previousAlpha * previousAlpha) / 5.0;
delta = clamp(delta, 0.0, 1.0); // Ensure delta is in valid range
#else #else
const float delta = 0.0; const float delta = 0.0;
#endif #endif
float weight = 0.5 * clamp(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE, 0.0, 1.0);
float weight = 0.5 * clamp(1.0 - sqrt(max(delta, 0.0)) * SMAA_REPROJECTION_WEIGHT_SCALE, 0.0, 1.0);
// Blend the pixels according to the calculated weight: vec3 blended = mix(current.rgb, previous.rgb, weight);
fragColor = vec4(mix(current.rgb, previous.rgb, weight), 1.0); blended = clamp(blended, vec3(0.0), vec3(10.0));
if (hasInvalidValues(blended)) {
blended = current.rgb;
}
fragColor = vec4(blended, 1.0);
#else #else
vec4 previous = textureLod(tex2, texCoord, 0.0); vec4 previous = textureLod(tex2, texCoord, 0.0);
fragColor = vec4(mix(current.rgb, previous.rgb, 0.5), 1.0);
previous.rgb = clamp(previous.rgb, vec3(0.0), vec3(10.0));
if (hasInvalidValues(previous.rgb)) {
previous.rgb = current.rgb;
}
vec3 blended = mix(current.rgb, previous.rgb, 0.5);
blended = clamp(blended, vec3(0.0), vec3(10.0));
if (hasInvalidValues(blended)) {
blended = current.rgb;
}
fragColor = vec4(blended, 1.0);
#endif #endif
} }

View File

@ -11,6 +11,11 @@
#include "std/light_common.glsl" #include "std/light_common.glsl"
#endif #endif
#ifdef _CPostprocess
uniform vec3 PPComp11;
uniform vec4 PPComp17;
#endif
uniform sampler2D gbufferD; uniform sampler2D gbufferD;
uniform sampler2D snoise; uniform sampler2D snoise;
@ -87,7 +92,13 @@ out float fragColor;
const float tScat = 0.08; const float tScat = 0.08;
const float tAbs = 0.0; const float tAbs = 0.0;
const float tExt = tScat + tAbs; const float tExt = tScat + tAbs;
const float stepLen = 1.0 / volumSteps; #ifdef _CPostprocess
float stepLen = 1.0 / int(PPComp11.y);
float AirTurbidity = PPComp17.w;
#else
const float stepLen = 1.0 / volumSteps;
float AirTurbidity = volumAirTurbidity;
#endif
const float lighting = 0.4; const float lighting = 0.4;
void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatteredLightAmount, float stepLenWorld, vec3 viewVecNorm) { void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatteredLightAmount, float stepLenWorld, vec3 viewVecNorm) {
@ -162,5 +173,5 @@ void main() {
rayStep(curPos, curOpticalDepth, scatteredLightAmount, stepLenWorld, viewVecNorm); rayStep(curPos, curOpticalDepth, scatteredLightAmount, stepLenWorld, viewVecNorm);
} }
fragColor = scatteredLightAmount * volumAirTurbidity; fragColor = scatteredLightAmount * AirTurbidity;
} }

View File

@ -140,6 +140,16 @@
"link": "_biasLightWorldViewProjectionMatrixSpot3", "link": "_biasLightWorldViewProjectionMatrixSpot3",
"ifndef": ["_ShadowMapAtlas"], "ifndef": ["_ShadowMapAtlas"],
"ifdef": ["_Spot", "_ShadowMap"] "ifdef": ["_Spot", "_ShadowMap"]
},
{
"name": "PPComp11",
"link": "_PPComp11",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp17",
"link": "_PPComp17",
"ifdef": ["_CPostprocess"]
} }
], ],
"texture_params": [], "texture_params": [],

View File

@ -87,51 +87,49 @@ float lpToDepth(vec3 lp, const vec2 lightProj) {
void main() { void main() {
int res = voxelgiResolution.x; int res = voxelgiResolution.x;
for (int i = 0; i < 6; i++) { ivec3 dst = ivec3(gl_GlobalInvocationID.xyz);
ivec3 dst = ivec3(gl_GlobalInvocationID.xyz);
vec3 P = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution;
P = P * 2.0 - 1.0;
float visibility; vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
vec3 lp = lightPos - P; wposition = wposition * 2.0 - 1.0;
vec3 l; wposition *= float(clipmaps[int(clipmapLevel * 10)]);
if (lightType == 0) { l = lightDir; visibility = 1.0; } wposition *= voxelgiResolution.x;
else { l = normalize(lp); visibility = attenuate(distance(P, lightPos)); } wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]);
float visibility;
vec3 lp = lightPos -wposition;
vec3 l;
if (lightType == 0) { l = lightDir; visibility = 1.0; }
else { l = normalize(lp); visibility = attenuate(distance(wposition, lightPos)); }
#ifdef _ShadowMap #ifdef _ShadowMap
if (lightShadow == 1) { if (lightShadow == 1) {
vec4 lightPosition = LVP * vec4(P, 1.0); vec4 lightPosition = LVP * vec4(wposition, 1.0);
vec3 lPos = lightPosition.xyz / lightPosition.w; vec3 lPos = lightPosition.xyz / lightPosition.w;
visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).r; visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).r;
}
else if (lightShadow == 2) {
vec4 lightPosition = LVP * vec4(P, 1.0);
vec3 lPos = lightPosition.xyz / lightPosition.w;
visibility *= texture(shadowMapSpot, vec3(lPos.xy, lPos.z - shadowsBias)).r;
}
else if (lightShadow == 3) {
#ifdef _ShadowMapAtlas
int faceIndex = 0;
const int lightIndex = index * 6;
const vec2 uv = sampleCube(-l, faceIndex);
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
#ifdef _FlipY
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
#endif
visibility *= texture(shadowMapPoint, vec3(uvtiled, lpToDepth(lp, lightProj) - shadowsBias)).r;
#else
visibility *= texture(shadowMapPoint, vec4(-l, lpToDepth(lp, lightProj) - shadowsBias)).r;
#endif
}
#endif
vec3 uvw_light = (P - vec3(clipmaps[int(clipmapLevel * 10 + 4)], clipmaps[int(clipmapLevel * 10 + 5)], clipmaps[int(clipmapLevel * 10 + 6)])) / (float(clipmaps[int(clipmapLevel * 10)]) * voxelgiResolution);
uvw_light = (uvw_light * 0.5 + 0.5);
if (any(notEqual(uvw_light, clamp(uvw_light, 0.0, 1.0)))) return;
vec3 writecoords_light = floor(uvw_light * voxelgiResolution);
imageAtomicMax(voxelsLight, ivec3(writecoords_light), uint(visibility * lightColor.r * 255));
imageAtomicMax(voxelsLight, ivec3(writecoords_light) + ivec3(0, 0, voxelgiResolution.x), uint(visibility * lightColor.g * 255));
imageAtomicMax(voxelsLight, ivec3(writecoords_light) + ivec3(0, 0, voxelgiResolution.x * 2), uint(visibility * lightColor.b * 255));
} }
else if (lightShadow == 2) {
vec4 lightPosition = LVP * vec4(wposition, 1.0);
vec3 lPos = lightPosition.xyz / lightPosition.w;
visibility *= texture(shadowMapSpot, vec3(lPos.xy, lPos.z - shadowsBias)).r;
}
else if (lightShadow == 3) {
#ifdef _ShadowMapAtlas
int faceIndex = 0;
const int lightIndex = index * 6;
const vec2 uv = sampleCube(-l, faceIndex);
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
#ifdef _FlipY
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
#endif
visibility *= texture(shadowMapPoint, vec3(uvtiled, lpToDepth(lp, lightProj) - shadowsBias)).r;
#else
visibility *= texture(shadowMapPoint, vec4(-l, lpToDepth(lp, lightProj) - shadowsBias)).r;
#endif
}
#endif
imageAtomicAdd(voxelsLight, dst, uint(visibility * lightColor.r * 255));
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x), uint(visibility * lightColor.g * 255));
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x * 2), uint(visibility * lightColor.b * 255));
} }

View File

@ -27,14 +27,14 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
#include "std/math.glsl" #include "std/math.glsl"
#include "std/gbuffer.glsl" #include "std/gbuffer.glsl"
#include "std/imageatomic.glsl" #include "std/imageatomic.glsl"
#include "std/voxels_constants.glsl" #include "std/constants.glsl"
#ifdef _VoxelGI #ifdef _VoxelGI
uniform layout(rgba8) image3D voxelsB; uniform layout(rgba8) image3D voxelsB;
uniform layout(rgba8) image3D voxelsOut; uniform layout(rgba8) image3D voxelsOut;
#else #else
uniform layout(r16) image3D voxelsB; uniform layout(r8) image3D voxelsB;
uniform layout(r16) image3D voxelsOut; uniform layout(r8) image3D voxelsOut;
#endif #endif
uniform int clipmapLevel; uniform int clipmapLevel;

View File

@ -29,19 +29,38 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#include "std/gbuffer.glsl" #include "std/gbuffer.glsl"
#include "std/imageatomic.glsl" #include "std/imageatomic.glsl"
#include "std/conetrace.glsl" #include "std/conetrace.glsl"
#include "std/brdf.glsl"
#include "std/shirr.glsl"
uniform sampler3D voxels; uniform sampler3D voxels;
uniform sampler2D gbufferD; uniform sampler2D gbufferD;
uniform sampler2D gbuffer0; uniform sampler2D gbuffer0;
uniform layout(r16) image2D voxels_ao; uniform layout(rgba8) image2D voxels_ao;
uniform float clipmaps[voxelgiClipmapCount * 10]; uniform float clipmaps[voxelgiClipmapCount * 10];
uniform mat4 InvVP; uniform mat4 InvVP;
uniform vec2 cameraProj;
uniform vec3 eye; uniform vec3 eye;
uniform vec3 eyeLook;
uniform vec2 postprocess_resolution; uniform vec2 postprocess_resolution;
uniform sampler2D gbuffer1;
#ifdef _gbuffer2
uniform sampler2D gbuffer2;
#endif
uniform float envmapStrength;
#ifdef _Irr
uniform float shirr[7 * 4];
#endif
#ifdef _Brdf
uniform sampler2D senvmapBrdf;
#endif
#ifdef _Rad
uniform sampler2D senvmapRadiance;
uniform int envmapNumMipmaps;
#endif
#ifdef _EnvCol
uniform vec3 backgroundCol;
#endif
void main() { void main() {
const vec2 pixel = gl_GlobalInvocationID.xy; const vec2 pixel = gl_GlobalInvocationID.xy;
vec2 uv = (pixel + 0.5) / postprocess_resolution; vec2 uv = (pixel + 0.5) / postprocess_resolution;
@ -54,12 +73,11 @@ void main() {
float x = uv.x * 2 - 1; float x = uv.x * 2 - 1;
float y = uv.y * 2 - 1; float y = uv.y * 2 - 1;
vec4 v = vec4(x, y, 1.0, 1.0); vec4 clipPos = vec4(x, y, depth, 1.0);
v = vec4(InvVP * v); vec4 worldPos = InvVP * clipPos;
v.xyz /= v.w; vec3 P = worldPos.xyz / worldPos.w;
vec3 viewRay = v.xyz - eye;
vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj); vec3 v = normalize(eye - P);
vec4 g0 = textureLod(gbuffer0, uv, 0.0); vec4 g0 = textureLod(gbuffer0, uv, 0.0);
vec3 n; vec3 n;
@ -67,7 +85,89 @@ void main() {
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy); n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
n = normalize(n); n = normalize(n);
float occ = 1.0 - traceAO(P, n, voxels, clipmaps); float roughness = g0.b;
float metallic;
uint matid;
unpackFloatInt16(g0.a, metallic, matid);
imageStore(voxels_ao, ivec2(pixel), vec4(occ)); vec4 g1 = textureLod(gbuffer1, uv, 0.0); // Basecolor.rgb, spec/occ
vec2 occspec = unpackFloat2(g1.a);
vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
vec3 f0 = surfaceF0(g1.rgb, metallic);
float dotNV = max(dot(n, v), 0.0);
#ifdef _gbuffer2
vec4 g2 = textureLod(gbuffer2, uv, 0.0);
#endif
#ifdef _MicroShadowing
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
#endif
#ifdef _Brdf
vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
vec3 F = f0 * envBRDF.x + envBRDF.y;
#endif
// Envmap
#ifdef _Irr
vec4 shPacked[7];
for (int i = 0; i < 7; i++) {
int base = i * 4;
shPacked[i] = vec4(
shirr[base],
shirr[base + 1],
shirr[base + 2],
shirr[base + 3]
);
}
vec3 envl = shIrradiance(n, shPacked);
#ifdef _gbuffer2
if (g2.b < 0.5) {
envl = envl;
} else {
envl = vec3(0.0);
}
#endif
#ifdef _EnvTex
envl /= PI;
#endif
#else
vec3 envl = vec3(0.0);
#endif
#ifdef _Rad
vec3 reflectionWorld = reflect(-v, n);
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
#endif
#ifdef _EnvLDR
envl.rgb = pow(envl.rgb, vec3(2.2));
#ifdef _Rad
prefilteredColor = pow(prefilteredColor, vec3(2.2));
#endif
#endif
envl.rgb *= albedo;
#ifdef _Brdf
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
#endif
#ifdef _Rad // Indirect specular
envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
#else
#ifdef _EnvCol
envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
#endif
#endif
envl.rgb *= envmapStrength * occspec.x;
vec3 occ = envl * (1.0 - traceAO(P, n, voxels, clipmaps));
imageStore(voxels_ao, ivec2(pixel), vec4(occ, 1.0));
} }

View File

@ -29,19 +29,38 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#include "std/gbuffer.glsl" #include "std/gbuffer.glsl"
#include "std/imageatomic.glsl" #include "std/imageatomic.glsl"
#include "std/conetrace.glsl" #include "std/conetrace.glsl"
#include "std/brdf.glsl"
#include "std/shirr.glsl"
uniform sampler3D voxels; uniform sampler3D voxels;
uniform sampler2D gbufferD; uniform sampler2D gbufferD;
uniform sampler2D gbuffer0; uniform sampler2D gbuffer0;
uniform layout(rgba16) image2D voxels_diffuse; uniform layout(rgba8) image2D voxels_diffuse;
uniform float clipmaps[voxelgiClipmapCount * 10]; uniform float clipmaps[voxelgiClipmapCount * 10];
uniform mat4 InvVP; uniform mat4 InvVP;
uniform vec2 cameraProj;
uniform vec3 eye; uniform vec3 eye;
uniform vec3 eyeLook;
uniform vec2 postprocess_resolution; uniform vec2 postprocess_resolution;
uniform sampler2D gbuffer1;
#ifdef _gbuffer2
uniform sampler2D gbuffer2;
#endif
uniform float envmapStrength;
#ifdef _Irr
uniform float shirr[7 * 4];
#endif
#ifdef _Brdf
uniform sampler2D senvmapBrdf;
#endif
#ifdef _Rad
uniform sampler2D senvmapRadiance;
uniform int envmapNumMipmaps;
#endif
#ifdef _EnvCol
uniform vec3 backgroundCol;
#endif
void main() { void main() {
const vec2 pixel = gl_GlobalInvocationID.xy; const vec2 pixel = gl_GlobalInvocationID.xy;
vec2 uv = (pixel + 0.5) / postprocess_resolution; vec2 uv = (pixel + 0.5) / postprocess_resolution;
@ -50,16 +69,14 @@ void main() {
#endif #endif
float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0; float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
if (depth == 0) return; if (depth == 0.0) return;
float x = uv.x * 2 - 1; float x = uv.x * 2 - 1;
float y = uv.y * 2 - 1; float y = uv.y * 2 - 1;
vec4 v = vec4(x, y, 1.0, 1.0); vec4 clipPos = vec4(x, y, depth, 1.0);
v = vec4(InvVP * v); vec4 worldPos = InvVP * clipPos;
v.xyz /= v.w; vec3 P = worldPos.xyz / worldPos.w;
vec3 viewRay = v.xyz - eye; vec3 v = normalize(eye - P);
vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
vec4 g0 = textureLod(gbuffer0, uv, 0.0); vec4 g0 = textureLod(gbuffer0, uv, 0.0);
vec3 n; vec3 n;
@ -67,7 +84,94 @@ void main() {
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy); n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
n = normalize(n); n = normalize(n);
vec4 color = traceDiffuse(P, n, voxels, clipmaps); float roughness = g0.b;
float metallic;
uint matid;
unpackFloatInt16(g0.a, metallic, matid);
imageStore(voxels_diffuse, ivec2(pixel), color); vec4 g1 = textureLod(gbuffer1, uv, 0.0); // Basecolor.rgb, spec/occ
vec2 occspec = unpackFloat2(g1.a);
vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
vec3 f0 = surfaceF0(g1.rgb, metallic);
float dotNV = max(dot(n, v), 0.0);
#ifdef _gbuffer2
vec4 g2 = textureLod(gbuffer2, uv, 0.0);
#endif
#ifdef _MicroShadowing
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
#endif
#ifdef _Brdf
vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
vec3 F = f0 * envBRDF.x + envBRDF.y;
#else
vec3 F = f0;
#endif
// Envmap
#ifdef _Irr
vec4 shPacked[7];
for (int i = 0; i < 7; i++) {
int base = i * 4;
shPacked[i] = vec4(
shirr[base],
shirr[base + 1],
shirr[base + 2],
shirr[base + 3]
);
}
vec3 envl = shIrradiance(n, shPacked);
#ifdef _gbuffer2
if (g2.b < 0.5) {
envl = envl;
} else {
envl = vec3(0.0);
}
#endif
#ifdef _EnvTex
envl /= PI;
#endif
#else
vec3 envl = vec3(0.0);
#endif
#ifdef _Rad
vec3 reflectionWorld = reflect(-v, n);
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
#endif
#ifdef _EnvLDR
envl.rgb = pow(envl.rgb, vec3(2.2));
#ifdef _Rad
prefilteredColor = pow(prefilteredColor, vec3(2.2));
#endif
#endif
envl.rgb *= albedo;
#ifdef _Brdf
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
#endif
#ifdef _Rad // Indirect specular
envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
#else
#ifdef _EnvCol
envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
#endif
#endif
envl.rgb *= envmapStrength * occspec.x;
vec4 trace = traceDiffuse(P, n, voxels, clipmaps);
vec3 color = trace.rgb * albedo * (1.0 - F);
color += envl * (1.0 - trace.a);
imageStore(voxels_diffuse, ivec2(pixel), vec4(color, 1.0));
} }

View File

@ -29,18 +29,17 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#include "std/gbuffer.glsl" #include "std/gbuffer.glsl"
#include "std/imageatomic.glsl" #include "std/imageatomic.glsl"
#include "std/conetrace.glsl" #include "std/conetrace.glsl"
#include "std/brdf.glsl"
uniform sampler2D gbufferD; uniform sampler2D gbufferD;
uniform sampler2D gbuffer0; uniform sampler2D gbuffer0;
uniform sampler3D voxels; uniform sampler3D voxels;
uniform sampler3D voxelsSDF; uniform sampler3D voxelsSDF;
uniform layout(rgba16) image2D voxels_specular; uniform layout(rgba8) image2D voxels_specular;
uniform float clipmaps[voxelgiClipmapCount * 10]; uniform float clipmaps[voxelgiClipmapCount * 10];
uniform mat4 InvVP; uniform mat4 InvVP;
uniform vec2 cameraProj;
uniform vec3 eye; uniform vec3 eye;
uniform vec3 eyeLook;
uniform vec2 postprocess_resolution; uniform vec2 postprocess_resolution;
uniform sampler2D sveloc; uniform sampler2D sveloc;
@ -56,12 +55,10 @@ void main() {
float x = uv.x * 2 - 1; float x = uv.x * 2 - 1;
float y = uv.y * 2 - 1; float y = uv.y * 2 - 1;
vec4 v = vec4(x, y, 1.0, 1.0); vec4 clipPos = vec4(x, y, depth, 1.0);
v = vec4(InvVP * v); vec4 worldPos = InvVP * clipPos;
v.xyz /= v.w; vec3 P = worldPos.xyz / worldPos.w;
vec3 viewRay = v.xyz - eye;
vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
vec4 g0 = textureLod(gbuffer0, uv, 0.0); vec4 g0 = textureLod(gbuffer0, uv, 0.0);
vec3 n; vec3 n;

View File

@ -74,13 +74,9 @@ void main() {
#endif #endif
#endif #endif
ivec3 src = ivec3(gl_GlobalInvocationID.xyz); int nor_count = 0;
#ifdef _VoxelGI vec3 avgNormal = vec3(0.0);
vec3 light = vec3(0.0); mat3 TBN = mat3(0.0);
light.r = float(imageLoad(voxelsLight, src)) / 255;
light.g = float(imageLoad(voxelsLight, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
light.b = float(imageLoad(voxelsLight, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
#endif
for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++) for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++)
{ {
@ -90,7 +86,7 @@ void main() {
float aniso_colors[6]; float aniso_colors[6];
#endif #endif
src = ivec3(gl_GlobalInvocationID.xyz); ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
src.x += i * res; src.x += i * res;
ivec3 dst = src; ivec3 dst = src;
dst.y += clipmapLevel * res; dst.y += clipmapLevel * res;
@ -103,44 +99,67 @@ void main() {
if (i < 6) { if (i < 6) {
#ifdef _VoxelGI #ifdef _VoxelGI
vec4 basecol = vec4(0.0); int count = int(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 15)));
basecol.r = float(imageLoad(voxels, src)) / 255; if (count > 0) {
basecol.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x))) / 255; vec4 basecol = vec4(0.0);
basecol.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255; basecol.r = float(imageLoad(voxels, src)) / 255;
basecol.a = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 3))) / 255; basecol.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
basecol /= 4; basecol.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
vec3 emission = vec3(0.0); basecol.a = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 3))) / 255;
emission.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 4))) / 255; basecol /= count;
emission.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 5))) / 255; vec3 emission = vec3(0.0);
emission.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 6))) / 255; emission.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 4))) / 255;
emission /= 3; emission.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 5))) / 255;
vec3 N = vec3(0.0); emission.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 6))) / 255;
N.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 7))) / 255; emission /= count;
N.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 8))) / 255; vec3 N = vec3(0.0);
N /= 2; N.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 7))) / 255;
vec3 wnormal = decode_oct(N.rg * 2 - 1); N.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 8))) / 255;
vec3 envl = vec3(0.0); N /= count;
envl.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 9))) / 255; N = decode_oct(N.rg * 2.0 - 1.0);
envl.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 10))) / 255;
envl.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255;
envl /= 3;
if (abs(N.x) > 0)
avgNormal.x += N.x;
if (abs(N.y) > 0)
avgNormal.y += N.y;
if (abs(N.z) > 0)
avgNormal.z += N.z;
if (i == 5)
{
avgNormal = normalize(avgNormal);
TBN = makeTangentBasis(avgNormal);
}
//clipmap to world vec3 envl = vec3(0.0);
vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x; envl.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 9))) / 255;
wposition = wposition * 2.0 - 1.0; envl.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 10))) / 255;
wposition *= float(clipmaps[int(clipmapLevel * 10)]); envl.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255;
wposition *= voxelgiResolution.x; envl /= count;
wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]); vec3 light = vec3(0.0);
light.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 12))) / 255;
light.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 13))) / 255;
light.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 14))) / 255;
light /= count;
radiance = basecol; //clipmap to world
vec4 trace = traceDiffuse(wposition, wnormal, voxelsSampler, clipmaps); vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a); wposition = wposition * 2.0 - 1.0;
radiance.rgb *= light / PI + indirect; wposition *= float(clipmaps[int(clipmapLevel * 10)]);
radiance.rgb += emission.rgb; wposition *= voxelgiResolution.x;
wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]);
radiance = basecol;
vec4 trace = traceDiffuse(wposition, N, voxelsSampler, clipmaps);
vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a);
radiance.rgb *= light + indirect;
radiance.rgb += emission.rgb;
}
#else #else
opac = float(imageLoad(voxels, src)) / 255; int count = int(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x)));
if (count > 0) {
opac = float(imageLoad(voxels, src)) / 255;
opac /= count;
}
#endif #endif
#ifdef _VoxelGI #ifdef _VoxelGI
@ -194,7 +213,7 @@ void main() {
} }
else { else {
// precompute cone sampling: // precompute cone sampling:
vec3 coneDirection = DIFFUSE_CONE_DIRECTIONS[i - 6]; vec3 coneDirection = TBN * DIFFUSE_CONE_DIRECTIONS[i - 6];
vec3 aniso_direction = -coneDirection; vec3 aniso_direction = -coneDirection;
uvec3 face_offsets = uvec3( uvec3 face_offsets = uvec3(
aniso_direction.x > 0 ? 0 : 1, aniso_direction.x > 0 ? 0 : 1,
@ -235,4 +254,4 @@ void main() {
imageStore(SDF, dst_sdf, vec4(sdf)); imageStore(SDF, dst_sdf, vec4(sdf));
#endif #endif
#endif #endif
} }

View File

@ -75,17 +75,16 @@ vec4 binarySearch(vec3 dir) {
} }
vec4 rayCast(vec3 dir) { vec4 rayCast(vec3 dir) {
float ddepth; #ifdef _CPostprocess
dir *= ss_refractionRayStep; dir *= PPComp9.x;
for (int i = 0; i < maxSteps; i++) { #else
hitCoord += dir; dir *= ssrRayStep;
ddepth = getDeltaDepth(hitCoord); #endif
if (ddepth > 0.0) for (int i = 0; i < maxSteps; i++) {
return binarySearch(dir); hitCoord += dir;
} if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir);
// No hit — fallback to projecting the ray to UV space }
vec2 fallbackUV = getProjectedCoord(hitCoord); return vec4(0.0);
return vec4(fallbackUV, 0.0, 0.5); // We set .w lower to indicate fallback
} }
#endif //SSR #endif //SSR

View File

@ -12,6 +12,7 @@ class App {
static var traitInits: Array<Void->Void> = []; static var traitInits: Array<Void->Void> = [];
static var traitUpdates: Array<Void->Void> = []; static var traitUpdates: Array<Void->Void> = [];
static var traitLateUpdates: Array<Void->Void> = []; static var traitLateUpdates: Array<Void->Void> = [];
static var traitFixedUpdates: Array<Void->Void> = [];
static var traitRenders: Array<kha.graphics4.Graphics->Void> = []; static var traitRenders: Array<kha.graphics4.Graphics->Void> = [];
static var traitRenders2D: Array<kha.graphics2.Graphics->Void> = []; static var traitRenders2D: Array<kha.graphics2.Graphics->Void> = [];
public static var framebuffer: kha.Framebuffer; public static var framebuffer: kha.Framebuffer;
@ -23,6 +24,8 @@ class App {
public static var renderPathTime: Float; public static var renderPathTime: Float;
public static var endFrameCallbacks: Array<Void->Void> = []; public static var endFrameCallbacks: Array<Void->Void> = [];
#end #end
static var last = 0.0;
static var time = 0.0;
static var lastw = -1; static var lastw = -1;
static var lasth = -1; static var lasth = -1;
public static var onResize: Void->Void = null; public static var onResize: Void->Void = null;
@ -34,13 +37,14 @@ class App {
function new(done: Void->Void) { function new(done: Void->Void) {
done(); done();
kha.System.notifyOnFrames(render); kha.System.notifyOnFrames(render);
kha.Scheduler.addTimeTask(update, 0, iron.system.Time.delta); kha.Scheduler.addTimeTask(update, 0, iron.system.Time.step);
} }
public static function reset() { public static function reset() {
traitInits = []; traitInits = [];
traitUpdates = []; traitUpdates = [];
traitLateUpdates = []; traitLateUpdates = [];
traitFixedUpdates = [];
traitRenders = []; traitRenders = [];
traitRenders2D = []; traitRenders2D = [];
if (onResets != null) for (f in onResets) f(); if (onResets != null) for (f in onResets) f();
@ -48,6 +52,39 @@ class App {
static function update() { static function update() {
if (Scene.active == null || !Scene.active.ready) return; if (Scene.active == null || !Scene.active.ready) return;
// VR is handling it so we prevent double updates
// TODO: avoid js.Syntax
#if (kha_webgl && lnx_vr)
var vrActive = false;
js.Syntax.code("
if (typeof kha !== 'undefined' && kha.vr && kha.vr.VrInterface) {
const vr = kha.vr.VrInterface.instance;
if (vr && vr.IsPresenting && vr.IsPresenting()) {
{0} = true;
}
}
", vrActive);
if (vrActive) return;
#end
iron.system.Time.update();
if (lastw == -1) {
lastw = App.w();
lasth = App.h();
}
if (lastw != App.w() || lasth != App.h()) {
if (onResize != null) onResize();
else {
if (Scene.active != null && Scene.active.camera != null) {
Scene.active.camera.buildProjection();
}
}
}
lastw = App.w();
lasth = App.h();
if (pauseUpdates) return; if (pauseUpdates) return;
#if lnx_debug #if lnx_debug
@ -56,6 +93,14 @@ class App {
Scene.active.updateFrame(); Scene.active.updateFrame();
time += iron.system.Time.delta;
while (time >= iron.system.Time.fixedStep) {
for (f in traitFixedUpdates) f();
time -= iron.system.Time.fixedStep;
}
var i = 0; var i = 0;
var l = traitUpdates.length; var l = traitUpdates.length;
while (i < l) { while (i < l) {
@ -84,29 +129,13 @@ class App {
for (cb in endFrameCallbacks) cb(); for (cb in endFrameCallbacks) cb();
updateTime = kha.Scheduler.realTime() - startTime; updateTime = kha.Scheduler.realTime() - startTime;
#end #end
// Rebuild projection on window resize
if (lastw == -1) {
lastw = App.w();
lasth = App.h();
}
if (lastw != App.w() || lasth != App.h()) {
if (onResize != null) onResize();
else {
if (Scene.active != null && Scene.active.camera != null) {
Scene.active.camera.buildProjection();
}
}
}
lastw = App.w();
lasth = App.h();
} }
static function render(frames: Array<kha.Framebuffer>) { static function render(frames: Array<kha.Framebuffer>) {
var frame = frames[0]; var frame = frames[0];
framebuffer = frame; framebuffer = frame;
iron.system.Time.update(); iron.system.Time.render();
if (Scene.active == null || !Scene.active.ready) { if (Scene.active == null || !Scene.active.ready) {
render2D(frame); render2D(frame);
@ -124,6 +153,21 @@ class App {
traitInits.splice(0, traitInits.length); traitInits.splice(0, traitInits.length);
} }
// skip for XR callback to handle rendering
// TODO: avoid js Syntax
#if (kha_webgl && lnx_vr)
var vrActive = false;
js.Syntax.code("
if (typeof kha !== 'undefined' && kha.vr && kha.vr.VrInterface) {
const vr = kha.vr.VrInterface.instance;
if (vr && vr.IsPresenting && vr.IsPresenting()) {
{0} = true;
}
}
", vrActive);
if (!vrActive) {
#end
Scene.active.renderFrame(frame.g4); Scene.active.renderFrame(frame.g4);
for (f in traitRenders) { for (f in traitRenders) {
@ -132,6 +176,10 @@ class App {
render2D(frame); render2D(frame);
#if (kha_webgl && lnx_vr)
}
#end
#if lnx_debug #if lnx_debug
renderPathTime = kha.Scheduler.realTime() - startTime; renderPathTime = kha.Scheduler.realTime() - startTime;
#end #end
@ -172,6 +220,14 @@ class App {
traitLateUpdates.remove(f); traitLateUpdates.remove(f);
} }
public static function notifyOnFixedUpdate(f: Void->Void) {
traitFixedUpdates.push(f);
}
public static function removeFixedUpdate(f: Void->Void) {
traitFixedUpdates.remove(f);
}
public static function notifyOnRender(f: kha.graphics4.Graphics->Void) { public static function notifyOnRender(f: kha.graphics4.Graphics->Void) {
traitRenders.push(f); traitRenders.push(f);
} }

View File

@ -18,10 +18,44 @@ import iron.object.LightObject;
import iron.object.MeshObject; import iron.object.MeshObject;
import iron.object.Uniforms; import iron.object.Uniforms;
import iron.object.Clipmap; import iron.object.Clipmap;
#if lnx_vr
import iron.math.Vec4;
import iron.math.Mat4;
import iron.math.Quat;
#end
class RenderPath { class RenderPath {
public static var active: RenderPath; public static var active: RenderPath;
#if lnx_vr
static var vrSimulateMode: Bool = false;
static var vrCameraOffsetSet:Bool = false;
static var vrCameraOffset:Vec4 = new Vec4();
static var wasVRPresenting:Bool = false;
public static var vrCalibrationPosition:Vec4 = null;
public static var vrCalibrationRotation:iron.math.Quat = null;
public static var vrCalibrationSaved:Bool = false;
public static var vrCenterCameraWorld:Mat4 = null;
static var vrOriginalSuperSample:Float = -1.0;
public static inline function isVRPresenting(): Bool {
#if (kha_webgl && lnx_vr)
return kha.vr.VrInterface.instance != null && kha.vr.VrInterface.instance.IsPresenting();
#else
return false;
#end
}
public static inline function isVRSimulateMode(): Bool {
return vrSimulateMode;
}
// TODO: done remove safely
public static inline function debugLog(msg: String, once: Bool = true): Void {
return;
}
#end
public var frameScissor = false; public var frameScissor = false;
public var frameScissorX = 0; public var frameScissorX = 0;
@ -43,9 +77,15 @@ class RenderPath {
public var isProbe = false; public var isProbe = false;
public var currentG: Graphics = null; public var currentG: Graphics = null;
public var frameG: Graphics; public var frameG: Graphics;
#if lnx_vr
var beginCalled = false;
var scissorSet = false;
var viewportScaled = false;
var renderToXRFramebuffer = false;
#end
public var drawOrder = DrawOrder.Distance; public var drawOrder = DrawOrder.Distance;
public var paused = false; public var paused = false;
public var ready(get, null): Bool; public var ready(get, never): Bool;
function get_ready(): Bool { return loading == 0; } function get_ready(): Bool { return loading == 0; }
public var commands: Void->Void = null; public var commands: Void->Void = null;
public var setupDepthTexture: Void->Void = null; public var setupDepthTexture: Void->Void = null;
@ -123,9 +163,93 @@ class RenderPath {
public function renderFrame(g: Graphics) { public function renderFrame(g: Graphics) {
if (!ready || paused || iron.App.w() == 0 || iron.App.h() == 0) return; if (!ready || paused || iron.App.w() == 0 || iron.App.h() == 0) return;
if (lastW > 0 && (lastW != iron.App.w() || lastH != iron.App.h())) resize(); var appW = iron.App.w();
lastW = iron.App.w(); var appH = iron.App.h();
lastH = iron.App.h();
// use native XR framebuffer dimensions
#if (kha_webgl && lnx_vr)
if (kha.vr.VrInterface.instance != null) {
var vr = kha.vr.VrInterface.instance;
var isPresenting = vr != null && vr.IsPresenting();
// save/restore camera position between modes
if (!wasVRPresenting && isPresenting) {
if (Scene.active != null && Scene.active.camera != null) {
if (vrCalibrationPosition == null) vrCalibrationPosition = new Vec4();
if (vrCalibrationRotation == null) vrCalibrationRotation = new Quat();
vrCalibrationPosition.setFrom(Scene.active.camera.transform.loc);
vrCalibrationRotation.setFrom(Scene.active.camera.transform.rot);
vrCalibrationSaved = true;
}
// save original super sampling for later
vrOriginalSuperSample = leenkx.renderpath.Inc.superSample;
// compositeToXR function handles blitting to VR framebuffer
var xrVr: kha.js.vr.VrInterface = cast vr;
if (xrVr.xrGLLayer != null) {
var vrWidth = untyped xrVr.xrGLLayer.framebufferWidth;
var vrHeight = untyped xrVr.xrGLLayer.framebufferHeight;
}
}
else if (wasVRPresenting && !isPresenting) {
// reset VR frame time before anything else
#if (kha_webgl && lnx_vr)
iron.system.Time.vrFrameTime = -1.0;
#end
if (vrCalibrationSaved && Scene.active != null && Scene.active.camera != null) {
Scene.active.camera.transform.loc.setFrom(vrCalibrationPosition);
Scene.active.camera.transform.rot.setFrom(vrCalibrationRotation);
Scene.active.camera.buildMatrix();
Scene.active.camera.buildProjection();
}
// restore original super sampling from simulate mode
if (vrOriginalSuperSample >= 0.0) {
leenkx.renderpath.Inc.superSample = vrOriginalSuperSample;
for (rt in renderTargets) {
if (rt.raw.width == 0 && rt.raw.scale != null) {
rt.raw.scale = vrOriginalSuperSample;
}
}
resize();
vrOriginalSuperSample = -1.0;
}
// reset offset for next session
vrCameraOffsetSet = false;
vrCameraOffset = null;
}
wasVRPresenting = isPresenting;
if (isPresenting) {
// TODO: re-investigate using super sampling to avoid pixelation in simulate mode while giving max quality in headset
if (vrOriginalSuperSample >= 0.0 && leenkx.renderpath.Inc.superSample != 4.0) {
leenkx.renderpath.Inc.superSample = 4.0;
for (rt in renderTargets) {
if (rt.raw.width == 0 && rt.raw.scale != null) {
rt.raw.scale = 4.0;
}
}
resize();
}
var xrVr: kha.js.vr.VrInterface = cast vr;
if (xrVr.xrGLLayer != null) {
appW = xrVr.xrGLLayer.framebufferWidth;
appH = xrVr.xrGLLayer.framebufferHeight;
}
}
}
#end
if (lastW > 0 && (lastW != appW || lastH != appH)) resize();
lastW = appW;
lastH = appH;
frameTime = Time.time() - lastFrameTime; frameTime = Time.time() - lastFrameTime;
lastFrameTime = Time.time(); lastFrameTime = Time.time();
@ -191,7 +315,9 @@ class RenderPath {
} }
light = Scene.active.lights[0]; light = Scene.active.lights[0];
commands(); if (commands != null) {
commands();
}
if (!isProbe) frame++; if (!isProbe) frame++;
} }
@ -207,13 +333,13 @@ class RenderPath {
begin(frameG, Scene.active.camera.currentFace); begin(frameG, Scene.active.camera.currentFace);
} }
else { // Screen, planar probe else { // Screen, planar probe
currentW = iron.App.w(); currentW = kha.System.windowWidth();
currentH = iron.App.h(); currentH = kha.System.windowHeight();
if (frameScissor) setFrameScissor(); if (frameScissor) setFrameScissor();
begin(frameG); begin(frameG);
if (!isProbe) { if (!isProbe) {
setCurrentViewport(iron.App.w(), iron.App.h()); setCurrentViewport(kha.System.windowWidth(), kha.System.windowHeight());
setCurrentScissor(iron.App.w(), iron.App.h()); setCurrentScissor(kha.System.windowWidth(), kha.System.windowHeight());
} }
} }
} }
@ -258,16 +384,42 @@ class RenderPath {
if (currentG != null) end(); if (currentG != null) end();
currentG = g; currentG = g;
additionalTargets = additionalRenderTargets; additionalTargets = additionalRenderTargets;
face >= 0 ? g.beginFace(face) : g.begin(additionalRenderTargets);
// we still bind but skip begin() when explicitly rendering to XR framebuffer (renderToXRFramebuffer flag)
#if lnx_vr
if (!renderToXRFramebuffer) {
face >= 0 ? g.beginFace(face) : g.begin(additionalRenderTargets);
beginCalled = true;
} else {
// XR framebuffer is already bound by VrInterface so we dont rebind
beginCalled = false;
}
#else
face >= 0 ? g.beginFace(face) : g.begin(additionalRenderTargets);
#end
} }
inline function end() { inline function end() {
if (currentG == null) return;
if (scissorSet) { if (scissorSet) {
currentG.disableScissor(); currentG.disableScissor();
scissorSet = false; scissorSet = false;
} }
#if lnx_vr
if (beginCalled) {
currentG.end();
beginCalled = false;
}
// persist for rendering both eyes
if (!isVRPresenting()) {
currentG = null;
additionalTargets = null;
}
#else
currentG.end(); currentG.end();
currentG = null; currentG = null;
#end
bindParams = null; bindParams = null;
} }
@ -331,14 +483,17 @@ class RenderPath {
}); });
} }
public static function sortMeshesShader(meshes: Array<MeshObject>) { public static function sortMeshesIndex(meshes: Array<MeshObject>) {
meshes.sort(function(a, b): Int { meshes.sort(function(a, b): Int {
#if rp_depth_texture #if rp_depth_texture
var depthDiff = boolToInt(a.depthRead) - boolToInt(b.depthRead); var depthDiff = boolToInt(a.depthRead) - boolToInt(b.depthRead);
if (depthDiff != 0) return depthDiff; if (depthDiff != 0) return depthDiff;
#end #end
return a.materials[0].name >= b.materials[0].name ? 1 : -1; if (a.data.sortingIndex != b.data.sortingIndex) {
return a.data.sortingIndex > b.data.sortingIndex ? 1 : -1;
}
return a.data.name >= b.data.name ? 1 : -1;
}); });
} }
@ -399,7 +554,7 @@ class RenderPath {
#if lnx_batch #if lnx_batch
sortMeshesDistance(Scene.active.meshBatch.nonBatched); sortMeshesDistance(Scene.active.meshBatch.nonBatched);
#else #else
drawOrder == DrawOrder.Shader ? sortMeshesShader(meshes) : sortMeshesDistance(meshes); drawOrder == DrawOrder.Index ? sortMeshesIndex(meshes) : sortMeshesDistance(meshes);
#end #end
meshesSorted = true; meshesSorted = true;
} }
@ -518,12 +673,208 @@ class RenderPath {
return Reflect.field(kha.Shaders, handle + "_comp"); return Reflect.field(kha.Shaders, handle + "_comp");
} }
#if (kha_krom && lnx_vr) #if lnx_vr
public function drawStereo(drawMeshes: Int->Void) { // blits to each eyes viewport in the XR framebuffer.
for (eye in 0...2) { public function compositeToXR(sourceTarget: String) {
Krom.vrBeginRender(eye); #if (kha_webgl && lnx_vr)
drawMeshes(eye);
Krom.vrEndRender(eye); var vr: kha.js.vr.VrInterface = cast kha.vr.VrInterface.instance;
if (vr == null || vr._glContext == null || vr.xrGLLayer == null) {
return;
}
var gl: js.html.webgl.WebGL2RenderingContext = cast vr._glContext;
var source = renderTargets.get(sourceTarget);
if (source == null) {
return;
}
var sourceFB: js.html.webgl.Framebuffer = untyped source.image.g4.renderTargetFrameBuffer;
if (sourceFB == null) {
return;
}
// trace('Framebuffer OK');
renderToXRFramebuffer = true;
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.DRAW_FRAMEBUFFER, vr.xrGLLayer.framebuffer);
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.READ_FRAMEBUFFER, sourceFB);
var readStatus = gl.checkFramebufferStatus(js.html.webgl.WebGL2RenderingContext.READ_FRAMEBUFFER);
var drawStatus = gl.checkFramebufferStatus(js.html.webgl.WebGL2RenderingContext.DRAW_FRAMEBUFFER);
if (readStatus != js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER_COMPLETE ||
drawStatus != js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER_COMPLETE) {
return;
}
var halfWidth = Std.int(source.image.width / 2);
var fullHeight = source.image.height;
if (vr._leftViewport != null) {
var vp = vr._leftViewport;
gl.blitFramebuffer(
0, 0, halfWidth, fullHeight,
vp.x, vp.y, vp.x + vp.width, vp.y + vp.height,
js.html.webgl.WebGL2RenderingContext.COLOR_BUFFER_BIT,
js.html.webgl.WebGL2RenderingContext.LINEAR
);
}
if (vr._rightViewport != null) {
var vp = vr._rightViewport;
gl.blitFramebuffer(
halfWidth, 0, source.image.width, fullHeight,
vp.x, vp.y, vp.x + vp.width, vp.y + vp.height,
js.html.webgl.WebGL2RenderingContext.COLOR_BUFFER_BIT,
js.html.webgl.WebGL2RenderingContext.LINEAR
);
}
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER, null);
renderToXRFramebuffer = false;
#end
}
#end
#if lnx_vr
public function drawStereo(drawMeshes: Void->Void) {
vrSimulateMode = false;
if (currentG == null && frameG != null) {
currentG = frameG;
}
var appw = iron.App.w();
var apph = iron.App.h();
var g = currentG;
// get render target dimensions not App.w/h gbuffer is scaled in simulate mode with supersampling
var gbuffer0 = renderTargets.get("gbuffer0");
var actualWidth = (gbuffer0 != null && gbuffer0.image != null) ? gbuffer0.image.width : appw;
var actualHeight = (gbuffer0 != null && gbuffer0.image != null) ? gbuffer0.image.height : apph;
var actualHalfWidth = Std.int(actualWidth / 2);
var vrFBWidth = actualWidth;
var vrFBHeight = actualHeight;
var vrHalfWidth = actualHalfWidth;
var isVRPresenting = false;
vrSimulateMode = false;
var vr:Dynamic = null;
var vrExists = false;
#if (kha_webgl && lnx_vr)
if (kha.vr.VrInterface.instance != null) {
vr = kha.vr.VrInterface.instance;
vrExists = true;
}
#end
if (vrExists && vr != null && vr.IsPresenting()) {
vrSimulateMode = false;
isVRPresenting = true;
// get framebuffer dimensions from XR layer
#if (kha_webgl && lnx_vr)
var xrVr: kha.js.vr.VrInterface = cast vr;
if (xrVr.xrGLLayer != null) {
vrFBWidth = untyped xrVr.xrGLLayer.framebufferWidth;
vrFBHeight = untyped xrVr.xrGLLayer.framebufferHeight;
vrHalfWidth = Std.int(vrFBWidth / 2);
}
#end
if (Scene.active == null || Scene.active.camera == null) {
return;
}
#if (kha_webgl && lnx_vr)
if (vrCenterCameraWorld == null) vrCenterCameraWorld = Mat4.identity();
vrCenterCameraWorld.setFrom(Scene.active.camera.transform.world);
#end
// LEFT EYE
// HMD center for room scale position tracking
#if (kha_webgl && lnx_vr)
var xrVr: kha.js.vr.VrInterface = cast vr;
if (xrVr.currentViewerPose != null) {
var viewerTransform = untyped xrVr.currentViewerPose.transform;
if (viewerTransform != null && viewerTransform.position != null) {
// VR present calibration is used to position objects in world space not the camera
var pos = viewerTransform.position;
// camera follows headset directly in local floor space
Scene.active.camera.transform.loc.set(pos.x, pos.y, pos.z);
if (viewerTransform.orientation != null) {
Scene.active.camera.transform.rot.set(
viewerTransform.orientation.x,
viewerTransform.orientation.y,
viewerTransform.orientation.z,
viewerTransform.orientation.w
);
}
Scene.active.camera.transform.buildMatrix();
}
}
iron.system.VRController.updatePoses();
#end
Scene.active.camera.V.self = vr.GetViewMatrix(0);
Scene.active.camera.P.self = vr.GetProjectionMatrix(0);
Scene.active.camera.VP.setFrom(Scene.active.camera.P);
Scene.active.camera.VP.multmat(Scene.active.camera.V);
Scene.active.camera.buildMatrix(); // update frustum for culling
var renderWidth = actualWidth;
var renderHeight = actualHeight;
var renderHalfWidth = actualHalfWidth;
// left half of render target
g.viewport(0, 0, renderHalfWidth, renderHeight);
g.scissor(0, 0, renderHalfWidth, renderHeight);
drawMeshes();
// RIGHT EYE
Scene.active.camera.V.self = vr.GetViewMatrix(1);
Scene.active.camera.P.self = vr.GetProjectionMatrix(1);
Scene.active.camera.VP.setFrom(Scene.active.camera.P);
Scene.active.camera.VP.multmat(Scene.active.camera.V);
Scene.active.camera.buildMatrix();
// right half of render target
g.viewport(renderHalfWidth, 0, renderHalfWidth, renderHeight);
g.scissor(renderHalfWidth, 0, renderHalfWidth, renderHeight);
drawMeshes();
// restore for post-processing
g.disableScissor();
g.viewport(0, 0, renderWidth, renderHeight);
}
else { // Simulate
vrSimulateMode = true;
var ipd_offset = 0.032 * 35.0;
#if (kha_webgl && lnx_vr)
if (vrCenterCameraWorld == null) vrCenterCameraWorld = Mat4.identity();
vrCenterCameraWorld.setFrom(Scene.active.camera.transform.world);
#end
Scene.active.camera.buildProjection(actualHalfWidth / actualHeight);
Scene.active.camera.transform.move(Scene.active.camera.right(), -ipd_offset);
Scene.active.camera.buildMatrix();
g.viewport(0, 0, actualHalfWidth, actualHeight);
g.scissor(0, 0, actualHalfWidth, actualHeight);
drawMeshes();
begin(g, additionalTargets);
Scene.active.camera.transform.move(Scene.active.camera.right(), ipd_offset * 2.0);
Scene.active.camera.buildMatrix();
g.viewport(actualHalfWidth, 0, actualHalfWidth, actualHeight);
g.scissor(actualHalfWidth, 0, actualHalfWidth, actualHeight);
drawMeshes();
Scene.active.camera.transform.move(Scene.active.camera.right(), -ipd_offset);
Scene.active.camera.buildMatrix();
g.disableScissor();
g.viewport(0, 0, actualWidth, actualHeight);
} }
} }
#end #end
@ -882,6 +1233,6 @@ class CachedShaderContext {
@:enum abstract DrawOrder(Int) from Int { @:enum abstract DrawOrder(Int) from Int {
var Distance = 0; // Early-z var Distance = 0; // Early-z
var Shader = 1; // Less state changes var Index = 1; // Less state changes
// var Mix = 2; // Distance buckets sorted by shader // var Mix = 2; // Distance buckets sorted by shader
} }

View File

@ -775,6 +775,7 @@ class Scene {
// Attach particle systems // Attach particle systems
#if lnx_particles #if lnx_particles
if (o.particle_refs != null) { if (o.particle_refs != null) {
cast(object, MeshObject).render_emitter = o.render_emitter;
for (ref in o.particle_refs) cast(object, MeshObject).setupParticleSystem(sceneName, ref); for (ref in o.particle_refs) cast(object, MeshObject).setupParticleSystem(sceneName, ref);
} }
#end #end
@ -782,6 +783,11 @@ class Scene {
if (o.tilesheet_ref != null) { if (o.tilesheet_ref != null) {
cast(object, MeshObject).setupTilesheet(sceneName, o.tilesheet_ref, o.tilesheet_action_ref); cast(object, MeshObject).setupTilesheet(sceneName, o.tilesheet_ref, o.tilesheet_action_ref);
} }
if (o.camera_list != null){
cast(object, MeshObject).cameraList = o.camera_list;
}
returnObject(object, o, done); returnObject(object, o, done);
}); });
} }
@ -881,8 +887,12 @@ class Scene {
var ptype: String = t.props[i * 3 + 1]; var ptype: String = t.props[i * 3 + 1];
var pval: Dynamic = t.props[i * 3 + 2]; var pval: Dynamic = t.props[i * 3 + 2];
if (StringTools.endsWith(ptype, "Object") && pval != "") { if (StringTools.endsWith(ptype, "Object") && pval != "" && pval != null) {
Reflect.setProperty(traitInst, pname, Scene.active.getChild(pval)); Reflect.setProperty(traitInst, pname, Scene.active.getChild(pval));
} else if (ptype == "TSceneFormat" && pval != "") {
Data.getSceneRaw(pval, function (r: TSceneFormat) {
Reflect.setProperty(traitInst, pname, r);
});
} }
else { else {
switch (ptype) { switch (ptype) {
@ -944,7 +954,14 @@ class Scene {
static function createTraitClassInstance(traitName: String, args: Array<Dynamic>): Dynamic { static function createTraitClassInstance(traitName: String, args: Array<Dynamic>): Dynamic {
var cname = Type.resolveClass(traitName); var cname = Type.resolveClass(traitName);
if (cname == null) return null; if (cname == null) return null;
return Type.createInstance(cname, args); var trait:Dynamic;
try {
trait = Type.createInstance(cname, args);
} catch(e) {
trace("Error creating trait: " + traitName + " - " + e);
trait = null;
}
return trait;
} }
function loadEmbeddedData(datas: Array<String>, done: Void->Void) { function loadEmbeddedData(datas: Array<String>, done: Void->Void) {

View File

@ -16,6 +16,7 @@ class Trait {
var _remove: Array<Void->Void> = null; var _remove: Array<Void->Void> = null;
var _update: Array<Void->Void> = null; var _update: Array<Void->Void> = null;
var _lateUpdate: Array<Void->Void> = null; var _lateUpdate: Array<Void->Void> = null;
var _fixedUpdate: Array<Void->Void> = null;
var _render: Array<kha.graphics4.Graphics->Void> = null; var _render: Array<kha.graphics4.Graphics->Void> = null;
var _render2D: Array<kha.graphics2.Graphics->Void> = null; var _render2D: Array<kha.graphics2.Graphics->Void> = null;
@ -87,6 +88,23 @@ class Trait {
App.removeLateUpdate(f); App.removeLateUpdate(f);
} }
/**
Add fixed game logic handler.
**/
public function notifyOnFixedUpdate(f: Void->Void) {
if (_fixedUpdate == null) _fixedUpdate = [];
_fixedUpdate.push(f);
App.notifyOnFixedUpdate(f);
}
/**
Remove fixed game logic handler.
**/
public function removeFixedUpdate(f: Void->Void) {
_fixedUpdate.remove(f);
App.removeFixedUpdate(f);
}
/** /**
Add render handler. Add render handler.
**/ **/

View File

@ -37,7 +37,9 @@ class Armature {
} }
public function getAction(name: String): TAction { public function getAction(name: String): TAction {
for (a in actions) if (a.name == name) return a; for (a in actions) {
if (a.name == name) return a;
}
return null; return null;
} }

View File

@ -9,6 +9,7 @@ import iron.data.SceneFormat;
class MeshData { class MeshData {
public var name: String; public var name: String;
public var sortingIndex: Int;
public var raw: TMeshData; public var raw: TMeshData;
public var format: TSceneFormat; public var format: TSceneFormat;
public var geom: Geometry; public var geom: Geometry;
@ -23,7 +24,8 @@ class MeshData {
public function new(raw: TMeshData, done: MeshData->Void) { public function new(raw: TMeshData, done: MeshData->Void) {
this.raw = raw; this.raw = raw;
this.name = raw.name; this.name = raw.name;
this.sortingIndex = raw.sorting_index;
if (raw.scale_pos != null) scalePos = raw.scale_pos; if (raw.scale_pos != null) scalePos = raw.scale_pos;
if (raw.scale_tex != null) scaleTex = raw.scale_tex; if (raw.scale_tex != null) scaleTex = raw.scale_tex;

View File

@ -49,6 +49,7 @@ typedef TMeshData = {
@:structInit class TMeshData { @:structInit class TMeshData {
#end #end
public var name: String; public var name: String;
public var sorting_index: Int;
public var vertex_arrays: Array<TVertexArray>; public var vertex_arrays: Array<TVertexArray>;
public var index_arrays: Array<TIndexArray>; public var index_arrays: Array<TIndexArray>;
@:optional public var dynamic_usage: Null<Bool>; @:optional public var dynamic_usage: Null<Bool>;
@ -222,6 +223,7 @@ typedef TShaderData = {
@:structInit class TShaderData { @:structInit class TShaderData {
#end #end
public var name: String; public var name: String;
public var next_pass: String;
public var contexts: Array<TShaderContext>; public var contexts: Array<TShaderContext>;
} }
@ -392,6 +394,9 @@ typedef TParticleData = {
#end #end
public var name: String; public var name: String;
public var type: Int; // 0 - Emitter, Hair public var type: Int; // 0 - Emitter, Hair
public var auto_start: Bool;
public var dynamic_emitter: Bool;
public var is_unique: Bool;
public var loop: Bool; public var loop: Bool;
public var count: Int; public var count: Int;
public var frame_start: FastFloat; public var frame_start: FastFloat;
@ -439,6 +444,7 @@ typedef TObj = {
@:optional public var traits: Array<TTrait>; @:optional public var traits: Array<TTrait>;
@:optional public var properties: Array<TProperty>; @:optional public var properties: Array<TProperty>;
@:optional public var vertex_groups: Array<TVertex_groups>; @:optional public var vertex_groups: Array<TVertex_groups>;
@:optional public var camera_list: Array<String>;
@:optional public var constraints: Array<TConstraint>; @:optional public var constraints: Array<TConstraint>;
@:optional public var dimensions: Float32Array; // Geometry objects @:optional public var dimensions: Float32Array; // Geometry objects
@:optional public var object_actions: Array<String>; @:optional public var object_actions: Array<String>;

View File

@ -22,6 +22,7 @@ using StringTools;
class ShaderData { class ShaderData {
public var name: String; public var name: String;
public var nextPass: String;
public var raw: TShaderData; public var raw: TShaderData;
public var contexts: Array<ShaderContext> = []; public var contexts: Array<ShaderContext> = [];
@ -33,6 +34,7 @@ class ShaderData {
public function new(raw: TShaderData, done: ShaderData->Void, overrideContext: TShaderOverride = null) { public function new(raw: TShaderData, done: ShaderData->Void, overrideContext: TShaderOverride = null) {
this.raw = raw; this.raw = raw;
this.name = raw.name; this.name = raw.name;
this.nextPass = raw.next_pass;
for (c in raw.contexts) contexts.push(null); for (c in raw.contexts) contexts.push(null);
var contextsLoaded = 0; var contextsLoaded = 0;

View File

@ -0,0 +1,50 @@
/*
* format - Haxe File Formats
*
* BMP File Format
* Copyright (C) 2007-2009 Trevor McCauley, Baluta Cristian (hx port) & Robert Sköld (format conversion)
*
* Copyright (c) 2009, The Haxe Project Contributors
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package iron.format.bmp;
typedef Data = {
var header : iron.format.bmp.Header;
var pixels : haxe.io.Bytes;
#if (haxe_ver < 4)
var colorTable : Null<haxe.io.Bytes>;
#else
var ?colorTable : haxe.io.Bytes;
#end
}
typedef Header = {
var width : Int; // real width (in pixels)
var height : Int; // real height (in pixels)
var paddedStride : Int; // number of bytes in a stride (including padding)
var topToBottom : Bool; // whether the bitmap is stored top to bottom
var bpp : Int; // bits per pixel
var dataLength : Int; // equal to `paddedStride` * `height`
var compression : Int; // which compression is being used, 0 for no compression
}

View File

@ -0,0 +1,122 @@
/*
* format - Haxe File Formats
*
* BMP File Format
* Copyright (C) 2007-2009 Robert Sköld
*
* Copyright (c) 2009, The Haxe Project Contributors
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package iron.format.bmp;
import iron.format.bmp.Data;
class Reader {
var input : haxe.io.Input;
public function new( i ) {
input = i;
}
/**
* Only supports uncompressed 24bpp bitmaps (the most common format).
*
* The returned bytes in `Data.pixels` will be in BGR order, and with padding (if present).
*
* @see https://msdn.microsoft.com/en-us/library/windows/desktop/dd318229(v=vs.85).aspx
* @see https://en.wikipedia.org/wiki/BMP_file_format#Bitmap_file_header
*/
public function read() : format.bmp.Data {
// Read Header
for (b in ["B".code, "M".code]) {
if (input.readByte() != b) throw "Invalid header";
}
var fileSize = input.readInt32();
input.readInt32(); // Reserved
var offset = input.readInt32();
// Read InfoHeader
var infoHeaderSize = input.readInt32(); // InfoHeader size
if (infoHeaderSize != 40) {
throw 'Info headers with size $infoHeaderSize not supported.';
}
var width = input.readInt32(); // Image width (actual, not padded)
var height = input.readInt32(); // Image height
var numPlanes = input.readInt16(); // Number of planes
var bits = input.readInt16(); // Bits per pixel
var compression = input.readInt32(); // Compression type
var dataLength = input.readInt32(); // Image data size (includes padding!)
input.readInt32(); // Horizontal resolution
input.readInt32(); // Vertical resolution
var colorsUsed = input.readInt32(); // Colors used (0 when uncompressed)
input.readInt32(); // Important colors (0 when uncompressed)
// If there's no compression, the dataLength may be 0
if ( compression == 0 && dataLength == 0 ) dataLength = fileSize - offset;
var bytesRead = 54; // total read above
var colorTable : haxe.io.Bytes = null;
if ( bits <= 8 ) {
if ( colorsUsed == 0 ) {
colorsUsed = Tools.getNumColorsForBitDepth(bits);
}
var colorTableLength = 4 * colorsUsed;
colorTable = haxe.io.Bytes.alloc( colorTableLength );
input.readFullBytes( colorTable, 0, colorTableLength );
bytesRead += colorTableLength;
}
input.read( offset - bytesRead );
var p = haxe.io.Bytes.alloc( dataLength );
// Read Raster Data
var paddedStride = Tools.computePaddedStride(width, bits);
var topToBottom = false;
if ( height < 0 ) { // if bitmap is stored top to bottom
topToBottom = true;
height = -height;
}
input.readFullBytes(p, 0, dataLength);
return {
header: {
width: width,
height: height,
paddedStride: paddedStride,
topToBottom: topToBottom,
bpp: bits,
dataLength: dataLength,
compression: compression
},
pixels: p,
colorTable: colorTable
}
}
}

View File

@ -0,0 +1,256 @@
/*
* format - Haxe File Formats
*
* BMP File Format
* Copyright (C) 2007-2009 Trevor McCauley, Baluta Cristian (hx port) & Robert Sköld (format conversion)
*
* Copyright (c) 2009, The Haxe Project Contributors
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package iron.format.bmp;
class Tools {
// a r g b
static var ARGB_MAP(default, never):Array<Int> = [0, 1, 2, 3];
static var BGRA_MAP(default, never):Array<Int> = [3, 2, 1, 0];
static var COLOR_SIZE(default, never):Int = 4;
/**
Extract BMP pixel data (24bpp in BGR format) and expands it to BGRA, removing any padding in the process.
**/
inline static public function extractBGRA( bmp : iron.format.bmp.Data ) : haxe.io.Bytes {
return _extract32(bmp, BGRA_MAP, 0xFF);
}
/**
Extract BMP pixel data (24bpp in BGR format) and converts it to ARGB.
**/
inline static public function extractARGB( bmp : iron.format.bmp.Data ) : haxe.io.Bytes {
return _extract32(bmp, ARGB_MAP, 0xFF);
}
/**
Creates BMP data from bytes in BGRA format for each pixel.
**/
inline static public function buildFromBGRA( width : Int, height : Int, srcBytes : haxe.io.Bytes, topToBottom : Bool = false ) : Data {
return _buildFrom32(width, height, srcBytes, BGRA_MAP, topToBottom);
}
/**
Creates BMP data from bytes in ARGB format for each pixel.
**/
inline static public function buildFromARGB( width : Int, height : Int, srcBytes : haxe.io.Bytes, topToBottom : Bool = false ) : Data {
return _buildFrom32(width, height, srcBytes, ARGB_MAP, topToBottom);
}
inline static public function computePaddedStride(width:Int, bpp:Int):Int {
return ((((width * bpp) + 31) & ~31) >> 3);
}
/**
* Gets number of colors for indexed palettes
*/
inline static public function getNumColorsForBitDepth(bpp:Int):Int {
return switch (bpp) {
case 1: 2;
case 4: 16;
case 8: 256;
case 16: 65536;
default: throw 'Unsupported bpp $bpp';
}
}
// `channelMap` contains indices to map into ARGB (f.e. the mapping for ARGB is [0,1,2,3], while for BGRA is [3,2,1,0])
static function _extract32( bmp : iron.format.bmp.Data, channelMap : Array<Int>, alpha : Int = 0xFF) : haxe.io.Bytes {
var srcBytes = bmp.pixels;
var dstLen = bmp.header.width * bmp.header.height * 4;
var dstBytes = haxe.io.Bytes.alloc( dstLen );
var srcPaddedStride = bmp.header.paddedStride;
var yDir = -1;
var dstPos = 0;
var srcPos = srcPaddedStride * (bmp.header.height - 1);
if ( bmp.header.topToBottom ) {
yDir = 1;
srcPos = 0;
}
if ( bmp.header.bpp < 8 || bmp.header.bpp == 16 ) {
throw 'bpp ${bmp.header.bpp} not supported';
}
var colorTable:haxe.io.Bytes = null;
if ( bmp.header.bpp <= 8 ) {
var colorTableLength = getNumColorsForBitDepth(bmp.header.bpp);
colorTable = haxe.io.Bytes.alloc(colorTableLength * COLOR_SIZE);
var definedColorTableLength = Std.int( bmp.colorTable.length / COLOR_SIZE );
for( i in 0...definedColorTableLength ) {
var b = bmp.colorTable.get( i * COLOR_SIZE);
var g = bmp.colorTable.get( i * COLOR_SIZE + 1);
var r = bmp.colorTable.get( i * COLOR_SIZE + 2);
colorTable.set(i * COLOR_SIZE + channelMap[0], alpha);
colorTable.set(i * COLOR_SIZE + channelMap[1], r);
colorTable.set(i * COLOR_SIZE + channelMap[2], g);
colorTable.set(i * COLOR_SIZE + channelMap[3], b);
}
// We want to have the table the full length in case indices outside the range are present
colorTable.fill(definedColorTableLength, colorTableLength - definedColorTableLength, 0);
for( i in definedColorTableLength...colorTableLength ) {
colorTable.set(i * COLOR_SIZE + channelMap[0], alpha);
}
}
switch bmp.header.compression {
case 0:
while( dstPos < dstLen ) {
for( i in 0...bmp.header.width ) {
if (bmp.header.bpp == 8) {
var currentSrcPos = srcPos + i;
var index = srcBytes.get(currentSrcPos);
dstBytes.blit( dstPos, colorTable, index * COLOR_SIZE, COLOR_SIZE );
} else if (bmp.header.bpp == 24) {
var currentSrcPos = srcPos + i * 3;
var b = srcBytes.get(currentSrcPos);
var g = srcBytes.get(currentSrcPos + 1);
var r = srcBytes.get(currentSrcPos + 2);
dstBytes.set(dstPos + channelMap[0], alpha);
dstBytes.set(dstPos + channelMap[1], r);
dstBytes.set(dstPos + channelMap[2], g);
dstBytes.set(dstPos + channelMap[3], b);
} else if (bmp.header.bpp == 32) {
var currentSrcPos = srcPos + i * 4;
var b = srcBytes.get(currentSrcPos);
var g = srcBytes.get(currentSrcPos + 1);
var r = srcBytes.get(currentSrcPos + 2);
dstBytes.set(dstPos + channelMap[0], alpha);
dstBytes.set(dstPos + channelMap[1], r);
dstBytes.set(dstPos + channelMap[2], g);
dstBytes.set(dstPos + channelMap[3], b);
}
dstPos += 4;
}
srcPos += yDir * srcPaddedStride;
}
case 1:
srcPos = 0;
var x = 0;
var y = bmp.header.topToBottom ? 0 : bmp.header.height - 1;
while( srcPos < bmp.header.dataLength ) {
var count = srcBytes.get(srcPos++);
var index = srcBytes.get(srcPos++);
if ( count == 0 ) {
if ( index == 0 ) {
x = 0;
y += yDir;
} else if ( index == 1 ) {
break;
} else if ( index == 2 ) {
x += srcBytes.get(srcPos++);
y += srcBytes.get(srcPos++);
} else {
count = index;
for( i in 0...count ) {
index = srcBytes.get(srcPos++);
dstBytes.blit( COLOR_SIZE * ((x+i) + y * bmp.header.width), colorTable, index * COLOR_SIZE, COLOR_SIZE );
}
if (srcPos % 2 != 0) srcPos++;
x += count;
}
} else {
for( i in 0...count ) {
dstBytes.blit( COLOR_SIZE * ((x+i) + y * bmp.header.width), colorTable, index * COLOR_SIZE, COLOR_SIZE );
}
x += count;
}
}
default:
throw 'compression ${bmp.header.compression} not supported';
}
return dstBytes;
}
// `channelMap` contains indices to map into ARGB (f.e. the mapping for ARGB is [0,1,2,3], while for BGRA is [3,2,1,0])
static function _buildFrom32( width : Int, height : Int, srcBytes : haxe.io.Bytes, channelMap : Array<Int>, topToBottom : Bool = false ) : Data {
var bpp = 24;
var paddedStride = computePaddedStride(width, bpp);
var bytesBGR = haxe.io.Bytes.alloc(paddedStride * height);
var topToBottom = topToBottom;
var dataLength = bytesBGR.length;
var dstStride = width * 3;
var srcLen = width * height * 4;
var yDir = -1;
var dstPos = dataLength - paddedStride;
var srcPos = 0;
if ( topToBottom ) {
yDir = 1;
dstPos = 0;
}
while( srcPos < srcLen ) {
var i = dstPos;
while( i < dstPos + dstStride ) {
var r = srcBytes.get(srcPos + channelMap[1]);
var g = srcBytes.get(srcPos + channelMap[2]);
var b = srcBytes.get(srcPos + channelMap[3]);
bytesBGR.set(i++, b);
bytesBGR.set(i++, g);
bytesBGR.set(i++, r);
srcPos += 4;
}
dstPos += yDir * paddedStride;
}
return {
header: {
width: width,
height: height,
paddedStride: paddedStride,
topToBottom: topToBottom,
bpp: bpp,
dataLength: dataLength,
compression: 0
},
pixels: bytesBGR,
colorTable: null
}
}
}

View File

@ -0,0 +1,74 @@
/*
* format - Haxe File Formats
*
* BMP File Format
* Copyright (C) 2007-2009 Robert Sköld
*
* Copyright (c) 2009, The Haxe Project Contributors
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package iron.format.bmp;
import iron.format.bmp.Data;
class Writer {
static var DATA_OFFSET : Int = 0x36;
var output : haxe.io.Output;
public function new(o) {
output = o;
}
/**
* Specs: http://s223767089.online.de/en/file-format-bmp
*/
public function write( bmp : Data ) {
// Write Header (14 bytes)
output.writeString( "BM" ); // Signature
output.writeInt32(bmp.pixels.length + DATA_OFFSET ); // FileSize
output.writeInt32( 0 ); // Reserved
output.writeInt32( DATA_OFFSET ); // Offset
// Write InfoHeader (40 bytes)
output.writeInt32( 40 ); // InfoHeader size
output.writeInt32( bmp.header.width ); // Image width
var height = bmp.header.height;
if (bmp.header.topToBottom) height = -height;
output.writeInt32( height ); // Image height
output.writeInt16( 1 ); // Number of planes
output.writeInt16( 24 ); // Bits per pixel (24bit RGB)
output.writeInt32( 0 ); // Compression type (no compression)
output.writeInt32( bmp.header.dataLength ); // Image data size (0 when uncompressed)
output.writeInt32( 0x2e30 ); // Horizontal resolution
output.writeInt32( 0x2e30 ); // Vertical resolution
output.writeInt32( 0 ); // Colors used (0 when uncompressed)
output.writeInt32( 0 ); // Important colors (0 when uncompressed)
// Write Raster Data
output.write(bmp.pixels);
}
}

View File

@ -141,6 +141,7 @@ class Animation {
sampler.cacheSet = false; sampler.cacheSet = false;
sampler.trackEnd = false; sampler.trackEnd = false;
if (anim == null || anim.tracks == null || anim.tracks.length == 0) return;
var track = anim.tracks[0]; var track = anim.tracks[0];
if (frameIndex == -1) { if (frameIndex == -1) {
@ -159,9 +160,17 @@ class Animation {
if(markerEvents.get(sampler) != null){ if(markerEvents.get(sampler) != null){
for (i in 0...anim.marker_frames.length) { for (i in 0...anim.marker_frames.length) {
if (frameIndex == anim.marker_frames[i]) { if (frameIndex == anim.marker_frames[i]) {
var marketAct = markerEvents.get(sampler); var markerAct = markerEvents.get(sampler);
var ar = marketAct.get(anim.marker_names[i]); var ar = markerAct.get(anim.marker_names[i]);
if (ar != null) for (f in ar) f(); if (ar != null) for (f in ar) f();
} else {
for (j in 0...(frameIndex - lastFrameIndex)) {
if (lastFrameIndex + j + 1 == anim.marker_frames[i]) {
var markerAct = markerEvents.get(sampler);
var ar = markerAct.get(anim.marker_names[i]);
if (ar != null) for (f in ar) f();
}
}
} }
} }
lastFrameIndex = frameIndex; lastFrameIndex = frameIndex;
@ -434,7 +443,12 @@ class ActionSampler {
*/ */
public inline function setObjectAction(actionData: TObj) { public inline function setObjectAction(actionData: TObj) {
this.actionData = [actionData]; this.actionData = [actionData];
this.totalFrames = actionData.anim.tracks[0].frames.length; if (actionData != null && actionData.anim != null && actionData.anim.tracks != null && actionData.anim.tracks.length > 0) {
this.totalFrames = actionData.anim.tracks[0].frames.length;
}
else {
this.totalFrames = 0;
}
actionDataInit = true; actionDataInit = true;
} }

View File

@ -108,9 +108,11 @@ class BoneAnimation extends Animation {
object.transform.rot.set(0, 0, 0, 1); object.transform.rot.set(0, 0, 0, 1);
object.transform.buildMatrix(); object.transform.buildMatrix();
var refs = mo.parent.raw.bone_actions; if (mo.parent != null && mo.parent.raw != null && mo.parent.raw.bone_actions != null) {
if (refs != null && refs.length > 0) { var refs = mo.parent.raw.bone_actions;
Data.getSceneRaw(refs[0], function(action: TSceneFormat) { play(action.name); }); if (refs.length > 0) {
Data.getSceneRaw(refs[0], function(action: TSceneFormat) { play(action.name); });
}
} }
} }
if (armatureObject.raw.relative_bone_constraints) relativeBoneConstraints = true; if (armatureObject.raw.relative_bone_constraints) relativeBoneConstraints = true;
@ -183,8 +185,10 @@ class BoneAnimation extends Animation {
} }
function setAction(action: String) { function setAction(action: String) {
if (armature == null) return;
armature.initMats(); armature.initMats();
var a = armature.getAction(action); var a = armature.getAction(action);
if (a == null) return;
skeletonBones = a.bones; skeletonBones = a.bones;
skeletonMats = a.mats; skeletonMats = a.mats;
if(! rootMotionCacheInit) skeletonMats.push(Mat4.identity()); if(! rootMotionCacheInit) skeletonMats.push(Mat4.identity());
@ -193,8 +197,11 @@ class BoneAnimation extends Animation {
} }
function getAction(action: String): Array<TObj> { function getAction(action: String): Array<TObj> {
if (armature == null) return null;
armature.initMats(); armature.initMats();
return armature.getAction(action).bones; var a = armature.getAction(action);
if (a == null) return null;
return a.bones;
} }
function multParent(i: Int, fasts: Array<Mat4>, bones: Array<TObj>, mats: Array<Mat4>) { function multParent(i: Int, fasts: Array<Mat4>, bones: Array<TObj>, mats: Array<Mat4>) {
@ -225,9 +232,9 @@ class BoneAnimation extends Animation {
} }
override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.2, speed = 1.0, loop = true) { override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.2, speed = 1.0, loop = true) {
super.play(action, onComplete, blendTime, speed, loop);
if (action != "") { if (action != "") {
setAction(action); setAction(action);
super.play(action, onComplete, blendTime, speed, loop);
var tempAnimParam = new ActionSampler(action); var tempAnimParam = new ActionSampler(action);
registerAction("tempAction", tempAnimParam); registerAction("tempAction", tempAnimParam);
updateAnimation = function(mats){ updateAnimation = function(mats){
@ -239,6 +246,10 @@ class BoneAnimation extends Animation {
override public function update(delta: FastFloat) { override public function update(delta: FastFloat) {
this.delta = delta; this.delta = delta;
if (!isSkinned && skeletonBones == null) setAction(armature.actions[0].name); if (!isSkinned && skeletonBones == null) setAction(armature.actions[0].name);
// TODO: double check skip culling for skinned meshes if they need animation updates for bounds
// if (object != null && !object.visible) return;
if (object != null && (!object.visible || object.culled)) return; if (object != null && (!object.visible || object.culled)) return;
if (skeletonBones == null || skeletonBones.length == 0) return; if (skeletonBones == null || skeletonBones.length == 0) return;
@ -248,7 +259,6 @@ class BoneAnimation extends Animation {
super.update(delta); super.update(delta);
if(updateAnimation != null) { if(updateAnimation != null) {
updateAnimation(skeletonMats); updateAnimation(skeletonMats);
} }
@ -401,6 +411,7 @@ class BoneAnimation extends Animation {
} }
var bones = sampler.getBoneAction(); var bones = sampler.getBoneAction();
if (bones == null) return;
for(b in bones){ for(b in bones){
if (b.anim != null) { if (b.anim != null) {
updateTrack(b.anim, sampler); updateTrack(b.anim, sampler);
@ -410,13 +421,14 @@ class BoneAnimation extends Animation {
} }
public function sampleAction(sampler: ActionSampler, actionMats: Array<Mat4>) { public function sampleAction(sampler: ActionSampler, actionMats: Array<Mat4>) {
if(! sampler.actionDataInit) { if(! sampler.actionDataInit) {
var bones = getAction(sampler.action); var bones = getAction(sampler.action);
sampler.setBoneAction(bones); sampler.setBoneAction(bones);
} }
var bones = sampler.getBoneAction(); var bones = sampler.getBoneAction();
if (bones == null) return;
actionMats[skeletonBones.length].setIdentity(); actionMats[skeletonBones.length].setIdentity();
var rootMotionEnabled = sampler.rootMotionPos || sampler.rootMotionRot; var rootMotionEnabled = sampler.rootMotionPos || sampler.rootMotionRot;
for (i in 0...bones.length) { for (i in 0...bones.length) {
@ -427,7 +439,6 @@ class BoneAnimation extends Animation {
updateAnimSampled(bones[i].anim, actionMats[i], sampler); updateAnimSampled(bones[i].anim, actionMats[i], sampler);
} }
} }
} }
function updateAnimSampled(anim: TAnimation, mm: Mat4, sampler: ActionSampler) { function updateAnimSampled(anim: TAnimation, mm: Mat4, sampler: ActionSampler) {
@ -588,6 +599,9 @@ class BoneAnimation extends Animation {
public override function getTotalFrames(sampler: ActionSampler): Int { public override function getTotalFrames(sampler: ActionSampler): Int {
var bones = getAction(sampler.action); var bones = getAction(sampler.action);
if (bones == null){
return 0;
}
var track = bones[0].anim.tracks[0]; var track = bones[0].anim.tracks[0];
return Std.int(track.frames[track.frames.length - 1] - track.frames[0]); return Std.int(track.frames[track.frames.length - 1] - track.frames[0]);
} }
@ -1048,9 +1062,9 @@ class BoneAnimation extends Animation {
var rootLen = root.bone_length * rootMat.getScale().x; var rootLen = root.bone_length * rootMat.getScale().x;
// Get distance form root to goal // Get distance form root to goal
var goalLen = Math.abs(Vec4.distance(rootMat.getLoc(), goal)); var goalLen: FastFloat = Math.abs(Vec4.distance(rootMat.getLoc(), goal));
var totalLength = effectorLen + rootLen; var totalLength: FastFloat = effectorLen + rootLen;
// Get tip location of effector bone // Get tip location of effector bone
var effectorTipPos = new Vec4().setFrom(effectorMat.look()).normalize(); var effectorTipPos = new Vec4().setFrom(effectorMat.look()).normalize();
@ -1070,7 +1084,7 @@ class BoneAnimation extends Animation {
// Get unit vector of effector bone // Get unit vector of effector bone
var vectorEffector = new Vec4().setFrom(effectorMat.look()).normalize(); var vectorEffector = new Vec4().setFrom(effectorMat.look()).normalize();
// Get dot product of vectors // Get dot product of vectors
var dot = new Vec4().setFrom(vectorRootEffector).dot(vectorRoot); var dot = new Vec4().setFrom(vectorRootEffector).dot(vectorRoot);
// Calmp between -1 and 1 // Calmp between -1 and 1

View File

@ -30,12 +30,23 @@ class CameraObject extends Object {
static var sphereCenter = new Vec4(); static var sphereCenter = new Vec4();
static var vcenter = new Vec4(); static var vcenter = new Vec4();
static var vup = new Vec4(); static var vup = new Vec4();
#if lnx_vr
var helpMat = Mat4.identity();
public var leftV = Mat4.identity();
public var rightV = Mat4.identity();
#end
public function new(data: CameraData) { public function new(data: CameraData) {
super(); super();
this.data = data; this.data = data;
// dont just auto initialize VR button - headset trait controls VR
// #if lnx_vr
// iron.system.VR.initButton();
// #end
buildProjection(); buildProjection();
V = Mat4.identity(); V = Mat4.identity();
@ -75,7 +86,14 @@ class CameraObject extends Object {
projectionJitter(); projectionJitter();
#end #end
// matrices are set by VR system so avoid rebuilding transforms unless its in preview/not presenting
#if (kha_webgl && lnx_vr)
if (@:privateAccess !RenderPath.isVRPresenting()) {
buildMatrix();
}
#else
buildMatrix(); buildMatrix();
#end
RenderPath.active.renderFrame(g); RenderPath.active.renderFrame(g);
@ -117,6 +135,26 @@ class CameraObject extends Object {
V.getInverse(transform.world); V.getInverse(transform.world);
VP.multmats(P, V); VP.multmats(P, V);
#if lnx_vr
var vr = kha.vr.VrInterface.instance;
if (vr != null && vr.IsPresenting()) {
leftV.setFrom(V);
helpMat.self = vr.GetViewMatrix(0);
leftV.multmat(helpMat);
rightV.setFrom(V);
helpMat.self = vr.GetViewMatrix(1);
rightV.multmat(helpMat);
}
else {
leftV.setFrom(V);
}
VP.multmats(P, leftV);
#else
VP.multmats(P, V);
#end
if (data.raw.frustum_culling) { if (data.raw.frustum_culling) {
buildViewFrustum(VP, frustumPlanes); buildViewFrustum(VP, frustumPlanes);
} }

View File

@ -59,6 +59,9 @@ class LightObject extends Object {
public static var clustersData: kha.Image = null; public static var clustersData: kha.Image = null;
static var lpos = new Vec4(); static var lpos = new Vec4();
public static var LWVPMatrixArray: Float32Array = null; public static var LWVPMatrixArray: Float32Array = null;
#if lnx_vr
static var originalLightPositions: Float32Array = null;
#end
#end // lnx_clusters #end // lnx_clusters
public var V: Mat4 = Mat4.identity(); public var V: Mat4 = Mat4.identity();
@ -155,8 +158,13 @@ class LightObject extends Object {
} }
public function setCascade(camera: CameraObject, cascade: Int) { public function setCascade(camera: CameraObject, cascade: Int) {
m.setFrom(camera.V);
#if lnx_vr
m.setFrom(camera.leftV);
#else
m.setFrom(camera.V);
#end
#if lnx_csm #if lnx_csm
if (camSlicedP == null) { if (camSlicedP == null) {
camSlicedP = []; camSlicedP = [];
@ -514,7 +522,7 @@ class LightObject extends Object {
updateLightsArray(); // TODO: only update on light change updateLightsArray(); // TODO: only update on light change
} }
static function updateLightsArray() { public static function updateLightsArray() {
if (lightsArray == null) { // vec4x3 - 1: pos, a, color, b, 2: dir, c if (lightsArray == null) { // vec4x3 - 1: pos, a, color, b, 2: dir, c
lightsArray = new Float32Array(maxLights * 4 * 3); lightsArray = new Float32Array(maxLights * 4 * 3);
#if lnx_spot #if lnx_spot
@ -573,6 +581,49 @@ class LightObject extends Object {
} }
} }
// VR deferred stereo we save original light positions before adjusting for per-eye rendering
#if lnx_vr
public static function saveOriginalLightPositions() {
if (lightsArray == null) return;
if (originalLightPositions == null) {
originalLightPositions = new Float32Array(lightsArray.length);
}
for (i in 0...lightsArray.length) {
originalLightPositions[i] = lightsArray[i];
}
}
// negative for left eye, positive for right eye
public static function adjustLightPositionsForVREye(offsetX: Float, rightVec: Vec4) {
if (lightsArray == null) return;
var lights = Scene.active.lights;
var n = lights.length > maxLights ? maxLights : lights.length;
var i = 0;
for (l in lights) {
if (discardLightCulled(l)) continue;
if (i >= n) break;
lightsArray[i * 12 ] = originalLightPositions[i * 12 ] + rightVec.x * offsetX;
lightsArray[i * 12 + 1] = originalLightPositions[i * 12 + 1] + rightVec.y * offsetX;
lightsArray[i * 12 + 2] = originalLightPositions[i * 12 + 2] + rightVec.z * offsetX;
i++;
}
}
public static function restoreOriginalLightPositions() {
if (lightsArray == null || originalLightPositions == null) return;
for (i in 0...lightsArray.length) {
lightsArray[i] = originalLightPositions[i];
}
}
#end
public static function updateLWVPMatrixArray(object: Object, type: String) { public static function updateLWVPMatrixArray(object: Object, type: String) {
if (LWVPMatrixArray == null) { if (LWVPMatrixArray == null) {
LWVPMatrixArray = new Float32Array(maxLightsCluster * 16); LWVPMatrixArray = new Float32Array(maxLightsCluster * 16);
@ -624,8 +675,8 @@ class LightObject extends Object {
LWVPMatrixArray[i * 16 + 13] = m._31; LWVPMatrixArray[i * 16 + 13] = m._31;
LWVPMatrixArray[i * 16 + 14] = m._32; LWVPMatrixArray[i * 16 + 14] = m._32;
LWVPMatrixArray[i * 16 + 15] = m._33; LWVPMatrixArray[i * 16 + 15] = m._33;
i++; // only increment in light type
} }
i++;
} }
return LWVPMatrixArray; return LWVPMatrixArray;
} }

View File

@ -21,8 +21,10 @@ class MeshObject extends Object {
public var particleChildren: Array<MeshObject> = null; public var particleChildren: Array<MeshObject> = null;
public var particleOwner: MeshObject = null; // Particle object public var particleOwner: MeshObject = null; // Particle object
public var particleIndex = -1; public var particleIndex = -1;
public var render_emitter = true;
#end #end
public var cameraDistance: Float; public var cameraDistance: Float;
public var cameraList: Array<String> = null;
public var screenSize = 0.0; public var screenSize = 0.0;
public var frustumCulling = true; public var frustumCulling = true;
public var activeTilesheet: Tilesheet = null; public var activeTilesheet: Tilesheet = null;
@ -234,6 +236,8 @@ class MeshObject extends Object {
if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return; if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return;
var meshContext = raw != null ? context == "mesh" : false; var meshContext = raw != null ? context == "mesh" : false;
if (cameraList != null && cameraList.indexOf(Scene.active.camera.name) < 0) return;
#if lnx_particles #if lnx_particles
if (raw != null && raw.is_particle && particleOwner == null) return; // Instancing not yet set-up by particle system owner if (raw != null && raw.is_particle && particleOwner == null) return; // Instancing not yet set-up by particle system owner
if (particleSystems != null && meshContext) { if (particleSystems != null && meshContext) {
@ -244,6 +248,7 @@ class MeshObject extends Object {
Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) { Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
if (o != null) { if (o != null) {
var c: MeshObject = cast o; var c: MeshObject = cast o;
c.cameraList = this.cameraList;
particleChildren.push(c); particleChildren.push(c);
c.particleOwner = this; c.particleOwner = this;
c.particleIndex = particleChildren.length - 1; c.particleIndex = particleChildren.length - 1;
@ -255,11 +260,11 @@ class MeshObject extends Object {
particleSystems[i].update(particleChildren[i], this); particleSystems[i].update(particleChildren[i], this);
} }
} }
if (particleSystems != null && particleSystems.length > 0 && !raw.render_emitter) return; if (particleSystems != null && particleSystems.length > 0 && !render_emitter) return;
if (particleSystems == null && cullMaterial(context)) return;
#else
if (cullMaterial(context)) return;
#end #end
if (cullMaterial(context)) return;
// Get lod // Get lod
var mats = materials; var mats = materials;
var lod = this; var lod = this;
@ -297,6 +302,10 @@ class MeshObject extends Object {
// Render mesh // Render mesh
var ldata = lod.data; var ldata = lod.data;
// Next pass rendering first (inverse order)
renderNextPass(g, context, bindParams, lod);
for (i in 0...ldata.geom.indexBuffers.length) { for (i in 0...ldata.geom.indexBuffers.length) {
var mi = ldata.geom.materialIndices[i]; var mi = ldata.geom.materialIndices[i];
@ -400,4 +409,85 @@ class MeshObject extends Object {
} }
} }
} }
function renderNextPass(g: Graphics, context: String, bindParams: Array<String>, lod: MeshObject) {
var ldata = lod.data;
for (i in 0...ldata.geom.indexBuffers.length) {
var mi = ldata.geom.materialIndices[i];
if (mi >= materials.length) continue;
var currentMaterial: MaterialData = materials[mi];
if (currentMaterial == null || currentMaterial.shader == null) continue;
var nextPassName: String = currentMaterial.shader.nextPass;
if (nextPassName == null || nextPassName == "") continue;
var nextMaterial: MaterialData = null;
for (mat in materials) {
// First try exact match
if (mat.name == nextPassName) {
nextMaterial = mat;
break;
}
// If no exact match, try to match base name for linked materials
if (mat.name.indexOf("_") > 0 && mat.name.substr(mat.name.length - 6) == ".blend") {
var baseName = mat.name.substring(0, mat.name.indexOf("_"));
if (baseName == nextPassName) {
nextMaterial = mat;
break;
}
}
}
if (nextMaterial == null) continue;
var nextMaterialContext: MaterialContext = null;
var nextShaderContext: ShaderContext = null;
for (j in 0...nextMaterial.raw.contexts.length) {
if (nextMaterial.raw.contexts[j].name.substr(0, context.length) == context) {
nextMaterialContext = nextMaterial.contexts[j];
nextShaderContext = nextMaterial.shader.getContext(context);
break;
}
}
if (nextShaderContext == null) continue;
if (skipContext(context, nextMaterial)) continue;
var elems = nextShaderContext.raw.vertex_elements;
// Uniforms
if (nextShaderContext.pipeState != lastPipeline) {
g.setPipeline(nextShaderContext.pipeState);
lastPipeline = nextShaderContext.pipeState;
}
Uniforms.setContextConstants(g, nextShaderContext, bindParams);
Uniforms.setObjectConstants(g, nextShaderContext, this);
Uniforms.setMaterialConstants(g, nextShaderContext, nextMaterialContext);
// VB / IB
#if lnx_deinterleaved
g.setVertexBuffers(ldata.geom.get(elems));
#else
if (ldata.geom.instancedVB != null) {
g.setVertexBuffers([ldata.geom.get(elems), ldata.geom.instancedVB]);
}
else {
g.setVertexBuffer(ldata.geom.get(elems));
}
#end
g.setIndexBuffer(ldata.geom.indexBuffers[i]);
// Draw next pass for this specific geometry section
if (ldata.geom.instanced) {
g.drawIndexedVerticesInstanced(ldata.geom.instanceCount, ldata.geom.start, ldata.geom.count);
}
else {
g.drawIndexedVertices(ldata.geom.start, ldata.geom.count);
}
}
}
} }

View File

@ -20,6 +20,13 @@ class MorphTarget {
public var morphDataPos: Image; public var morphDataPos: Image;
public var morphDataNor: Image; public var morphDataNor: Image;
public var morphMap: Map<String, Int> = null; public var morphMap: Map<String, Int> = null;
public var isDirty: Bool = true;
var previousWeights: Float32Array;
var changeThreshold: FastFloat = 0.001; // skip smaller
var pendingUpdates: Map<Int, Float> = null;
var batchUpdateEnabled: Bool = true;
var lastFlushFrame: Int = 0;
public function new(data: TMorphTarget) { public function new(data: TMorphTarget) {
initWeights(data.morph_target_defaults); initWeights(data.morph_target_defaults);
@ -42,6 +49,14 @@ class MorphTarget {
morphMap.set(name, i); morphMap.set(name, i);
i++; i++;
} }
previousWeights = new Float32Array(morphWeights.length);
for (i in 0...morphWeights.length) {
previousWeights.set(i, morphWeights.get(i));
}
// batch system
pendingUpdates = new Map<Int, Float>();
} }
inline function initWeights(defaults: Float32Array) { inline function initWeights(defaults: Float32Array) {
@ -54,9 +69,96 @@ class MorphTarget {
public function setMorphValue(name: String, value: Float) { public function setMorphValue(name: String, value: Float) {
var i = morphMap.get(name); var i = morphMap.get(name);
if (i != null) { if (i != null) {
morphWeights.set(i, value); if (batchUpdateEnabled) {
pendingUpdates.set(i, value);
} else {
setMorphValueDirect(i, value);
}
} }
} }
// faster indexed access
public inline function setMorphValueDirect(index: Int, value: Float) {
var current = morphWeights.get(index);
// allow explicit zero values to reset
if (value == 0.0 && current != 0.0) {
morphWeights.set(index, value);
isDirty = true;
return;
}
var delta = value - current;
if (delta < -changeThreshold || delta > changeThreshold) {
morphWeights.set(index, value);
isDirty = true;
}
}
// flush pending batch
public function flushBatchedUpdates() {
if (pendingUpdates.keys().hasNext()) {
var anyChanged = false;
var hasZeros = false;
for (index in pendingUpdates.keys()) {
var value = pendingUpdates.get(index);
if (value == null) continue;
if (value == 0.0) hasZeros = true;
var current = morphWeights.get(index);
var delta = value - current;
if (value == 0.0 && current != 0.0) {
try{
morphWeights.set(index, cast value);
}catch(e){
trace("ERROR: " + e);
}
anyChanged = true;
}
else if (delta < -changeThreshold || delta > changeThreshold) {
morphWeights.set(index, cast value);
anyChanged = true;
}
}
pendingUpdates.clear();
if (anyChanged || hasZeros) {
isDirty = true;
}
}
}
public inline function markClean() {
isDirty = false;
for (i in 0...morphWeights.length) {
previousWeights.set(i, morphWeights.get(i));
}
}
public inline function markDirty() {
isDirty = true;
}
// toggle batch mode
public inline function setBatchMode(enabled: Bool) {
if (!enabled && batchUpdateEnabled) {
flushBatchedUpdates();
}
batchUpdateEnabled = enabled;
}
public function resetAllWeights() {
for (i in 0...morphWeights.length) {
morphWeights.set(i, 0.0);
}
pendingUpdates.clear();
isDirty = true;
}
} }
#end #end

View File

@ -172,6 +172,10 @@ class Object {
for (f in t._init) App.removeInit(f); for (f in t._init) App.removeInit(f);
t._init = null; t._init = null;
} }
if (t._fixedUpdate != null) {
for (f in t._fixedUpdate) App.removeFixedUpdate(f);
t._fixedUpdate = null;
}
if (t._update != null) { if (t._update != null) {
for (f in t._update) App.removeUpdate(f); for (f in t._update) App.removeUpdate(f);
t._update = null; t._update = null;
@ -206,8 +210,12 @@ class Object {
} }
#if lnx_skin #if lnx_skin
public function getBoneAnimation(armatureUid): BoneAnimation { public function getBoneAnimation(armatureUid: Int): BoneAnimation {
for (a in Scene.active.animations) if (a.armature != null && a.armature.uid == armatureUid) return cast a; for (a in Scene.active.animations) {
if (a.armature != null && a.armature.uid == armatureUid) {
return cast a;
}
}
return null; return null;
} }
#else #else

View File

@ -24,6 +24,9 @@ class ObjectAnimation extends Animation {
public var transformMap: Map<String, FastFloat>; public var transformMap: Map<String, FastFloat>;
var defaultSampler: ActionSampler = null;
static inline var DEFAULT_SAMPLER_ID = "__object_default_action__";
public static var trackNames: Array<String> = [ "xloc", "yloc", "zloc", public static var trackNames: Array<String> = [ "xloc", "yloc", "zloc",
"xrot", "yrot", "zrot", "xrot", "yrot", "zrot",
"qwrot", "qxrot", "qyrot", "qzrot", "qwrot", "qxrot", "qyrot", "qzrot",
@ -39,7 +42,6 @@ class ObjectAnimation extends Animation {
isSkinned = false; isSkinned = false;
super(); super();
} }
function getAction(action: String): TObj { function getAction(action: String): TObj {
for (a in oactions) if (a != null && a.objects[0].name == action) return a.objects[0]; for (a in oactions) if (a != null && a.objects[0].name == action) return a.objects[0];
return null; return null;
@ -47,10 +49,29 @@ class ObjectAnimation extends Animation {
override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.0, speed = 1.0, loop = true) { override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.0, speed = 1.0, loop = true) {
super.play(action, onComplete, blendTime, speed, loop); super.play(action, onComplete, blendTime, speed, loop);
if (this.action == "" && oactions[0] != null) this.action = oactions[0].objects[0].name; if (this.action == "" && oactions != null && oactions[0] != null){
this.action = oactions[0].objects[0].name;
}
oaction = getAction(this.action); oaction = getAction(this.action);
if (oaction != null) { if (oaction != null) {
isSampled = oaction.sampled != null && oaction.sampled; isSampled = oaction.sampled != null && oaction.sampled;
if (defaultSampler != null) {
deRegisterAction(DEFAULT_SAMPLER_ID);
}
var callbacks = onComplete != null ? [onComplete] : null;
defaultSampler = new ActionSampler(this.action, speed, loop, false, callbacks);
registerAction(DEFAULT_SAMPLER_ID, defaultSampler);
if (paused) defaultSampler.paused = true;
updateAnimation = function(map: Map<String, FastFloat>) {
sampleAction(defaultSampler, map);
};
}
else {
if (defaultSampler != null) {
deRegisterAction(DEFAULT_SAMPLER_ID);
defaultSampler = null;
}
updateAnimation = null;
} }
} }
@ -61,12 +82,13 @@ class ObjectAnimation extends Animation {
Animation.beginProfile(); Animation.beginProfile();
#end #end
if(transformMap == null) transformMap = new Map(); if (transformMap == null) transformMap = new Map();
transformMap = initTransformMap(); transformMap = initTransformMap();
super.update(delta); super.update(delta);
if (defaultSampler != null) defaultSampler.paused = paused;
if (paused) return; if (paused) return;
if(updateAnimation == null) return; if (updateAnimation == null) return;
if (!isSkinned) updateObjectAnimation(); if (!isSkinned) updateObjectAnimation();
#if lnx_debug #if lnx_debug
@ -75,7 +97,9 @@ class ObjectAnimation extends Animation {
} }
public override function getTotalFrames(sampler: ActionSampler): Int { public override function getTotalFrames(sampler: ActionSampler): Int {
var track = getAction(sampler.action).anim.tracks[0]; var action = getAction(sampler.action);
if (action == null || action.anim == null || action.anim.tracks == null || action.anim.tracks.length == 0) return 0;
var track = action.anim.tracks[0];
return Std.int(track.frames[track.frames.length - 1] - track.frames[0]); return Std.int(track.frames[track.frames.length - 1] - track.frames[0]);
} }

View File

@ -2,11 +2,14 @@ package iron.object;
#if lnx_particles #if lnx_particles
import kha.FastFloat;
import kha.graphics4.Usage; import kha.graphics4.Usage;
import kha.arrays.Float32Array; import kha.arrays.Float32Array;
import iron.data.Data; import iron.data.Data;
import iron.data.ParticleData; import iron.data.ParticleData;
import iron.data.SceneFormat; import iron.data.SceneFormat;
import iron.data.Geometry;
import iron.data.MeshData;
import iron.system.Time; import iron.system.Time;
import iron.math.Mat4; import iron.math.Mat4;
import iron.math.Quat; import iron.math.Quat;
@ -16,10 +19,13 @@ import iron.math.Vec4;
class ParticleSystem { class ParticleSystem {
public var data: ParticleData; public var data: ParticleData;
public var speed = 1.0; public var speed = 1.0;
public var dynamicEmitter: Bool = true;
var currentSpeed = 0.0;
var particles: Array<Particle>; var particles: Array<Particle>;
var ready: Bool; var ready: Bool;
var frameRate = 24; var frameRate = 24;
var lifetime = 0.0; var lifetime = 0.0;
var looptime = 0.0;
var animtime = 0.0; var animtime = 0.0;
var time = 0.0; var time = 0.0;
var spawnRate = 0.0; var spawnRate = 0.0;
@ -46,15 +52,31 @@ class ParticleSystem {
var ownerLoc = new Vec4(); var ownerLoc = new Vec4();
var ownerRot = new Quat(); var ownerRot = new Quat();
var ownerScl = new Vec4(); var ownerScl = new Vec4();
var random = 0.0;
var tmpV4 = new Vec4();
var instancedData: Float32Array = null;
var lastSpawnedCount: Int = 0;
var hasUniqueGeom: Bool = false;
public function new(sceneName: String, pref: TParticleReference) { public function new(sceneName: String, pref: TParticleReference) {
seed = pref.seed; seed = pref.seed;
currentSpeed = speed;
speed = 0;
particles = []; particles = [];
ready = false; ready = false;
Data.getParticle(sceneName, pref.particle, function(b: ParticleData) { Data.getParticle(sceneName, pref.particle, function(b: ParticleData) {
data = b; data = b;
r = data.raw; r = data.raw;
var dyn: Null<Bool> = r.dynamic_emitter;
var dynValue: Bool = true;
if (dyn != null) {
dynValue = dyn;
}
dynamicEmitter = dynValue;
if (Scene.active.raw.gravity != null) { if (Scene.active.raw.gravity != null) {
gx = Scene.active.raw.gravity[0] * r.weight_gravity; gx = Scene.active.raw.gravity[0] * r.weight_gravity;
gy = Scene.active.raw.gravity[1] * r.weight_gravity; gy = Scene.active.raw.gravity[1] * r.weight_gravity;
@ -65,38 +87,73 @@ class ParticleSystem {
gy = 0; gy = 0;
gz = -9.81 * r.weight_gravity; gz = -9.81 * r.weight_gravity;
} }
alignx = r.object_align_factor[0] / 2; alignx = r.object_align_factor[0];
aligny = r.object_align_factor[1] / 2; aligny = r.object_align_factor[1];
alignz = r.object_align_factor[2] / 2; alignz = r.object_align_factor[2];
looptime = (r.frame_end - r.frame_start) / frameRate;
lifetime = r.lifetime / frameRate; lifetime = r.lifetime / frameRate;
animtime = (r.frame_end - r.frame_start) / frameRate; animtime = r.loop ? looptime : looptime + lifetime;
spawnRate = ((r.frame_end - r.frame_start) / r.count) / frameRate; spawnRate = ((r.frame_end - r.frame_start) / r.count) / frameRate;
for (i in 0...r.count) { for (i in 0...r.count) {
var particle = new Particle(i); particles.push(new Particle(i));
particle.sr = 1 - Math.random() * r.size_random;
particles.push(particle);
} }
ready = true; ready = true;
if (r.auto_start){
start();
}
}); });
} }
public function start() {
if (r.is_unique) random = Math.random();
lifetime = r.lifetime / frameRate;
time = 0;
lap = 0;
lapTime = 0;
speed = currentSpeed;
lastSpawnedCount = 0;
instancedData = null;
}
public function pause() { public function pause() {
lifetime = 0; speed = 0;
} }
public function resume() { public function resume() {
lifetime = r.lifetime / frameRate; lifetime = r.lifetime / frameRate;
speed = currentSpeed;
} }
// TODO: interrupt smoothly
public function stop() {
end();
}
function end() {
lifetime = 0;
speed = 0;
lap = 0;
}
public function update(object: MeshObject, owner: MeshObject) { public function update(object: MeshObject, owner: MeshObject) {
if (!ready || object == null || speed == 0.0) return; if (!ready || object == null || speed == 0.0) return;
if (iron.App.pauseUpdates) return;
var prevLap = lap;
// Copy owner world transform but discard scale // Copy owner world transform but discard scale
owner.transform.world.decompose(ownerLoc, ownerRot, ownerScl); owner.transform.world.decompose(ownerLoc, ownerRot, ownerScl);
object.transform.loc = ownerLoc; if (dynamicEmitter) {
object.transform.rot = ownerRot; object.transform.loc.x = 0; object.transform.loc.y = 0; object.transform.loc.z = 0;
object.transform.rot = new Quat();
} else {
object.transform.loc = ownerLoc;
object.transform.rot = ownerRot;
}
// Set particle size per particle system // Set particle size per particle system
object.transform.scale = new Vec4(r.particle_size, r.particle_size, r.particle_size, 1); object.transform.scale = new Vec4(r.particle_size, r.particle_size, r.particle_size, 1);
@ -115,16 +172,25 @@ class ParticleSystem {
} }
// Animate // Animate
time += Time.delta * speed; time += Time.renderDelta * speed; // realDelta to renderDelta
lap = Std.int(time / animtime); lap = Std.int(time / animtime);
lapTime = time - lap * animtime; lapTime = time - lap * animtime;
count = Std.int(lapTime / spawnRate); count = Std.int(lapTime / spawnRate);
if (lap > prevLap && !r.loop) {
end();
}
if (lap > prevLap && r.loop) {
lastSpawnedCount = 0;
}
updateGpu(object, owner); updateGpu(object, owner);
} }
public function getData(): Mat4 { public function getData(): Mat4 {
var hair = r.type == 1; var hair = r.type == 1;
// Store loop flag in the sign: positive -> loop, negative -> no loop
m._00 = r.loop ? animtime : -animtime; m._00 = r.loop ? animtime : -animtime;
m._01 = hair ? 1 / particles.length : spawnRate; m._01 = hair ? 1 / particles.length : spawnRate;
m._02 = hair ? 1 : lifetime; m._02 = hair ? 1 : lifetime;
@ -133,9 +199,9 @@ class ParticleSystem {
m._11 = hair ? 0 : aligny; m._11 = hair ? 0 : aligny;
m._12 = hair ? 0 : alignz; m._12 = hair ? 0 : alignz;
m._13 = hair ? 0 : r.factor_random; m._13 = hair ? 0 : r.factor_random;
m._20 = hair ? 0 : gx * r.mass; m._20 = hair ? 0 : gx;
m._21 = hair ? 0 : gy * r.mass; m._21 = hair ? 0 : gy;
m._22 = hair ? 0 : gz * r.mass; m._22 = hair ? 0 : gz;
m._23 = hair ? 0 : r.lifetime_random; m._23 = hair ? 0 : r.lifetime_random;
m._30 = tilesx; m._30 = tilesx;
m._31 = tilesy; m._31 = tilesy;
@ -144,13 +210,34 @@ class ParticleSystem {
return m; return m;
} }
public function getSizeRandom(): FastFloat {
return r.size_random;
}
public inline function getRandom(): FastFloat {
return random;
}
public inline function getSize(): FastFloat {
return r.particle_size;
}
function updateGpu(object: MeshObject, owner: MeshObject) { function updateGpu(object: MeshObject, owner: MeshObject) {
if (!object.data.geom.instanced) setupGeomGpu(object, owner); if (dynamicEmitter) {
// GPU particles transform is attached to owner object if (!hasUniqueGeom) ensureUniqueGeom(object);
var needSetup = instancedData == null || object.data.geom.instancedVB == null;
if (needSetup) setupGeomGpuDynamic(object, owner);
updateSpawnedInstances(object, owner);
}
else {
if (!hasUniqueGeom) ensureUniqueGeom(object);
if (!object.data.geom.instanced) setupGeomGpu(object, owner);
}
// GPU particles transform is attached to owner object in static mode
} }
function setupGeomGpu(object: MeshObject, owner: MeshObject) { function setupGeomGpu(object: MeshObject, owner: MeshObject) {
var instancedData = new Float32Array(particles.length * 6); var instancedData = new Float32Array(particles.length * 3);
var i = 0; var i = 0;
var normFactor = 1 / 32767; // pa.values are not normalized var normFactor = 1 / 32767; // pa.values are not normalized
@ -169,10 +256,6 @@ class ParticleSystem {
instancedData.set(i, pa.values[j * pa.size ] * normFactor * scaleFactor.x); i++; instancedData.set(i, pa.values[j * pa.size ] * normFactor * scaleFactor.x); i++;
instancedData.set(i, pa.values[j * pa.size + 1] * normFactor * scaleFactor.y); i++; instancedData.set(i, pa.values[j * pa.size + 1] * normFactor * scaleFactor.y); i++;
instancedData.set(i, pa.values[j * pa.size + 2] * normFactor * scaleFactor.z); i++; instancedData.set(i, pa.values[j * pa.size + 2] * normFactor * scaleFactor.z); i++;
instancedData.set(i, p.sr); i++;
instancedData.set(i, p.sr); i++;
instancedData.set(i, p.sr); i++;
} }
case 1: // Face case 1: // Face
@ -196,10 +279,6 @@ class ParticleSystem {
instancedData.set(i, pos.x * normFactor * scaleFactor.x); i++; instancedData.set(i, pos.x * normFactor * scaleFactor.x); i++;
instancedData.set(i, pos.y * normFactor * scaleFactor.y); i++; instancedData.set(i, pos.y * normFactor * scaleFactor.y); i++;
instancedData.set(i, pos.z * normFactor * scaleFactor.z); i++; instancedData.set(i, pos.z * normFactor * scaleFactor.z); i++;
instancedData.set(i, p.sr); i++;
instancedData.set(i, p.sr); i++;
instancedData.set(i, p.sr); i++;
} }
case 2: // Volume case 2: // Volume
@ -210,27 +289,139 @@ class ParticleSystem {
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.x); i++; instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.x); i++;
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y); i++; instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y); i++;
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z); i++; instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z); i++;
instancedData.set(i, p.sr); i++;
instancedData.set(i, p.sr); i++;
instancedData.set(i, p.sr); i++;
} }
} }
object.data.geom.setupInstanced(instancedData, 3, Usage.StaticUsage); object.data.geom.setupInstanced(instancedData, 1, Usage.StaticUsage);
} }
function fhash(n: Int): Float { // allocate instanced VB once for this object
var s = n + 1.0; function setupGeomGpuDynamic(object: MeshObject, owner: MeshObject) {
s *= 9301.0 % s; if (instancedData == null) instancedData = new Float32Array(particles.length * 3);
s = (s * 9301.0 + 49297.0) % 233280.0; lastSpawnedCount = 0;
return s / 233280.0; // Create instanced VB once if missing (seed with our instancedData)
if (object.data.geom.instancedVB == null) {
object.data.geom.setupInstanced(instancedData, 1, Usage.DynamicUsage);
}
} }
function ensureUniqueGeom(object: MeshObject) {
if (hasUniqueGeom) return;
var newData: MeshData = null;
new MeshData(object.data.raw, function(dat: MeshData) {
dat.scalePos = object.data.scalePos;
dat.scaleTex = object.data.scaleTex;
dat.format = object.data.format;
newData = dat;
});
if (newData != null) object.setData(newData);
hasUniqueGeom = true;
}
function updateSpawnedInstances(object: MeshObject, owner: MeshObject) {
if (instancedData == null) return;
var targetCount = count;
if (targetCount > particles.length) targetCount = particles.length;
if (targetCount <= lastSpawnedCount) return;
var normFactor = 1 / 32767;
var scalePosOwner = owner.data.scalePos;
var scalePosParticle = object.data.scalePos;
var particleSize = r.particle_size;
var base = 1.0 / (particleSize * scalePosParticle);
switch (r.emit_from) {
case 0: // Vert
var pa = owner.data.geom.positions;
var osx = owner.transform.scale.x;
var osy = owner.transform.scale.y;
var osz = owner.transform.scale.z;
var pCount = Std.int(pa.values.length / pa.size);
for (idx in lastSpawnedCount...targetCount) {
var j = Std.int(fhash(idx) * pCount);
var lx = pa.values[j * pa.size ] * normFactor * scalePosOwner * osx;
var ly = pa.values[j * pa.size + 1] * normFactor * scalePosOwner * osy;
var lz = pa.values[j * pa.size + 2] * normFactor * scalePosOwner * osz;
tmpV4.x = lx; tmpV4.y = ly; tmpV4.z = lz; tmpV4.w = 1;
tmpV4.applyQuat(ownerRot);
var o = idx * 3;
instancedData.set(o , (tmpV4.x + ownerLoc.x) * base);
instancedData.set(o + 1, (tmpV4.y + ownerLoc.y) * base);
instancedData.set(o + 2, (tmpV4.z + ownerLoc.z) * base);
}
case 1: // Face
var positions = owner.data.geom.positions.values;
var osx1 = owner.transform.scale.x;
var osy1 = owner.transform.scale.y;
var osz1 = owner.transform.scale.z;
for (idx in lastSpawnedCount...targetCount) {
var ia = owner.data.geom.indices[Std.random(owner.data.geom.indices.length)];
var faceIndex = Std.random(Std.int(ia.length / 3));
var i0 = ia[faceIndex * 3 + 0];
var i1 = ia[faceIndex * 3 + 1];
var i2 = ia[faceIndex * 3 + 2];
var v0x = positions[i0 * 4 ], v0y = positions[i0 * 4 + 1], v0z = positions[i0 * 4 + 2];
var v1x = positions[i1 * 4 ], v1y = positions[i1 * 4 + 1], v1z = positions[i1 * 4 + 2];
var v2x = positions[i2 * 4 ], v2y = positions[i2 * 4 + 1], v2z = positions[i2 * 4 + 2];
var rx = Math.random(); var ry = Math.random(); if (rx + ry > 1) { rx = 1 - rx; ry = 1 - ry; }
var pxs = v0x + rx * (v1x - v0x) + ry * (v2x - v0x);
var pys = v0y + rx * (v1y - v0y) + ry * (v2y - v0y);
var pzs = v0z + rx * (v1z - v0z) + ry * (v2z - v0z);
var px = pxs * normFactor * scalePosOwner * osx1;
var py = pys * normFactor * scalePosOwner * osy1;
var pz = pzs * normFactor * scalePosOwner * osz1;
tmpV4.x = px; tmpV4.y = py; tmpV4.z = pz; tmpV4.w = 1;
tmpV4.applyQuat(ownerRot);
var o1 = idx * 3;
instancedData.set(o1 , (tmpV4.x + ownerLoc.x) * base);
instancedData.set(o1 + 1, (tmpV4.y + ownerLoc.y) * base);
instancedData.set(o1 + 2, (tmpV4.z + ownerLoc.z) * base);
}
case 2: // Volume
var dim = object.transform.dim;
for (idx in lastSpawnedCount...targetCount) {
tmpV4.x = (Math.random() * 2.0 - 1.0) * (dim.x * 0.5);
tmpV4.y = (Math.random() * 2.0 - 1.0) * (dim.y * 0.5);
tmpV4.z = (Math.random() * 2.0 - 1.0) * (dim.z * 0.5);
tmpV4.w = 1;
tmpV4.applyQuat(ownerRot);
var o2 = idx * 3;
instancedData.set(o2 , (tmpV4.x + ownerLoc.x) * base);
instancedData.set(o2 + 1, (tmpV4.y + ownerLoc.y) * base);
instancedData.set(o2 + 2, (tmpV4.z + ownerLoc.z) * base);
}
}
// Upload full active range [0..targetCount) to this object's instanced VB
var geom = object.data.geom;
if (geom.instancedVB == null) {
geom.setupInstanced(instancedData, 1, Usage.DynamicUsage);
}
var vb = geom.instancedVB.lock();
var totalFloats = targetCount * 3; // xyz per instance
var i = 0;
while (i < totalFloats) {
vb.setFloat32(i * 4, instancedData[i]);
i++;
}
geom.instancedVB.unlock();
geom.instanceCount = targetCount;
lastSpawnedCount = targetCount;
}
inline function fhash(n: Int): Float {
var s = n + 1.0;
s *= 9301.0 % s;
s = (s * 9301.0 + 49297.0) % 233280.0;
return s / 233280.0;
}
public function remove() {} public function remove() {}
/** /**
Generates a random point in the triangle with vertex positions abc. Generates a random point in the triangle with vertex positions abc.
Please note that the given position vectors are changed in-place by this Please note that the given position vectors are changed in-place by this
function and can be considered garbage afterwards, so make sure to clone function and can be considered garbage afterwards, so make sure to clone
them first if needed. them first if needed.
@ -255,10 +446,11 @@ class ParticleSystem {
class Particle { class Particle {
public var i: Int; public var i: Int;
public var px = 0.0;
public var py = 0.0; public var x = 0.0;
public var pz = 0.0; public var y = 0.0;
public var sr = 1.0; // Size random public var z = 0.0;
public var cameraDistance: Float; public var cameraDistance: Float;
public function new(i: Int) { public function new(i: Int) {

View File

@ -80,7 +80,7 @@ class Tilesheet {
function update() { function update() {
if (!ready || paused || action.start >= action.end) return; if (!ready || paused || action.start >= action.end) return;
time += Time.realDelta; time += Time.renderDelta;
var frameTime = 1 / raw.framerate; var frameTime = 1 / raw.framerate;
var framesToAdvance = 0; var framesToAdvance = 0;

View File

@ -7,16 +7,20 @@ import kha.graphics4.TextureFilter;
import kha.graphics4.MipMapFilter; import kha.graphics4.MipMapFilter;
import kha.arrays.Float32Array; import kha.arrays.Float32Array;
import iron.math.Vec4; import iron.math.Vec4;
import iron.math.Mat4;
import iron.math.Quat; import iron.math.Quat;
import iron.math.Mat3; import iron.math.Mat3;
import iron.math.Mat4;
import iron.data.WorldData;
import iron.data.MaterialData; import iron.data.MaterialData;
import iron.data.ShaderData; import iron.data.ShaderData;
import iron.data.SceneFormat; import iron.data.WorldData;
import iron.data.SceneFormat.TShaderConstant;
import iron.data.SceneFormat.TBindConstant;
import iron.object.Transform;
import iron.object.LightObject;
import iron.Scene;
import iron.RenderPath;
import iron.system.Input; import iron.system.Input;
import iron.system.Time; import iron.system.Time;
import iron.RenderPath;
using StringTools; using StringTools;
// Structure for setting shader uniforms // Structure for setting shader uniforms
@ -38,6 +42,7 @@ class Uniforms {
public static var helpMat = Mat4.identity(); public static var helpMat = Mat4.identity();
public static var helpMat2 = Mat4.identity(); public static var helpMat2 = Mat4.identity();
public static var helpMat3 = Mat3.identity(); public static var helpMat3 = Mat3.identity();
public static var helpMat4 = Mat4.identity();
public static var helpVec = new Vec4(); public static var helpVec = new Vec4();
public static var helpVec2 = new Vec4(); public static var helpVec2 = new Vec4();
public static var helpQuat = new Quat(); // Keep at identity public static var helpQuat = new Quat(); // Keep at identity
@ -47,6 +52,10 @@ class Uniforms {
public static var externalVec4Links: Array<Object->MaterialData->String->Vec4> = null; public static var externalVec4Links: Array<Object->MaterialData->String->Vec4> = null;
public static var externalVec3Links: Array<Object->MaterialData->String->Vec4> = null; public static var externalVec3Links: Array<Object->MaterialData->String->Vec4> = null;
public static var externalVec2Links: Array<Object->MaterialData->String->Vec4> = null; public static var externalVec2Links: Array<Object->MaterialData->String->Vec4> = null;
public static var eyeLeftCallCount = 0;
public static var lastFrameChecked = -1;
public static var externalFloatLinks: Array<Object->MaterialData->String->Null<kha.FastFloat>> = null; public static var externalFloatLinks: Array<Object->MaterialData->String->Null<kha.FastFloat>> = null;
public static var externalFloatsLinks: Array<Object->MaterialData->String->Float32Array> = null; public static var externalFloatsLinks: Array<Object->MaterialData->String->Float32Array> = null;
public static var externalIntLinks: Array<Object->MaterialData->String->Null<Int>> = null; public static var externalIntLinks: Array<Object->MaterialData->String->Null<Int>> = null;
@ -59,6 +68,10 @@ class Uniforms {
public static var defaultFilter = TextureFilter.LinearFilter; public static var defaultFilter = TextureFilter.LinearFilter;
#end #end
#if lnx_morph_target
public static var forceUploadMorphWeights: Bool = false;
#end
public static function setContextConstants(g: Graphics, context: ShaderContext, bindParams: Array<String>) { public static function setContextConstants(g: Graphics, context: ShaderContext, bindParams: Array<String>) {
if (context.raw.constants != null) { if (context.raw.constants != null) {
for (i in 0...context.raw.constants.length) { for (i in 0...context.raw.constants.length) {
@ -181,11 +194,15 @@ class Uniforms {
// Multiple voxel volumes, always set params // Multiple voxel volumes, always set params
g.setImageTexture(context.textureUnits[j], rt.image); // image2D/3D g.setImageTexture(context.textureUnits[j], rt.image); // image2D/3D
if (rt.raw.name.startsWith("voxels_")) { if (rt.raw.name.startsWith("voxels_")) {
g.setTextureParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.NoMipFilter); g.setTextureParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.LinearMipFilter);
}
else if (rt.raw.name.startsWith("voxelsSDF"))
{
g.setTexture3DParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.PointFilter, TextureFilter.PointFilter, MipMapFilter.NoMipFilter);
} }
else if (rt.raw.name.startsWith("voxels")) else if (rt.raw.name.startsWith("voxels"))
{ {
g.setTexture3DParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.NoMipFilter); g.setTexture3DParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.PointMipFilter);
} }
else else
{ {
@ -286,6 +303,89 @@ class Uniforms {
helpMat.getInverse(helpMat); helpMat.getInverse(helpMat);
m = helpMat; m = helpMat;
} }
#if lnx_vr
case "_inverseViewProjectionMatrixLeft": {
var vr = kha.vr.VrInterface.instance;
if (vr != null && vr.IsPresenting()) {
var leftView = vr.GetViewMatrix(0);
var leftProj = vr.GetProjectionMatrix(0);
helpMat._00 = leftView._00; helpMat._01 = leftView._01; helpMat._02 = leftView._02; helpMat._03 = leftView._03;
helpMat._10 = leftView._10; helpMat._11 = leftView._11; helpMat._12 = leftView._12; helpMat._13 = leftView._13;
helpMat._20 = leftView._20; helpMat._21 = leftView._21; helpMat._22 = leftView._22; helpMat._23 = leftView._23;
helpMat._30 = leftView._30; helpMat._31 = leftView._31; helpMat._32 = leftView._32; helpMat._33 = leftView._33;
helpMat2._00 = leftProj._00; helpMat2._01 = leftProj._01; helpMat2._02 = leftProj._02; helpMat2._03 = leftProj._03;
helpMat2._10 = leftProj._10; helpMat2._11 = leftProj._11; helpMat2._12 = leftProj._12; helpMat2._13 = leftProj._13;
helpMat2._20 = leftProj._20; helpMat2._21 = leftProj._21; helpMat2._22 = leftProj._22; helpMat2._23 = leftProj._23;
helpMat2._30 = leftProj._30; helpMat2._31 = leftProj._31; helpMat2._32 = leftProj._32; helpMat2._33 = leftProj._33;
helpMat.multmat(helpMat2);
helpMat.getInverse(helpMat);
} else if (iron.RenderPath.isVRSimulateMode()) {
var ipd_offset = 0.032 * 35.0; // Match eye offset
var rightVec = camera.rightWorld();
var eyeLeftX = camera.transform.worldx() - rightVec.x * ipd_offset;
var eyeLeftY = camera.transform.worldy() - rightVec.y * ipd_offset;
var eyeLeftZ = camera.transform.worldz() - rightVec.z * ipd_offset;
helpMat.setFrom(camera.transform.world);
helpMat._30 = eyeLeftX;
helpMat._31 = eyeLeftY;
helpMat._32 = eyeLeftZ;
helpMat.getInverse(helpMat); // Now it's a view matrix
helpMat.multmat(camera.P);
helpMat.getInverse(helpMat);
} else {
helpMat.setFrom(camera.V);
helpMat.multmat(camera.P);
helpMat.getInverse(helpMat);
}
m = helpMat;
}
case "_inverseViewProjectionMatrixRight": {
var vr = kha.vr.VrInterface.instance;
if (vr != null && vr.IsPresenting()) {
var rightView = vr.GetViewMatrix(1);
var rightProj = vr.GetProjectionMatrix(1);
// kha.math.FastMatrix4 to iron.math.Mat4
helpMat2._00 = rightView._00; helpMat2._01 = rightView._01; helpMat2._02 = rightView._02; helpMat2._03 = rightView._03;
helpMat2._10 = rightView._10; helpMat2._11 = rightView._11; helpMat2._12 = rightView._12; helpMat2._13 = rightView._13;
helpMat2._20 = rightView._20; helpMat2._21 = rightView._21; helpMat2._22 = rightView._22; helpMat2._23 = rightView._23;
helpMat2._30 = rightView._30; helpMat2._31 = rightView._31; helpMat2._32 = rightView._32; helpMat2._33 = rightView._33;
helpMat4._00 = rightProj._00; helpMat4._01 = rightProj._01; helpMat4._02 = rightProj._02; helpMat4._03 = rightProj._03;
helpMat4._10 = rightProj._10; helpMat4._11 = rightProj._11; helpMat4._12 = rightProj._12; helpMat4._13 = rightProj._13;
helpMat4._20 = rightProj._20; helpMat4._21 = rightProj._21; helpMat4._22 = rightProj._22; helpMat4._23 = rightProj._23;
helpMat4._30 = rightProj._30; helpMat4._31 = rightProj._31; helpMat4._32 = rightProj._32; helpMat4._33 = rightProj._33;
helpMat2.multmat(helpMat4);
helpMat2.getInverse(helpMat2);
m = helpMat2;
} else if (iron.RenderPath.isVRSimulateMode()) {
var ipd_offset = 0.032 * 35.0;
var rightVec = camera.rightWorld();
// calculate right eye position in world space
var eyeRightX = camera.transform.worldx() + rightVec.x * ipd_offset;
var eyeRightY = camera.transform.worldy() + rightVec.y * ipd_offset;
var eyeRightZ = camera.transform.worldz() + rightVec.z * ipd_offset;
helpMat2.setFrom(camera.transform.world);
helpMat2._30 = eyeRightX;
helpMat2._31 = eyeRightY;
helpMat2._32 = eyeRightZ;
helpMat2.getInverse(helpMat2);
helpMat2.multmat(camera.P);
helpMat2.getInverse(helpMat2);
m = helpMat2;
} else {
// fallback to center camera
helpMat2.setFrom(camera.V);
helpMat2.multmat(camera.P);
helpMat2.getInverse(helpMat2);
m = helpMat2;
}
}
#end
case "_viewProjectionMatrix": { case "_viewProjectionMatrix": {
#if lnx_centerworld #if lnx_centerworld
m = vmat(camera.V); m = vmat(camera.V);
@ -398,6 +498,28 @@ class Uniforms {
v = helpVec; v = helpVec;
} }
} }
#if lnx_vr
case "_pointPositionLeft": {
var point = RenderPath.active.point;
if (point != null) {
var lightWorldX = point.transform.worldx();
var lightWorldY = point.transform.worldy();
var lightWorldZ = point.transform.worldz();
helpVec.set(lightWorldX, lightWorldY, lightWorldZ);
v = helpVec;
}
}
case "_pointPositionRight": {
var point = RenderPath.active.point;
if (point != null) {
var lightWorldX = point.transform.worldx();
var lightWorldY = point.transform.worldy();
var lightWorldZ = point.transform.worldz();
helpVec.set(lightWorldX, lightWorldY, lightWorldZ);
v = helpVec;
}
}
#end
#if lnx_spot #if lnx_spot
case "_spotDirection": { case "_spotDirection": {
var point = RenderPath.active.point; var point = RenderPath.active.point;
@ -484,6 +606,84 @@ class Uniforms {
helpVec = camera.rightWorld().normalize(); helpVec = camera.rightWorld().normalize();
v = helpVec; v = helpVec;
} }
#if lnx_vr
case "_eyeLeft": {
var currentFrame = iron.RenderPath.active.frame;
if (currentFrame != lastFrameChecked) {
eyeLeftCallCount = 0;
lastFrameChecked = currentFrame;
}
eyeLeftCallCount++;
var vr = kha.vr.VrInterface.instance;
if (vr != null && vr.IsPresenting()) {
var leftViewMatrix = vr.GetViewMatrix(0);
var invLeft = leftViewMatrix.inverse();
helpVec.set(invLeft._30, invLeft._31, invLeft._32);
// trace("eyeLeft: " + helpVec.x + ", " + helpVec.y + ", " + helpVec.z);
} else if (iron.RenderPath.isVRSimulateMode()) {
var ipd_offset = 0.032 * 35.0;
var rightVec = camera.rightWorld();
var centerX = camera.transform.worldx();
var centerY = camera.transform.worldy();
var centerZ = camera.transform.worldz();
helpVec.set(
centerX - rightVec.x * ipd_offset,
centerY - rightVec.y * ipd_offset,
centerZ - rightVec.z * ipd_offset
);
} else {
helpVec.set(camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz());
}
v = helpVec;
}
case "_eyeRight": {
var vr = kha.vr.VrInterface.instance;
if (vr != null && vr.IsPresenting()) {
var rightViewMatrix = vr.GetViewMatrix(1);
var invRight = rightViewMatrix.inverse();
helpVec.set(invRight._30, invRight._31, invRight._32);
} else if (iron.RenderPath.isVRSimulateMode()) {
var ipd_offset = 0.032 * 35.0;
var rightVec = camera.rightWorld();
var centerX = camera.transform.worldx();
var centerY = camera.transform.worldy();
var centerZ = camera.transform.worldz();
helpVec.set(
centerX + rightVec.x * ipd_offset,
centerY + rightVec.y * ipd_offset,
centerZ + rightVec.z * ipd_offset
);
} else {
helpVec.set(camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz());
}
v = helpVec;
}
case "_eyeLookLeft": {
var vr = kha.vr.VrInterface.instance;
if (vr != null && vr.IsPresenting()) {
var leftViewMatrix = vr.GetViewMatrix(0);
var invLeft = leftViewMatrix.inverse();
helpVec.set(-invLeft._20, -invLeft._21, -invLeft._22);
helpVec.normalize();
} else {
helpVec = camera.lookWorld().normalize();
}
v = helpVec;
}
case "_eyeLookRight": {
var vr = kha.vr.VrInterface.instance;
if (vr != null && vr.IsPresenting()) {
var rightViewMatrix = vr.GetViewMatrix(1);
var invRight = rightViewMatrix.inverse();
helpVec.set(-invRight._20, -invRight._21, -invRight._22);
helpVec.normalize();
} else {
helpVec = camera.lookWorld().normalize();
}
v = helpVec;
}
#end
case "_backgroundCol": { case "_backgroundCol": {
if (camera.data.raw.clear_color != null) helpVec.set(camera.data.raw.clear_color[0], camera.data.raw.clear_color[1], camera.data.raw.clear_color[2]); if (camera.data.raw.clear_color != null) helpVec.set(camera.data.raw.clear_color[0], camera.data.raw.clear_color[1], camera.data.raw.clear_color[2]);
v = helpVec; v = helpVec;
@ -1109,6 +1309,26 @@ class Uniforms {
case "_texUnpack": { case "_texUnpack": {
f = texUnpack != null ? texUnpack : 1.0; f = texUnpack != null ? texUnpack : 1.0;
} }
#if lnx_particles
case "_particleSizeRandom": {
var mo = cast(object, MeshObject);
if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
f = mo.particleOwner.particleSystems[mo.particleIndex].getSizeRandom();
}
}
case "_particleRandom": {
var mo = cast(object, MeshObject);
if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
f = mo.particleOwner.particleSystems[mo.particleIndex].getRandom();
}
}
case "_particleSize": {
var mo = cast(object, MeshObject);
if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
f = mo.particleOwner.particleSystems[mo.particleIndex].getSize();
}
}
#end
} }
if (f == null && externalFloatLinks != null) { if (f == null && externalFloatLinks != null) {
@ -1141,7 +1361,19 @@ class Uniforms {
#end // lnx_clusters #end // lnx_clusters
#if lnx_morph_target #if lnx_morph_target
case "_morphWeights": { case "_morphWeights": {
fa = cast(object, MeshObject).morphTarget.morphWeights; var morphTarget = cast(object, MeshObject).morphTarget;
morphTarget.flushBatchedUpdates();
if (forceUploadMorphWeights) {
fa = morphTarget.morphWeights;
}
else {
if (morphTarget.isDirty) {
fa = morphTarget.morphWeights;
}
else {
return;
}
}
} }
#end #end
} }
@ -1155,6 +1387,12 @@ class Uniforms {
if (fa == null) return; if (fa == null) return;
g.setFloats(location, fa); g.setFloats(location, fa);
#if lnx_morph_target
if (c.link == "_morphWeights") {
cast(object, MeshObject).morphTarget.markClean();
}
#end
} }
else if (c.type == "int") { else if (c.type == "int") {
var i: Null<Int> = null; var i: Null<Int> = null;
@ -1183,6 +1421,7 @@ class Uniforms {
if (materialContext.raw.bind_constants != null) { if (materialContext.raw.bind_constants != null) {
for (i in 0...materialContext.raw.bind_constants.length) { for (i in 0...materialContext.raw.bind_constants.length) {
var matc = materialContext.raw.bind_constants[i]; var matc = materialContext.raw.bind_constants[i];
if (matc == null) continue;
var pos = -1; var pos = -1;
for (i in 0...context.raw.constants.length) { for (i in 0...context.raw.constants.length) {
if (context.raw.constants[i].name == matc.name) { if (context.raw.constants[i].name == matc.name) {

View File

@ -1,37 +1,84 @@
package iron.system; package iron.system;
class Time { class Time {
public static var scale = 1.0;
// TODO: VR Frame Time Override - used to sync physics with VR headset refresh rate
#if lnx_vr
public static var vrFrameTime: Float = -1.0; // VR frame time in seconds (-1 = not in VR)
static var lastVRFrameTime: Float = 0.0;
static var vrFrameCount: Int = 0;
static var normalModeLogged: Bool = false;
#end
static var frequency: Null<Int> = null;
static function initFrequency() {
frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60;
}
public static var step(get, never): Float; public static var step(get, never): Float;
static function get_step(): Float { static function get_step(): Float {
if (frequency == null) initFrequency(); if (frequency == null) initFrequency();
return 1 / frequency; return 1 / frequency;
} }
static var _fixedStep: Null<Float> = 1/60;
public static var fixedStep(get, never): Float;
static function get_fixedStep(): Float {
return _fixedStep;
}
public static function initFixedStep(value: Float = 1 / 60) {
_fixedStep = value;
}
public static var scale = 1.0; static var lastTime = 0.0;
static var _delta = 0.0;
public static var delta(get, never): Float; public static var delta(get, never): Float;
static function get_delta(): Float { static function get_delta(): Float {
if (frequency == null) initFrequency(); return _delta;
return (1 / frequency) * scale;
} }
static var last = 0.0; static var lastRenderTime = 0.0;
public static var realDelta = 0.0; static var _renderDelta = 0.0;
public static var renderDelta(get, never): Float;
static function get_renderDelta(): Float {
return _renderDelta;
}
public static inline function time(): Float { public static inline function time(): Float {
return kha.Scheduler.time(); return kha.Scheduler.time() * scale;
} }
public static inline function realTime(): Float { public static inline function realTime(): Float {
return kha.Scheduler.realTime(); return kha.Scheduler.realTime() * scale;
}
static var frequency: Null<Int> = null;
static function initFrequency() {
frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60;
} }
public static function update() { public static function update() {
realDelta = realTime() - last; #if lnx_vr
last = realTime(); // TODO: use VR frame time when in VR present mode to sync physics with headset refresh
if (vrFrameTime >= 0.0) {
if (lastVRFrameTime > 0.0) {
_delta = vrFrameTime - lastVRFrameTime;
} else {
_delta = 1.0 / 90.0; // Default to 90Hz for first VR frame
}
lastVRFrameTime = vrFrameTime;
return;
} else {
if (!normalModeLogged) {
normalModeLogged = true;
}
}
#end
_delta = realTime() - lastTime;
lastTime = realTime();
}
public static function render() {
_renderDelta = realTime() - lastRenderTime;
lastRenderTime = realTime();
} }
} }

View File

@ -94,34 +94,34 @@ class Tween {
// Way too much Reflect trickery.. // Way too much Reflect trickery..
var ps = Reflect.fields(a.props); var ps = Reflect.fields(a.props);
for (i in 0...ps.length) { for (j in 0...ps.length) {
var p = ps[i]; var p = ps[j];
var k = a._time / a.duration; var k = a._time / a.duration;
if (k > 1) k = 1; if (k > 1) k = 1;
if (a._comps[i] == 1) { if (a._comps[j] == 1) {
var fromVal: Float = a._x[i]; var fromVal: Float = a._x[j];
var toVal: Float = Reflect.getProperty(a.props, p); var toVal: Float = Reflect.getProperty(a.props, p);
var val: Float = fromVal + (toVal - fromVal) * eases[a.ease](k); var val: Float = fromVal + (toVal - fromVal) * eases[a.ease](k);
Reflect.setProperty(a.target, p, val); Reflect.setProperty(a.target, p, val);
} }
else { // _comps[i] == 4 else { // _comps[j] == 4
var obj = Reflect.getProperty(a.props, p); var obj = Reflect.getProperty(a.props, p);
var toX: Float = Reflect.getProperty(obj, "x"); var toX: Float = Reflect.getProperty(obj, "x");
var toY: Float = Reflect.getProperty(obj, "y"); var toY: Float = Reflect.getProperty(obj, "y");
var toZ: Float = Reflect.getProperty(obj, "z"); var toZ: Float = Reflect.getProperty(obj, "z");
var toW: Float = Reflect.getProperty(obj, "w"); var toW: Float = Reflect.getProperty(obj, "w");
if (a._normalize[i]) { if (a._normalize[j]) {
var qdot = (a._x[i] * toX) + (a._y[i] * toY) + (a._z[i] * toZ) + (a._w[i] * toW); var qdot = (a._x[j] * toX) + (a._y[j] * toY) + (a._z[j] * toZ) + (a._w[j] * toW);
if (qdot < 0.0) { if (qdot < 0.0) {
toX = -toX; toY = -toY; toZ = -toZ; toW = -toW; toX = -toX; toY = -toY; toZ = -toZ; toW = -toW;
} }
} }
var x: Float = a._x[i] + (toX - a._x[i]) * eases[a.ease](k); var x: Float = a._x[j] + (toX - a._x[j]) * eases[a.ease](k);
var y: Float = a._y[i] + (toY - a._y[i]) * eases[a.ease](k); var y: Float = a._y[j] + (toY - a._y[j]) * eases[a.ease](k);
var z: Float = a._z[i] + (toZ - a._z[i]) * eases[a.ease](k); var z: Float = a._z[j] + (toZ - a._z[j]) * eases[a.ease](k);
var w: Float = a._w[i] + (toW - a._w[i]) * eases[a.ease](k); var w: Float = a._w[j] + (toW - a._w[j]) * eases[a.ease](k);
if (a._normalize[i]) { if (a._normalize[j]) {
var l = Math.sqrt(x * x + y * y + z * z + w * w); var l = Math.sqrt(x * x + y * y + z * z + w * w);
if (l > 0.0) { if (l > 0.0) {
l = 1.0 / l; l = 1.0 / l;

View File

@ -0,0 +1,52 @@
package iron.system;
import iron.math.Mat4;
#if lnx_vr
class VR {
static var undistortionMatrix: Mat4 = null;
public function new() {}
public static function getUndistortionMatrix(): Mat4 {
if (undistortionMatrix == null) {
undistortionMatrix = Mat4.identity();
}
return undistortionMatrix;
}
public static function getMaxRadiusSq(): Float {
return 0.0;
}
public static function initButton() {
function vrDownListener(index: Int, x: Float, y: Float) {
var vr = kha.vr.VrInterface.instance;
if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return;
var w: Float = iron.App.w();
var h: Float = iron.App.h();
if (x < w - 150 || y < h - 150) return;
vr.onVRRequestPresent();
}
function vrRender2D(g: kha.graphics2.Graphics) {
var vr = kha.vr.VrInterface.instance;
if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return;
var w: Float = iron.App.w();
var h: Float = iron.App.h();
g.color = 0xffff0000;
g.fillRect(w - 150, h - 150, 140, 140);
}
kha.input.Mouse.get().notify(vrDownListener, null, null, null);
iron.App.notifyOnRender2D(vrRender2D);
var vr = kha.vr.VrInterface.instance; // Straight to VR (Oculus Carmel)
if (vr != null && vr.IsVrEnabled()) {
vr.onVRRequestPresent();
}
}
}
#end

View File

@ -0,0 +1,138 @@
package iron.system;
#if lnx_vr
import iron.math.Vec4;
import iron.math.Quat;
class VRController {
public static var leftHandPosition: Vec4 = new Vec4();
public static var leftHandRotation: Quat = new Quat();
public static var rightHandPosition: Vec4 = new Vec4();
public static var rightHandRotation: Quat = new Quat();
public static var leftHandActive: Bool = false;
public static var rightHandActive: Bool = false;
public static var leftThumbstickX: Float = 0.0;
public static var leftThumbstickY: Float = 0.0;
public static var rightThumbstickX: Float = 0.0;
public static var rightThumbstickY: Float = 0.0;
public static var leftTrigger: Float = 0.0;
public static var rightTrigger: Float = 0.0;
public static var leftGrip: Float = 0.0;
public static var rightGrip: Float = 0.0;
public static var leftButtonX: Bool = false;
public static var leftButtonY: Bool = false;
public static var rightButtonA: Bool = false;
public static var rightButtonB: Bool = false;
public static var debugLog:Bool = false;
public static function enableDebug() {
debugLog = true;
}
public static function disableDebug() {
debugLog = false;
}
public static function updatePoses() {
var vr: kha.js.vr.VrInterface = cast kha.vr.VrInterface.instance;
if (vr == null || !vr.IsPresenting()) {
if (debugLog) trace("[VRController] Not presenting or VR null");
leftHandActive = false;
rightHandActive = false;
return;
}
untyped window._vrControllerFrame = (untyped window._vrControllerFrame || 0) + 1;
leftHandActive = false;
rightHandActive = false;
leftButtonX = false;
leftButtonY = false;
rightButtonA = false;
rightButtonB = false;
var refSpace = untyped vr.xrRefSpace;
if (vr.currentInputSources == null || vr.currentFrame == null || refSpace == null) {
return;
}
var inputSources = vr.currentInputSources;
var frame = vr.currentFrame;
var sourceCount:Int = untyped inputSources.length;
for (i in 0...sourceCount) {
var inputSource = untyped inputSources[i];
if (inputSource == null) continue;
var handedness = untyped inputSource.handedness; // "left", "right", or "none"
var gripSpace = untyped inputSource.gripSpace;
var targetRaySpace = untyped inputSource.targetRaySpace;
// use targetRaySpace first laser/pointer and fall back to gripSpace
var space = (targetRaySpace != null) ? targetRaySpace : gripSpace;
if (space == null) {
continue;
}
var pose = untyped frame.getPose(space, refSpace);
if (pose == null || pose.transform == null) {
continue;
}
var transform = pose.transform;
var pos = transform.position;
var orient = transform.orientation;
if (handedness == "left") {
leftHandPosition.set(pos.x, pos.y, pos.z);
leftHandRotation.set(orient.x, orient.y, orient.z, orient.w);
leftHandActive = true;
var gamepad = untyped inputSource.gamepad;
if (gamepad != null) {
// [0]=thumbstickX [1]=thumbstickY [2]=touchpadX [3]=touchpadY
if (gamepad.axes != null && gamepad.axes.length >= 2) {
leftThumbstickX = gamepad.axes[0];
leftThumbstickY = gamepad.axes[1];
}
// [0]=trigger [1]=grip [4]=X [5]=Y
if (gamepad.buttons != null) {
if (gamepad.buttons.length > 0) leftTrigger = gamepad.buttons[0].value;
if (gamepad.buttons.length > 1) leftGrip = gamepad.buttons[1].value;
if (gamepad.buttons.length > 4) leftButtonX = gamepad.buttons[4].pressed;
if (gamepad.buttons.length > 5) leftButtonY = gamepad.buttons[5].pressed;
}
}
}
else if (handedness == "right") {
rightHandPosition.set(pos.x, pos.y, pos.z);
rightHandRotation.set(orient.x, orient.y, orient.z, orient.w);
rightHandActive = true;
var gamepad = untyped inputSource.gamepad;
if (gamepad != null) {
if (gamepad.axes != null && gamepad.axes.length >= 2) {
rightThumbstickX = gamepad.axes[0];
rightThumbstickY = gamepad.axes[1];
}
if (gamepad.buttons != null) {
if (gamepad.buttons.length > 0) rightTrigger = gamepad.buttons[0].value;
if (gamepad.buttons.length > 1) rightGrip = gamepad.buttons[1].value;
if (gamepad.buttons.length > 4) rightButtonA = gamepad.buttons[4].pressed;
if (gamepad.buttons.length > 5) rightButtonB = gamepad.buttons[5].pressed;
}
}
}
}
}
}
#end

View File

@ -20,6 +20,7 @@ class Config {
var path = iron.data.Data.dataPath + "config.lnx"; var path = iron.data.Data.dataPath + "config.lnx";
var bytes = haxe.io.Bytes.ofString(haxe.Json.stringify(raw)); var bytes = haxe.io.Bytes.ofString(haxe.Json.stringify(raw));
#if kha_krom #if kha_krom
if (iron.data.Data.dataPath == '') path = Krom.getFilesLocation() + "/config.lnx";
Krom.fileSaveBytes(path, bytes.getData()); Krom.fileSaveBytes(path, bytes.getData());
#elseif kha_kore #elseif kha_kore
sys.io.File.saveBytes(path, bytes); sys.io.File.saveBytes(path, bytes);
@ -43,10 +44,12 @@ typedef TConfig = {
@:optional var rp_supersample: Null<Float>; @:optional var rp_supersample: Null<Float>;
@:optional var rp_shadowmap_cube: Null<Int>; // size @:optional var rp_shadowmap_cube: Null<Int>; // size
@:optional var rp_shadowmap_cascade: Null<Int>; // size for single cascade @:optional var rp_shadowmap_cascade: Null<Int>; // size for single cascade
@:optional var rp_ssao: Null<Bool>;
@:optional var rp_ssgi: Null<Bool>; @:optional var rp_ssgi: Null<Bool>;
@:optional var rp_ssr: Null<Bool>; @:optional var rp_ssr: Null<Bool>;
@:optional var rp_ssrefr: Null<Bool>; @:optional var rp_ssrefr: Null<Bool>;
@:optional var rp_bloom: Null<Bool>; @:optional var rp_bloom: Null<Bool>;
@:optional var rp_chromatic_aberration: Null<Bool>;
@:optional var rp_motionblur: Null<Bool>; @:optional var rp_motionblur: Null<Bool>;
@:optional var rp_gi: Null<Bool>; // voxelao @:optional var rp_gi: Null<Bool>; // voxelao
@:optional var rp_dynres: Null<Bool>; // dynamic resolution scaling @:optional var rp_dynres: Null<Bool>; // dynamic resolution scaling

View File

@ -0,0 +1,99 @@
package leenkx.logicnode;
import iron.data.SceneFormat.TSceneFormat;
import iron.data.Data;
import iron.object.Object;
class AddParticleToObjectNode extends LogicNode {
public var property0: String;
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
#if lnx_particles
if (property0 == 'Scene Active'){
var objFrom: Object = inputs[1].get();
var slot: Int = inputs[2].get();
var objTo: Object = inputs[3].get();
if (objFrom == null || objTo == null) return;
var mobjFrom = cast(objFrom, iron.object.MeshObject);
var psys = mobjFrom.particleSystems != null ? mobjFrom.particleSystems[slot] :
mobjFrom.particleOwner != null && mobjFrom.particleOwner.particleSystems != null ? mobjFrom.particleOwner.particleSystems[slot] : null;
if (psys == null) return;
var mobjTo = cast(objTo, iron.object.MeshObject);
mobjTo.setupParticleSystem(iron.Scene.active.raw.name, {name: 'LnxPS', seed: 0, particle: @:privateAccess psys.r.name});
mobjTo.render_emitter = inputs[4].get();
iron.Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
if (o != null) {
var c: iron.object.MeshObject = cast o;
if (mobjTo.particleChildren == null) mobjTo.particleChildren = [];
mobjTo.particleChildren.push(c);
c.particleOwner = mobjTo;
c.particleIndex = mobjTo.particleChildren.length - 1;
}
});
var oslot: Int = mobjTo.particleSystems.length-1;
var opsys = mobjTo.particleSystems[oslot];
@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
} else {
var sceneName: String = inputs[1].get();
var objectName: String = inputs[2].get();
var slot: Int = inputs[3].get();
var mobjTo: Object = inputs[4].get();
var mobjTo = cast(mobjTo, iron.object.MeshObject);
#if lnx_json
sceneName += ".json";
#elseif lnx_compress
sceneName += ".lz4";
#end
Data.getSceneRaw(sceneName, (rawScene: TSceneFormat) -> {
for (obj in rawScene.objects) {
if (obj.name == objectName) {
mobjTo.setupParticleSystem(sceneName, obj.particle_refs[slot]);
mobjTo.render_emitter = inputs[5].get();
iron.Scene.active.spawnObject(rawScene.particle_datas[slot].instance_object, null, function(o: Object) {
if (o != null) {
var c: iron.object.MeshObject = cast o;
if (mobjTo.particleChildren == null) mobjTo.particleChildren = [];
mobjTo.particleChildren.push(c);
c.particleOwner = mobjTo;
c.particleIndex = mobjTo.particleChildren.length - 1;
}
}, true, rawScene);
var oslot: Int = mobjTo.particleSystems.length-1;
var opsys = mobjTo.particleSystems[oslot];
@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
break;
}
}
});
}
#end
runOutput(0);
}
}

View File

@ -2,13 +2,16 @@ package leenkx.logicnode;
import iron.object.Object; import iron.object.Object;
#if lnx_bullet #if lnx_physics
import leenkx.trait.physics.PhysicsConstraint; import leenkx.trait.physics.PhysicsConstraint;
import leenkx.trait.physics.bullet.PhysicsConstraint.ConstraintType; #if lnx_bullet
#elseif lnx_oimo import leenkx.trait.physics.bullet.PhysicsConstraint.ConstraintType;
// TODO #elseif lnx_jolt
import leenkx.trait.physics.jolt.PhysicsConstraint.ConstraintType;
#else
import leenkx.trait.physics.oimo.PhysicsConstraint.ConstraintType;
#end
#end #end
class AddPhysicsConstraintNode extends LogicNode { class AddPhysicsConstraintNode extends LogicNode {
public var property0: String;//Type public var property0: String;//Type
@ -27,7 +30,7 @@ class AddPhysicsConstraintNode extends LogicNode {
if (pivotObject == null || rb1 == null || rb2 == null) return; if (pivotObject == null || rb1 == null || rb2 == null) return;
#if lnx_bullet #if lnx_physics
var disableCollisions: Bool = inputs[4].get(); var disableCollisions: Bool = inputs[4].get();
var breakable: Bool = inputs[5].get(); var breakable: Bool = inputs[5].get();
@ -110,8 +113,6 @@ class AddPhysicsConstraintNode extends LogicNode {
} }
pivotObject.addTrait(con); pivotObject.addTrait(con);
} }
#elseif lnx_oimo
// TODO
#end #end
runOutput(0); runOutput(0);
} }

View File

@ -0,0 +1,48 @@
package leenkx.logicnode;
import iron.object.Object;
#if lnx_physics
import leenkx.trait.physics.PhysicsCache;
import leenkx.trait.physics.RigidBody;
#end
class AnyContactNode extends LogicNode {
public var property0: String;
var lastContact = false;
public function new(tree: LogicTree) {
super(tree);
tree.notifyOnUpdate(update);
}
function update() {
var object1: Object = inputs[0].get();
if (object1 == null) object1 = tree.object;
if (object1 == null) return;
var contact = false;
#if lnx_physics
var rb1 = PhysicsCache.getCachedRigidBody(object1);
if (rb1 != null) {
var rbs = PhysicsCache.getCachedContacts(rb1);
contact = (rbs != null && rbs.length > 0);
}
#end
var shouldTrigger = false;
switch (property0) {
case "begin":
shouldTrigger = contact && !lastContact;
case "overlap":
shouldTrigger = contact;
case "end":
shouldTrigger = !contact && lastContact;
}
lastContact = contact;
if (shouldTrigger) runOutput(0);
}
}

View File

@ -0,0 +1,16 @@
package leenkx.logicnode;
class AutoExposureGetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
return switch (from) {
case 0: leenkx.renderpath.Postprocess.auto_exposure_uniforms[0];
case 1: leenkx.renderpath.Postprocess.auto_exposure_uniforms[1];
default: 0.0;
}
}
}

View File

@ -0,0 +1,15 @@
package leenkx.logicnode;
class AutoExposureSetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
leenkx.renderpath.Postprocess.auto_exposure_uniforms[0] = inputs[1].get();
leenkx.renderpath.Postprocess.auto_exposure_uniforms[1] = inputs[2].get();
runOutput(0);
}
}

View File

@ -1,26 +1,49 @@
package leenkx.logicnode; package leenkx.logicnode;
class CameraSetNode extends LogicNode { class CameraSetNode extends LogicNode {
public var property0: String;
public function new(tree:LogicTree) { public function new(tree:LogicTree) {
super(tree); super(tree);
} }
override function run(from:Int) { override function run(from:Int) {
leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number
leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[2].get();//Camera: Shutter time switch (property0) {
leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[3].get();//Camera: ISO case 'F-stop':
leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[4].get();//Camera: Exposure Compensation leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number
leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[5].get();//Fisheye Distortion case 'Shutter Time':
leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[6].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[1].get();//Camera: Shutter time
leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[7].get();//DoF Distance case 'ISO':
leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[8].get();//DoF Focal Length mm leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[1].get();//Camera: ISO
leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[9].get();//DoF F-Stop case 'Exposure Compensation':
leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[10].get();//Tonemapping Method leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[1].get();//Camera: Exposure Compensation
leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[11].get();//Distort case 'Fisheye Distortion':
leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[12].get();//Film Grain leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[1].get();//Fisheye Distortion
leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[13].get();//Sharpen case 'Auto Focus':
leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[14].get();//Vignette leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[1].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting
case 'DoF Distance':
leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[1].get();//DoF Distance
case 'DoF Length':
leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[1].get();//DoF Focal Length mm
case 'DoF F-Stop':
leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[1].get();//DoF F-Stop
case 'Tonemapping':
leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[1].get();//Tonemapping Method
case 'Distort':
leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[1].get();//Distort
case 'Film Grain':
leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[1].get();//Film Grain
case 'Sharpen':
leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[1].get();//Sharpen
case 'Vignette':
leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[1].get();//Vignette
case 'Exposure':
leenkx.renderpath.Postprocess.exposure_uniforms[0] = inputs[1].get();//Exposure
default:
null;
}
runOutput(0); runOutput(0);
} }

View File

@ -10,6 +10,7 @@ class ChromaticAberrationGetNode extends LogicNode {
return switch (from) { return switch (from) {
case 0: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0]; case 0: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0];
case 1: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1]; case 1: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1];
case 2: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2];
default: 0.0; default: 0.0;
} }
} }

View File

@ -10,6 +10,7 @@ class ChromaticAberrationSetNode extends LogicNode {
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0] = inputs[1].get(); leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0] = inputs[1].get();
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1] = inputs[2].get(); leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1] = inputs[2].get();
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2] = inputs[3].get();
runOutput(0); runOutput(0);
} }

View File

@ -37,86 +37,90 @@ class CreateLeenkxNode extends LogicNode {
function onEvent() { function onEvent() {
#if js #if js
var window:haxe.DynamicAccess<Dynamic> = untyped js.Browser.window; var lnxjs:Dynamic = js.Lib.global;
var lxCxNew = window.get('lxNew'); var lnxCxNew = lnxjs.lnxNew;
if (lnxCxNew == null) {
trace("ERROR: lnxNew not available");
return;
}
var lxCn:Dynamic = lxCxNew(net_Url); var lnxCn:Dynamic = lnxCxNew(net_Url);
lxCn.on("connections", function(c) { lnxCn.on("connections", function(c) {
leenkx.network.Leenkx.data.set(net_Url, c + 1); leenkx.network.Leenkx.data.set(net_Url, c + 1);
leenkx.network.Leenkx.connections[net_Url].onconnections(); leenkx.network.Leenkx.connections[net_Url].onconnections();
}); });
lxCn.on("message", function(address,message) { lnxCn.on("message", function(address, message) {
leenkx.network.Leenkx.data.set(net_Url, message); leenkx.network.Leenkx.data.set(net_Url, message);
leenkx.network.Leenkx.id.set(net_Url, address); leenkx.network.Leenkx.id.set(net_Url, address);
leenkx.network.Leenkx.connections[net_Url].onmessage(); leenkx.network.Leenkx.connections[net_Url].onmessage();
}); });
lxCn.on("seen", function(address) { lnxCn.on("seen", function(address) {
leenkx.network.Leenkx.id.set(net_Url, address); leenkx.network.Leenkx.id.set(net_Url, address);
leenkx.network.Leenkx.connections[net_Url].onseen(); leenkx.network.Leenkx.connections[net_Url].onseen();
}); });
lxCn.on("left", function(address) { lnxCn.on("left", function(address) {
leenkx.network.Leenkx.id.set(net_Url, address); leenkx.network.Leenkx.id.set(net_Url, address);
leenkx.network.Leenkx.connections[net_Url].onleft(); leenkx.network.Leenkx.connections[net_Url].onleft();
}); });
lxCn.on("server", function(address) { lnxCn.on("server", function(address) {
leenkx.network.Leenkx.id.set(net_Url, address); leenkx.network.Leenkx.id.set(net_Url, address);
leenkx.network.Leenkx.connections[net_Url].onserver(); leenkx.network.Leenkx.connections[net_Url].onserver();
}); });
lxCn.on("ping", function(address) { lnxCn.on("ping", function(address) {
leenkx.network.Leenkx.id.set(net_Url, address); leenkx.network.Leenkx.id.set(net_Url, address);
leenkx.network.Leenkx.connections[net_Url].onping(); leenkx.network.Leenkx.connections[net_Url].onping();
}); });
lxCn.on("timeout", function(address) { lnxCn.on("timeout", function(address) {
leenkx.network.Leenkx.id.set(net_Url, address); leenkx.network.Leenkx.id.set(net_Url, address);
leenkx.network.Leenkx.connections[net_Url].ontimeout(); leenkx.network.Leenkx.connections[net_Url].ontimeout();
}); });
lxCn.on("rpc", function(address, call, args, nonce) { lnxCn.on("rpc", function(address, call, args, nonce) {
leenkx.network.Leenkx.data.set(net_Url, call); leenkx.network.Leenkx.data.set(net_Url, call);
leenkx.network.Leenkx.id.set(net_Url, address); leenkx.network.Leenkx.id.set(net_Url, address);
call(args); call(args);
leenkx.network.Leenkx.connections[net_Url].onrpc(); leenkx.network.Leenkx.connections[net_Url].onrpc();
}); });
lxCn.on("rpc-response", function(address, nonce, response) { lnxCn.on("rpc-response", function(address, nonce, response) {
leenkx.network.Leenkx.id.set(net_Url, address); leenkx.network.Leenkx.id.set(net_Url, address);
leenkx.network.Leenkx.connections[net_Url].onrpcresponse(); leenkx.network.Leenkx.connections[net_Url].onrpcresponse();
}); });
lxCn.on("wireleft", function(wirecount, wire) { lnxCn.on("wireleft", function(wirecount, wire) {
leenkx.network.Leenkx.data.set(net_Url, wirecount); leenkx.network.Leenkx.data.set(net_Url, wirecount);
leenkx.network.Leenkx.id.set(net_Url, wire.peerId); leenkx.network.Leenkx.id.set(net_Url, wire.peerId);
leenkx.network.Leenkx.connections[net_Url].onwireleft(); leenkx.network.Leenkx.connections[net_Url].onwireleft();
}); });
lxCn.on("wireseen", function(wirecount, wire) { lnxCn.on("wireseen", function(wirecount, wire) {
leenkx.network.Leenkx.data.set(net_Url, wirecount); leenkx.network.Leenkx.data.set(net_Url, wirecount);
leenkx.network.Leenkx.id.set(net_Url, wire.peerId); leenkx.network.Leenkx.id.set(net_Url, wire.peerId);
leenkx.network.Leenkx.connections[net_Url].onwireseen(); leenkx.network.Leenkx.connections[net_Url].onwireseen();
}); });
lxCn.on("torrent", function(identifier, torrent) { lnxCn.on("torrent", function(identifier, torrent) {
leenkx.network.Leenkx.data.set(net_Url, torrent); leenkx.network.Leenkx.data.set(net_Url, torrent);
leenkx.network.Leenkx.id.set(net_Url, identifier); leenkx.network.Leenkx.id.set(net_Url, identifier);
leenkx.network.Leenkx.connections[net_Url].ontorrent(); leenkx.network.Leenkx.connections[net_Url].ontorrent();
}); });
lnxCn.on("tracker", function(identifier) {
lxCn.on("tracker", function(identifier) { leenkx.network.Leenkx.id.set(net_Url, identifier);
leenkx.network.Leenkx.id.set(net_Url, identifier); leenkx.network.Leenkx.connections[net_Url].ontracker();
leenkx.network.Leenkx.connections[net_Url].ontracker(); });
}); lnxCn.on("announce", function(identifier) {
leenkx.network.Leenkx.id.set(net_Url, identifier);
lxCn.on("announce", function(identifier) { leenkx.network.Leenkx.connections[net_Url].onannounce();
leenkx.network.Leenkx.id.set(net_Url, identifier); });
leenkx.network.Leenkx.connections[net_Url].onannounce();
}); Reflect.setField(lnxjs, "lnx_" + net_Url, lnxCn);
window.set("lx_" + net_Url, lxCn); Leenkx.connections[net_Url].client = lnxCn;
Leenkx.connections[net_Url].client = lxCn;
var script = ' var script = 'globalThis.addEventListener("beforeunload", function (e) {
window.addEventListener("beforeunload", function (e) { leenkx.network.Leenkx.connections.h["' + net_Url + '"].client.destroy();
leenkx.network.Leenkx.connections.h["' + net_Url + '"].client.destroy(); delete e["returnValue"];
delete e["returnValue"]; });';
}); js.Syntax.code('(1, eval)({0})', script);
';
js.Syntax.code('(1, eval)({0})', script.toString()); runOutput(0);
runOutput(0); #end
#end
} }

View File

@ -2,6 +2,9 @@ package leenkx.logicnode;
import iron.Scene; import iron.Scene;
import iron.object.CameraObject; import iron.object.CameraObject;
import iron.math.Vec4;
import iron.math.Quat;
import leenkx.math.Helper;
import leenkx.renderpath.RenderPathCreator; import leenkx.renderpath.RenderPathCreator;
@ -27,11 +30,19 @@ class DrawCameraTextureNode extends LogicNode {
final c = inputs[2].get(); final c = inputs[2].get();
assert(Error, Std.isOfType(c, CameraObject), "Camera must be a camera object!"); assert(Error, Std.isOfType(c, CameraObject), "Camera must be a camera object!");
cam = cast(c, CameraObject); cam = cast(c, CameraObject);
rt = kha.Image.createRenderTarget(iron.App.w(), iron.App.h()); rt = kha.Image.createRenderTarget(iron.App.w(), iron.App.h(),
kha.graphics4.TextureFormat.RGBA32,
kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
assert(Error, mo.materials[matSlot].contexts[0].textures != null, 'Object "${mo.name}" has no diffuse texture to render to'); assert(Error, mo.materials[matSlot].contexts[0].textures != null, 'Object "${mo.name}" has no diffuse texture to render to');
mo.materials[matSlot].contexts[0].textures[0] = rt; // Override diffuse texture
final n = inputs[5].get();
for (i => node in mo.materials[matSlot].contexts[0].raw.bind_textures){
if (node.name == n){
mo.materials[matSlot].contexts[0].textures[i] = rt; // Override diffuse texture
break;
}
}
tree.notifyOnRender(render); tree.notifyOnRender(render);
runOutput(0); runOutput(0);
@ -48,8 +59,20 @@ class DrawCameraTextureNode extends LogicNode {
iron.Scene.active.camera = cam; iron.Scene.active.camera = cam;
cam.renderTarget = rt; cam.renderTarget = rt;
#if kha_html5
var q: Quat = new Quat();
q.fromAxisAngle(new Vec4(0, 0, 1, 1), Helper.degToRad(180));
cam.transform.rot.mult(q);
cam.transform.buildMatrix();
#end
cam.renderFrame(g); cam.renderFrame(g);
#if kha_html5
cam.transform.rot.mult(q);
cam.transform.buildMatrix();
#end
cam.renderTarget = oldRT; cam.renderTarget = oldRT;
iron.Scene.active.camera = sceneCam; iron.Scene.active.camera = sceneCam;
} }

View File

@ -99,8 +99,6 @@ class DrawImageSequenceNode extends LogicNode {
final colorVec = inputs[4].get(); final colorVec = inputs[4].get();
g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w); g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
trace(currentImgIdx);
g.drawScaledImage(images[currentImgIdx], inputs[5].get(), inputs[6].get(), inputs[7].get(), inputs[8].get()); g.drawScaledImage(images[currentImgIdx], inputs[5].get(), inputs[6].get(), inputs[7].get(), inputs[8].get());
} }
} }

View File

@ -62,7 +62,7 @@ class DrawStringNode extends LogicNode {
override function get(from: Int): Dynamic { override function get(from: Int): Dynamic {
return from == 1 ? RenderToTexture.g.font.height(RenderToTexture.g.fontSize) : RenderToTexture.g.font.width(RenderToTexture.g.fontSize, string); return from == 1 ? RenderToTexture.g.font.width(RenderToTexture.g.fontSize, string) : RenderToTexture.g.font.height(RenderToTexture.g.fontSize);
} }
} }

View File

@ -0,0 +1,59 @@
package leenkx.logicnode;
import iron.math.Vec4;
import kha.Image;
import kha.Color;
import leenkx.renderpath.RenderToTexture;
class DrawSubImageNode extends LogicNode {
var img: Image;
var lastImgName = "";
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
RenderToTexture.ensure2DContext("DrawImageNode");
final imgName: String = inputs[1].get();
final colorVec: Vec4 = inputs[2].get();
final anchorH: Int = inputs[3].get();
final anchorV: Int = inputs[4].get();
final x: Float = inputs[5].get();
final y: Float = inputs[6].get();
final width: Float = inputs[7].get();
final height: Float = inputs[8].get();
final sx: Float = inputs[9].get();
final sy: Float = inputs[10].get();
final swidth: Float = inputs[11].get();
final sheight: Float = inputs[12].get();
final angle: Float = inputs[13].get();
final drawx = x - 0.5 * width * anchorH;
final drawy = y - 0.5 * height * anchorV;
final sdrawx = sx - 0.5 * swidth * anchorH;
final sdrawy = sy - 0.5 * sheight * anchorV;
RenderToTexture.g.rotate(angle, x, y);
if (imgName != lastImgName) {
// Load new image
lastImgName = imgName;
iron.data.Data.getImage(imgName, (image: Image) -> {
img = image;
});
}
if (img == null) {
runOutput(0);
return;
}
RenderToTexture.g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
RenderToTexture.g.drawScaledSubImage(img, sdrawx, sdrawy, swidth, sheight, drawx, drawy, width, height);
RenderToTexture.g.rotate(-angle, x, y);
runOutput(0);
}
}

View File

@ -0,0 +1,17 @@
package leenkx.logicnode;
import aura.Aura;
import aura.Types;
class GetAudioPositionNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
var audio = inputs[0].get();
if (audio == null || audio.channel == null) return 0.0;
return audio.channel.floatPosition / audio.channel.sampleRate;
}
}

View File

@ -0,0 +1,19 @@
package leenkx.logicnode;
import iron.object.MeshObject;
import iron.object.CameraObject;
class GetCameraRenderFilterNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
var mo: MeshObject = cast inputs[0].get();
if (mo == null) return null;
return mo.cameraList;
}
}

View File

@ -8,7 +8,7 @@ class GetFPSNode extends LogicNode {
override function get(from: Int): Dynamic { override function get(from: Int): Dynamic {
if (from == 0) { if (from == 0) {
var fps = Math.round(1 / iron.system.Time.realDelta); var fps = Math.round(1 / iron.system.Time.renderDelta);
if ((fps == Math.POSITIVE_INFINITY) || (fps == Math.NEGATIVE_INFINITY) || (Math.isNaN(fps))) { if ((fps == Math.POSITIVE_INFINITY) || (fps == Math.NEGATIVE_INFINITY) || (Math.isNaN(fps))) {
return 0; return 0;
} }

Some files were not shown because too many files have changed in this diff Show More