Compare commits
665 commits
Author | SHA1 | Date | |
---|---|---|---|
9220e6b57e | |||
15ec53830f | |||
946610c793 | |||
1430e22a90 | |||
07f4bea206 | |||
8581a75f9c | |||
6bb2513001 | |||
f581e91ba9 | |||
263d5853a5 | |||
1cec287891 | |||
83a60e7462 | |||
603d23fbfd | |||
03090cafa2 | |||
a1951bb66e | |||
3c0f580f69 | |||
8116729822 | |||
6c0d4bdead | |||
8f733222a9 | |||
4b65d8d68c | |||
13a2f4538a | |||
b7cafbb4e3 | |||
d4f9982768 | |||
8e69bea14e | |||
669898fae1 | |||
8df6fc9176 | |||
edeaf488b9 | |||
cb2cf0c9b4 | |||
4522055fac | |||
1d0eaf9371 | |||
e562d2515e | |||
8e7d8a4f56 | |||
6e153569dc | |||
d01c55fcd4 | |||
3814cd9da7 | |||
0636eb85c6 | |||
2f77c5b060 | |||
26a0fb8c5a | |||
8c034655be | |||
6f9b51a57a | |||
34243ed74c | |||
fb004f5dcc | |||
867100d151 | |||
09433f2a19 | |||
10d41e5eca | |||
b7941d2fa8 | |||
93563dbba5 | |||
9094154440 | |||
6ad9941d43 | |||
326d3bbf0d | |||
b2566a8249 | |||
18c5636d03 | |||
07cfa40727 | |||
e06ca4b9e7 | |||
ec1f25cfec | |||
1dc733ca88 | |||
f22542a0b4 | |||
c97c738870 | |||
130e470290 | |||
fabb4c0c3c | |||
ca03897811 | |||
6e255bcb05 | |||
f6dfc43dde | |||
36e42ad736 | |||
3df2916f5b | |||
59aca7ea41 | |||
297f7cdfca | |||
176ab43fd0 | |||
6b1333902c | |||
89ff1c29fc | |||
086c05eba2 | |||
3e6e1e4bd1 | |||
977b2db376 | |||
ebb3076431 | |||
826dbd786d | |||
4fe8f683dc | |||
b9b5c65141 | |||
ec3054cdeb | |||
d3b006c873 | |||
9c931aff56 | |||
622b8a275f | |||
ea9b01e733 | |||
34897c9747 | |||
c1f98dc668 | |||
67d511568f | |||
b8319fe28b | |||
d5e0208fd6 | |||
0fadefab69 | |||
50a1994867 | |||
b9a220fbcb | |||
5e1105f51d | |||
b060953a7e | |||
a4d09936d6 | |||
786e68e475 | |||
c7cba9d792 | |||
d9ddb5f4a3 | |||
8e8e8f586d | |||
e8fa3b1b9a | |||
7289b95a48 | |||
7f5d382131 | |||
ea02600d14 | |||
a2c33b2f6a | |||
c40fd26c20 | |||
308ab2d77b | |||
d979e4fde9 | |||
1c237dd6c3 | |||
152959699a | |||
259c375fda | |||
b579c8a15d | |||
73a352b76e | |||
957c5371c8 | |||
962f8a79a5 | |||
8604e670c3 | |||
d1d266a0f0 | |||
62d399e01a | |||
128efcc0ef | |||
3920c475be | |||
e3a55db813 | |||
597c291da7 | |||
16976cdc5b | |||
d1fe4d6686 | |||
ca966588ff | |||
0ce0c5c115 | |||
05465bcea1 | |||
77815d95ed | |||
156f1f433a | |||
5b4d24f067 | |||
c24389813f | |||
c398c1181e | |||
7d9d5ac50f | |||
eb5ef99309 | |||
62294c8bb4 | |||
ed6aa96fb0 | |||
f3fcb2846e | |||
afeecd4df1 | |||
de72bbf3a4 | |||
ecc4317919 | |||
667e73c867 | |||
56d84b08f4 | |||
adb2468245 | |||
abc52627a3 | |||
68ef00b668 | |||
55cfead084 | |||
fe6d1fa372 | |||
974181e75e | |||
a4ab1dcc98 | |||
ccbc946bf1 | |||
fddef0983c | |||
e715bf0108 | |||
214b84fcf7 | |||
32b745f829 | |||
8caf859db9 | |||
d6692efbdc | |||
c77eea93fa | |||
e0cbf1b332 | |||
b7024a5854 | |||
44d8325001 | |||
052c7b00c5 | |||
675618e529 | |||
a6b67e4e00 | |||
4b75a896d6 | |||
ecddc0af92 | |||
e05d556552 | |||
85edde6d24 | |||
703c618c7d | |||
df715db381 | |||
a8a44df249 | |||
1eb087125f | |||
2347348504 | |||
3e22cb3375 | |||
4e526a6dd3 | |||
2630c159d8 | |||
a67452802d | |||
f892fdfd8a | |||
29785172f4 | |||
1d0a6d7955 | |||
7b6d3536e3 | |||
f017d68ed7 | |||
1de97e1898 | |||
ca96174b6b | |||
bd67667a6e | |||
2910fcf1a8 | |||
c56a0c3a72 | |||
d610cc6a2f | |||
34f6e0fc7c | |||
45e3c1c138 | |||
c49bece460 | |||
2ef4f19eb7 | |||
5509096158 | |||
2d3e15064a | |||
386d2a3bf4 | |||
7607cc8ccd | |||
52a594c910 | |||
4c4bebcf4f | |||
ea8c13686c | |||
4c34c2a5ce | |||
b664e3a010 | |||
60d0f443f8 | |||
aeffd76b75 | |||
1532a332ff | |||
4fc1f38b3b | |||
5f2dce140e | |||
13cf22ecc2 | |||
9f7af6a1cd | |||
9ec425f6ae | |||
3bad878650 | |||
ce75516c59 | |||
bce14549ac | |||
ee208ece18 | |||
549040fc09 | |||
62ff11747b | |||
6a3045477f | |||
8a758bbe26 | |||
ffee6dc521 | |||
cca82a69bf | |||
c52d25e471 | |||
cf1dd0ac71 | |||
8e1aa2fb0d | |||
6d2b825dd5 | |||
6050bceaf1 | |||
dbb0764ca7 | |||
568f4f3a6d | |||
0a58279756 | |||
ff5fd9c7ed | |||
0456d5f080 | |||
af520b518e | |||
82c7302dd9 | |||
2b6a7a4f78 | |||
7eced3b4f5 | |||
aa21402221 | |||
97cc737aff | |||
256d27e289 | |||
9ff726bac1 | |||
5276711094 | |||
4f13ebc439 | |||
1edc7a9469 | |||
3ed915b654 | |||
e930da7388 | |||
c65764be99 | |||
bdee03873b | |||
1b758ec32c | |||
cfa941eab4 | |||
9b1393ea41 | |||
bfde181da6 | |||
a59c789528 | |||
caa03b59c5 | |||
ff93e5f824 | |||
b3162d8f6e | |||
823cc379b6 | |||
ee194a1806 | |||
96aa0ee890 | |||
c0333db44f | |||
e0ff256f40 | |||
28d21bf35f | |||
b452acaebb | |||
3c88ddcb23 | |||
db5aed465e | |||
55cf2896a2 | |||
daee309ad8 | |||
43a574eb15 | |||
919512fad0 | |||
14b18408aa | |||
801668a0c2 | |||
dc6753c2ca | |||
6dd27bfeed | |||
e7da337530 | |||
50c8ceec1e | |||
a6ec652d5f | |||
cb800729d2 | |||
4e19ddfeb0 | |||
b2153dbcd2 | |||
4387d774cc | |||
738a217001 | |||
9e493f6e79 | |||
7504d5d92b | |||
e308d9058b | |||
c7e1f5d0a9 | |||
202138304a | |||
8c0b6ba13e | |||
7515a20d93 | |||
3d49edee71 | |||
34b816b4d9 | |||
13c1e0508d | |||
f940e8566e | |||
dfad6902af | |||
441f42383e | |||
616a0e230d | |||
20540ccb11 | |||
31a2c9c4d3 | |||
ac48fd0bc9 | |||
f2cf3bdeda | |||
112c00a649 | |||
ee43724b97 | |||
5a2f952f89 | |||
936f11ed8e | |||
eab7fcbbe6 | |||
5a591fa15a | |||
975ec76f38 | |||
340f7e8af4 | |||
fa44147ee6 | |||
c44e2cf555 | |||
15da6ccf58 | |||
39922bc0f3 | |||
ea4f88aca8 | |||
39bd32f9d3 | |||
e744fd901c | |||
dbd348ad5d | |||
f542dc00ca | |||
aaa21bc019 | |||
a9f430c374 | |||
6cf3299ffe | |||
a588396dea | |||
dc34e48c52 | |||
fce97a5ddf | |||
d18aede964 | |||
66856e7ecc | |||
ebfbb68bb4 | |||
3c1264378b | |||
cbcc3e4e04 | |||
f45304ea10 | |||
dd13cc31b7 | |||
a5fa3445d9 | |||
1ece052aee | |||
24d917ae6a | |||
3288c3dcf5 | |||
251ad8e47e | |||
b2619828eb | |||
6c6d7c1419 | |||
0e6ba5b0b0 | |||
107dc730f4 | |||
b72e85894a | |||
20f9f8a5f4 | |||
5eb8fc781f | |||
70cb5ea421 | |||
ccc427c04a | |||
6d37095014 | |||
7057ec4ba6 | |||
138386f02a | |||
bdc2d91c1e | |||
7b5294121d | |||
9330090179 | |||
88f522c27b | |||
11da953407 | |||
494e2336ac | |||
20c6c52ae6 | |||
088bc0f666 | |||
a35cab5482 | |||
03baa49ecd | |||
c53d04374d | |||
43e145c3da | |||
6ded7e61f4 | |||
e7c1855b81 | |||
86316a10bd | |||
646d3a74cf | |||
5ed5b8d6a7 | |||
9fbc3d6cd4 | |||
7b2961459c | |||
3d46910530 | |||
68825516c9 | |||
07ffe06c1d | |||
3b72fff76d | |||
1945439cd1 | |||
98eeccd71d | |||
d31303391f | |||
590afcc573 | |||
30b2093b94 | |||
2f1fe4ef0b | |||
57093c34cd | |||
2c761b2ff6 | |||
4db37ea1c1 | |||
df372e9523 | |||
5b6875947c | |||
badc8853b4 | |||
1ebe528417 | |||
c185882db8 | |||
0085f6fbd7 | |||
04909603ec | |||
22a557162f | |||
ad9c7bfa6b | |||
6d52238db3 | |||
939649f492 | |||
ddc3da7799 | |||
a4e9ad945b | |||
41c6924231 | |||
9247b09c88 | |||
bb5ff191b7 | |||
df50ba397e | |||
97b578d0ed | |||
8a364259db | |||
6d4952624a | |||
1955edf01c | |||
eb01b4652a | |||
c21d17d04e | |||
069a9288ea | |||
da41d1fb17 | |||
00af258b14 | |||
c01b079cf1 | |||
e1cfa2f1da | |||
6fbee167ab | |||
78e266f77b | |||
1df882cad1 | |||
cf56c4f1d8 | |||
a3ca487183 | |||
63716eea17 | |||
614385ea7b | |||
69207a6289 | |||
766e26a7df | |||
316eafd286 | |||
f64419dd06 | |||
c9182cc152 | |||
899411dea4 | |||
b930b87bc9 | |||
34f08e6922 | |||
656b018e5f | |||
c5be90d0b0 | |||
ffcc5fcceb | |||
67110c15a9 | |||
ead7dc9d32 | |||
4a784c70a8 | |||
44f08a16ae | |||
de8073732a | |||
420033c86d | |||
845d2aff93 | |||
8118733474 | |||
8d812548c4 | |||
05c14238f2 | |||
24093d15df | |||
930b2968fa | |||
6e0bfa272c | |||
dfe1a49f85 | |||
0cc2ea4491 | |||
5c1f8fe128 | |||
07741abc55 | |||
362fffa408 | |||
fb56d85d02 | |||
eb6d23fab3 | |||
dc81aca823 | |||
d88d2320ed | |||
7851abc491 | |||
54fcd49c27 | |||
451e3484f0 | |||
8df7f66872 | |||
57660631b5 | |||
d4463a3611 | |||
a778460d28 | |||
255921b9ee | |||
5fe816d16a | |||
ef8fb21536 | |||
4b593af4ee | |||
ca2c3e151a | |||
1ad1d564bd | |||
7d78e01bb4 | |||
95af8f2f77 | |||
71a5ac6f6e | |||
c7211542b4 | |||
7463de6140 | |||
efcef7dd25 | |||
26c29fe15e | |||
b7fef30b70 | |||
4ad68304e5 | |||
7d9c6ce7c7 | |||
404a1248a1 | |||
8e972f75fd | |||
5f55b00710 | |||
b1a412cfc7 | |||
e5d6c47e3e | |||
4009d9d3fe | |||
7c56ee9304 | |||
70c46407c3 | |||
72dde10fb0 | |||
cf99e5a382 | |||
5f8b92f9c3 | |||
c07de1cc25 | |||
4dbf8a3b2a | |||
4ea5156f1e | |||
3e15ed9b5c | |||
91a10bea5c | |||
31f1b58c07 | |||
742b9ce1e1 | |||
dbee605e3f | |||
d20656339b | |||
e7ca541b51 | |||
f99ff0576d | |||
92554876f1 | |||
aec10274f4 | |||
f1858550d0 | |||
352f37db0c | |||
a1fce84f59 | |||
a25c5a744b | |||
98481929df | |||
c5855ad96f | |||
0abb43f249 | |||
d93de12252 | |||
325f7471c0 | |||
b7c4a8bb3f | |||
d4ee144577 | |||
8bc831d7e2 | |||
84663bc981 | |||
6beb9efb88 | |||
02e9ff7c5c | |||
3ef380978e | |||
0ee35adc81 | |||
49a599dc66 | |||
6d8012b45c | |||
702436e2a1 | |||
28011bcc00 | |||
726e2fec6d | |||
6cbe539098 | |||
a2e4850b12 | |||
b4d5afd561 | |||
b70a60078b | |||
52e4aaa21c | |||
3260e627ce | |||
c64b47548e | |||
1c3e24a8fd | |||
f0d7effb7c | |||
afe133381c | |||
6ffa58fb6b | |||
cbb8ee4bae | |||
f2c16097d4 | |||
d0e92b927b | |||
121d449c35 | |||
75bb88831c | |||
129d59ab54 | |||
4ee1131f6e | |||
4273aff1fb | |||
74b99411df | |||
725520081a | |||
6ef1195816 | |||
0fdb516083 | |||
a1bbd76de7 | |||
e3f992b1f3 | |||
05307817ee | |||
d55f889a84 | |||
1d79708b22 | |||
ba62ba0285 | |||
d7e70c4c0a | |||
6ae76bfdf6 | |||
6b6dc6264f | |||
888fb5c376 | |||
8619006757 | |||
288ead64dc | |||
396e60574a | |||
22d3530863 | |||
562d39c203 | |||
ffd3d6e824 | |||
7b55f3d8f5 | |||
f2e2a3d7dd | |||
41657adb64 | |||
fb8a056394 | |||
ee1b55184c | |||
fa7f58e4dd | |||
04fdcc5500 | |||
820de42e83 | |||
fb88361c5b | |||
b7903dbef1 | |||
40efd58214 | |||
b4f0df6367 | |||
133777f7e5 | |||
406d48eb7c | |||
4c0f0f4161 | |||
a98559ea7f | |||
1b9f010c57 | |||
0a5c209dd9 | |||
081fcb2870 | |||
9bab721f5f | |||
4920098831 | |||
4f25af45ba | |||
c69774402c | |||
70041fe2a5 | |||
e742ca76c0 | |||
833b513969 | |||
ad12af6933 | |||
80ea09671c | |||
c5e9522442 | |||
bf7592ae32 | |||
b7dc297d04 | |||
cab20d0a64 | |||
ae057508ca | |||
bc36bf571e | |||
24f62623ad | |||
27521265df | |||
5838401cd9 | |||
97582968bd | |||
c2bf021770 | |||
14bca0ec80 | |||
4862054bcf | |||
52cee7f0ce | |||
257f295b27 | |||
a647263d1a | |||
6a6d383970 | |||
11591c79a4 | |||
96dfc06295 | |||
93dc0d248b | |||
18070621db | |||
b05f719392 | |||
893b313643 | |||
3e819d7e99 | |||
174ce72349 | |||
4ee36afc0c | |||
2dcd1a951b | |||
268a59a4c7 | |||
a0422d49f2 | |||
569b2daecc | |||
f836e597d1 | |||
372419c9ff | |||
70b989e25f | |||
3d69855935 | |||
6ee5af2518 | |||
61986dfafd | |||
15d832c66c | |||
df522516f2 | |||
76b2380ec4 | |||
fa6d1903c7 | |||
563c04f456 | |||
f68debf39a | |||
3f1200417c | |||
0bda1abfb7 | |||
397d860a5a | |||
d7e5d07e52 | |||
2f911c756e | |||
bf22d7add6 | |||
570de6f699 | |||
8c1baa2e9a | |||
a89e3923e7 | |||
882dea8d6c | |||
e2231c7f16 | |||
1b6d321eaa | |||
76389c8652 | |||
b03e15edba | |||
62dbc5f34a | |||
f69185a765 | |||
c0bde50306 | |||
9f35d55bd3 | |||
fdcdf86c24 | |||
bcfbdae925 | |||
16700de7f0 | |||
10587900d4 | |||
71763f9e47 | |||
8a1b59ef8b | |||
c845301f7c | |||
c250be4735 | |||
300f5e37ea | |||
aab7a027c6 | |||
d87be744b2 | |||
e2511fd460 | |||
02e52341a5 | |||
ca9be33152 | |||
951f8298b8 | |||
174a7f66dd | |||
49e06b4b63 | |||
01874e2287 | |||
bd5953c39f | |||
1b210d0f00 | |||
332d60547b | |||
16376dafe2 | |||
0bddfea5e3 | |||
b5e33062b3 | |||
1fb1196979 | |||
e53d9446e7 | |||
90daf7e077 | |||
d726e8fc83 | |||
9ce721103e | |||
59c31950c8 | |||
bd6078e303 | |||
1867975099 |
|
@ -4,7 +4,9 @@
|
|||
|
||||
uniform sampler2D tex;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp10;
|
||||
#endif
|
||||
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"links": [
|
||||
{
|
||||
"name": "PPComp10",
|
||||
"link": "_PPComp10"
|
||||
"link": "_PPComp10",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
|
|
@ -7,7 +7,9 @@ uniform sampler2D tex;
|
|||
uniform vec2 dir;
|
||||
uniform vec2 screenSize;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp11;
|
||||
#endif
|
||||
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
@ -26,7 +28,7 @@ void main() {
|
|||
fragColor.rgb += textureLod(tex, texCoord + s, 0.0).rgb * weight[i];
|
||||
fragColor.rgb += textureLod(tex, texCoord - s, 0.0).rgb * weight[i];
|
||||
}
|
||||
|
||||
|
||||
#ifdef _CPostprocess
|
||||
fragColor.rgb *= PPComp11.x / 5;
|
||||
#else
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
},
|
||||
{
|
||||
"name": "PPComp11",
|
||||
"link": "_PPComp11"
|
||||
"link": "_PPComp11",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
@ -39,7 +40,8 @@
|
|||
},
|
||||
{
|
||||
"name": "PPComp11",
|
||||
"link": "_PPComp11"
|
||||
"link": "_PPComp11",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
@ -65,7 +67,8 @@
|
|||
},
|
||||
{
|
||||
"name": "PPComp11",
|
||||
"link": "_PPComp11"
|
||||
"link": "_PPComp11",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
#include "compiled.inc"
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp13;
|
||||
#endif
|
||||
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
"links": [
|
||||
{
|
||||
"name": "PPComp13",
|
||||
"link": "_PPComp13"
|
||||
"link": "_PPComp13",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
|
31
Shaders/custom_mat_presets/custom_mat_deferred.frag.glsl
Normal file
31
Shaders/custom_mat_presets/custom_mat_deferred.frag.glsl
Normal file
|
@ -0,0 +1,31 @@
|
|||
#version 450
|
||||
|
||||
// Include functions for gbuffer operations (packFloat2() etc.)
|
||||
#include "../std/gbuffer.glsl"
|
||||
|
||||
// World-space normal from the vertex shader stage
|
||||
in vec3 wnormal;
|
||||
|
||||
// Gbuffer output. Deferred rendering uses the following layout:
|
||||
// [0]: normal x normal y roughness metallic/matID
|
||||
// [1]: base color r base color g base color b occlusion/specular
|
||||
out vec4 fragColor[2];
|
||||
|
||||
void main() {
|
||||
// Pack normals into 2 components to fit into the gbuffer
|
||||
vec3 n = normalize(wnormal);
|
||||
n /= (abs(n.x) + abs(n.y) + abs(n.z));
|
||||
n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);
|
||||
|
||||
// Define PBR material values
|
||||
vec3 basecol = vec3(1.0);
|
||||
float roughness = 0.0;
|
||||
float metallic = 0.0;
|
||||
float occlusion = 1.0;
|
||||
float specular = 1.0;
|
||||
uint materialId = 0;
|
||||
|
||||
// Store in gbuffer (see layout table above)
|
||||
fragColor[0] = vec4(n.xy, roughness, packFloatInt16(metallic, materialId));
|
||||
fragColor[1] = vec4(basecol.rgb, packFloat2(occlusion, specular));
|
||||
}
|
20
Shaders/custom_mat_presets/custom_mat_deferred.vert.glsl
Normal file
20
Shaders/custom_mat_presets/custom_mat_deferred.vert.glsl
Normal file
|
@ -0,0 +1,20 @@
|
|||
#version 450
|
||||
|
||||
// World to view projection matrix to correctly position the vertex on screen
|
||||
uniform mat4 WVP;
|
||||
// Matrix to transform normals from local into world space
|
||||
uniform mat3 N;
|
||||
|
||||
// Position and normal vectors of the current vertex in local space
|
||||
// Armory packs the vertex data to preserve memory, so nor.z values are
|
||||
// saved in pos.w
|
||||
in vec4 pos; // pos.xyz, nor.w
|
||||
in vec2 nor; // nor.xy
|
||||
|
||||
// Normal vector in world space
|
||||
out vec3 wnormal;
|
||||
|
||||
void main() {
|
||||
wnormal = normalize(N * vec3(nor.xy, pos.w));
|
||||
gl_Position = WVP * vec4(pos.xyz, 1.0);
|
||||
}
|
9
Shaders/custom_mat_presets/custom_mat_forward.frag.glsl
Normal file
9
Shaders/custom_mat_presets/custom_mat_forward.frag.glsl
Normal file
|
@ -0,0 +1,9 @@
|
|||
#version 450
|
||||
|
||||
// Color of each fragment on the screen
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
// Shadeless white color
|
||||
fragColor = vec4(1.0);
|
||||
}
|
11
Shaders/custom_mat_presets/custom_mat_forward.vert.glsl
Normal file
11
Shaders/custom_mat_presets/custom_mat_forward.vert.glsl
Normal file
|
@ -0,0 +1,11 @@
|
|||
#version 450
|
||||
|
||||
// World to view projection matrix to correctly position the vertex on screen
|
||||
uniform mat4 WVP;
|
||||
|
||||
// Position vector of the current vertex in local space
|
||||
in vec3 pos;
|
||||
|
||||
void main() {
|
||||
gl_Position = WVP * vec4(pos, 1.0);
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include "compiled.inc"
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/light.glsl"
|
||||
#ifdef _Clusters
|
||||
#include "std/clusters.glsl"
|
||||
#endif
|
||||
|
@ -22,6 +21,9 @@
|
|||
uniform sampler2D gbufferD;
|
||||
uniform sampler2D gbuffer0;
|
||||
uniform sampler2D gbuffer1;
|
||||
#ifdef _gbuffer2
|
||||
uniform sampler2D gbuffer2;
|
||||
#endif
|
||||
|
||||
#ifdef _VoxelAOvar
|
||||
uniform sampler3D voxels;
|
||||
|
@ -80,14 +82,11 @@ uniform mat4 invVP;
|
|||
#ifdef _ShadowMap
|
||||
#ifdef _SinglePoint
|
||||
//!uniform sampler2DShadow shadowMapSpot[1];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot[1];
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot1;
|
||||
//!uniform mat4 LWVPSpot2;
|
||||
//!uniform mat4 LWVPSpot3;
|
||||
//!uniform mat4 LWVPSpotArray[4];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -97,7 +96,7 @@ uniform vec3 eye;
|
|||
uniform vec3 eyeLook;
|
||||
|
||||
#ifdef _Clusters
|
||||
uniform vec4 lightsArray[maxLights * 2];
|
||||
uniform vec4 lightsArray[maxLights * 3];
|
||||
#ifdef _Spot
|
||||
uniform vec4 lightsArraySpot[maxLights];
|
||||
#endif
|
||||
|
@ -109,21 +108,36 @@ uniform vec2 cameraPlane;
|
|||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
//!uniform sampler2DShadow shadowMapSpot[1];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot[1];
|
||||
#else
|
||||
//!uniform samplerCubeShadow shadowMapPoint[1];
|
||||
//!uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
//!uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifdef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlas;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
#endif
|
||||
//!uniform vec4 pointLightDataArray[4];
|
||||
#else
|
||||
//!uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#endif
|
||||
//!uniform vec2 lightProj;
|
||||
#ifdef _Spot
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot1;
|
||||
//!uniform mat4 LWVPSpot2;
|
||||
//!uniform mat4 LWVPSpot3;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
#endif
|
||||
#else
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
#endif
|
||||
//!uniform mat4 LWVPSpotArray[4];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -132,7 +146,13 @@ uniform vec2 cameraPlane;
|
|||
uniform vec3 sunDir;
|
||||
uniform vec3 sunCol;
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSun;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMap;
|
||||
#endif
|
||||
uniform float shadowsBias;
|
||||
#ifdef _CSM
|
||||
//!uniform vec4 casData[shadowmapCascades * 4 + 4];
|
||||
|
@ -159,6 +179,8 @@ uniform sampler2D texClouds;
|
|||
uniform float time;
|
||||
#endif
|
||||
|
||||
#include "std/light.glsl"
|
||||
|
||||
in vec2 texCoord;
|
||||
in vec3 viewRay;
|
||||
out vec4 fragColor;
|
||||
|
@ -186,6 +208,10 @@ void main() {
|
|||
vec3 v = normalize(eye - p);
|
||||
float dotNV = max(dot(n, v), 0.0);
|
||||
|
||||
#ifdef _gbuffer2
|
||||
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
|
||||
#endif
|
||||
|
||||
#ifdef _MicroShadowing
|
||||
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
|
||||
#endif
|
||||
|
@ -196,9 +222,19 @@ void main() {
|
|||
|
||||
// Envmap
|
||||
#ifdef _Irr
|
||||
|
||||
vec3 envl = shIrradiance(n, shirr);
|
||||
|
||||
#ifdef _gbuffer2
|
||||
if (g2.b < 0.5) {
|
||||
envl = envl;
|
||||
} else {
|
||||
envl = vec3(1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _EnvTex
|
||||
envl /= PI;
|
||||
envl /= PI;
|
||||
#endif
|
||||
#else
|
||||
vec3 envl = vec3(1.0);
|
||||
|
@ -289,10 +325,32 @@ void main() {
|
|||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _CSM
|
||||
svisibility = shadowTestCascade(shadowMap, eye, p + n * shadowsBias * 10, shadowsBias);
|
||||
svisibility = shadowTestCascade(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
, eye, p + n * shadowsBias * 10, shadowsBias
|
||||
);
|
||||
#else
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
if (lPos.w > 0.0) svisibility = shadowTest(shadowMap, lPos.xyz / lPos.w, shadowsBias);
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
if (lPos.w > 0.0) svisibility = shadowTest(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, shadowsBias
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -335,7 +393,18 @@ void main() {
|
|||
int casi, casindex;
|
||||
mat4 LWVP = getCascadeMat(distance(eye, p), casi, casindex);
|
||||
#endif
|
||||
fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVP, p, n, sunDir, lightPlane.y, shadowMap);
|
||||
fragColor.rgb += fragColor.rgb * SSSSTransmittance(
|
||||
LWVP, p, n, sunDir, lightPlane.y,
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -393,18 +462,19 @@ void main() {
|
|||
n,
|
||||
v,
|
||||
dotNV,
|
||||
lightsArray[li * 2].xyz, // lp
|
||||
lightsArray[li * 2 + 1].xyz, // lightCol
|
||||
lightsArray[li * 3].xyz, // lp
|
||||
lightsArray[li * 3 + 1].xyz, // lightCol
|
||||
albedo,
|
||||
roughness,
|
||||
occspec.y,
|
||||
f0
|
||||
#ifdef _ShadowMap
|
||||
, li, lightsArray[li * 2].w, true // bias
|
||||
// light index, shadow bias, cast_shadows
|
||||
, li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
, li > numPoints - 1
|
||||
, lightsArray[li * 2 + 1].w // cutoff
|
||||
, lightsArray[li * 3 + 2].y != 0.0
|
||||
, lightsArray[li * 3 + 2].y // cutoff
|
||||
, lightsArraySpot[li].w // cutoff - exponent
|
||||
, lightsArraySpot[li].xyz // spotDir
|
||||
#endif
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
},
|
||||
{
|
||||
"name": "LWVP",
|
||||
"link": "_biasLightWorldViewProjectionMatrix",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSun",
|
||||
"ifndef": ["_CSM"],
|
||||
"ifdef": ["_Sun", "_ShadowMap"]
|
||||
},
|
||||
|
@ -199,43 +199,37 @@
|
|||
"ifdef": ["_SinglePoint", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot0",
|
||||
"name": "LWVPSpotArray",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpotArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "pointLightDataArray",
|
||||
"link": "_pointLightsAtlasArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_ShadowMapAtlas"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot[0]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot0",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot1",
|
||||
"name": "LWVPSpot[1]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot1",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot2",
|
||||
"name": "LWVPSpot[2]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot2",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot3",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot0",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot0",
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot1",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot1",
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot2",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot2",
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot3",
|
||||
"name": "LWVPSpot[3]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
}
|
||||
],
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "compiled.inc"
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/math.glsl"
|
||||
#include "std/light_mobile.glsl"
|
||||
#ifdef _Clusters
|
||||
#include "std/clusters.glsl"
|
||||
#endif
|
||||
|
@ -30,12 +29,15 @@ uniform int envmapNumMipmaps;
|
|||
uniform vec3 backgroundCol;
|
||||
#endif
|
||||
|
||||
#ifdef _SMSizeUniform
|
||||
//!uniform vec2 smSizeUniform;
|
||||
#endif
|
||||
uniform vec2 cameraProj;
|
||||
uniform vec3 eye;
|
||||
uniform vec3 eyeLook;
|
||||
|
||||
#ifdef _Clusters
|
||||
uniform vec4 lightsArray[maxLights * 2];
|
||||
uniform vec4 lightsArray[maxLights * 3];
|
||||
#ifdef _Spot
|
||||
uniform vec4 lightsArraySpot[maxLights];
|
||||
#endif
|
||||
|
@ -47,21 +49,36 @@ uniform vec2 cameraPlane;
|
|||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
//!uniform sampler2DShadow shadowMapSpot[1];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot[1];
|
||||
#else
|
||||
//!uniform samplerCubeShadow shadowMapPoint[1];
|
||||
//!uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
//!uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifdef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlas;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
#endif
|
||||
//!uniform vec4 pointLightDataArray[4];
|
||||
#else
|
||||
//!uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#endif
|
||||
//!uniform vec2 lightProj;
|
||||
#ifdef _Spot
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot1;
|
||||
//!uniform mat4 LWVPSpot2;
|
||||
//!uniform mat4 LWVPSpot3;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
#endif
|
||||
#else
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
#endif
|
||||
//!uniform mat4 LWVPSpotArray[4];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -70,7 +87,13 @@ uniform vec2 cameraPlane;
|
|||
uniform vec3 sunDir;
|
||||
uniform vec3 sunCol;
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSun;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMap;
|
||||
#endif
|
||||
uniform float shadowsBias;
|
||||
#ifdef _CSM
|
||||
//!uniform vec4 casData[shadowmapCascades * 4 + 4];
|
||||
|
@ -90,6 +113,8 @@ uniform float pointBias;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include "std/light_mobile.glsl"
|
||||
|
||||
in vec2 texCoord;
|
||||
in vec3 viewRay;
|
||||
out vec4 fragColor;
|
||||
|
@ -168,10 +193,32 @@ void main() {
|
|||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _CSM
|
||||
svisibility = shadowTestCascade(shadowMap, eye, p + n * shadowsBias * 10, shadowsBias, shadowmapSize * vec2(shadowmapCascades, 1.0));
|
||||
svisibility = shadowTestCascade(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
, eye, p + n * shadowsBias * 10, shadowsBias
|
||||
);
|
||||
#else
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
if (lPos.w > 0.0) svisibility = shadowTest(shadowMap, lPos.xyz / lPos.w, shadowsBias, shadowmapSize);
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
if (lPos.w > 0.0) svisibility = shadowTest(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, shadowsBias
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -211,18 +258,19 @@ void main() {
|
|||
n,
|
||||
v,
|
||||
dotNV,
|
||||
lightsArray[li * 2].xyz, // lp
|
||||
lightsArray[li * 2 + 1].xyz, // lightCol
|
||||
lightsArray[li * 3].xyz, // lp
|
||||
lightsArray[li * 3 + 1].xyz, // lightCol
|
||||
albedo,
|
||||
roughness,
|
||||
occspec.y,
|
||||
f0
|
||||
#ifdef _ShadowMap
|
||||
, li, lightsArray[li * 2].w, true // bias
|
||||
// light index, shadow bias, cast_shadows
|
||||
, li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
, li > numPoints - 1
|
||||
, lightsArray[li * 2 + 1].w // cutoff
|
||||
, lightsArray[li * 3 + 2].y != 0.0
|
||||
, lightsArray[li * 3 + 2].y // cutoff
|
||||
, lightsArraySpot[li].w // cutoff - exponent
|
||||
, lightsArraySpot[li].xyz // spotDir
|
||||
#endif
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
},
|
||||
{
|
||||
"name": "LWVP",
|
||||
"link": "_biasLightWorldViewProjectionMatrix",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSun",
|
||||
"ifndef": ["_CSM"],
|
||||
"ifdef": ["_Sun", "_ShadowMap"]
|
||||
},
|
||||
|
@ -107,6 +107,11 @@
|
|||
"link": "_viewProjectionMatrix",
|
||||
"ifdef": ["_SSRS"]
|
||||
},
|
||||
{
|
||||
"name": "smSizeUniform",
|
||||
"link": "_shadowMapSize",
|
||||
"ifdef": ["_SMSizeUniform"]
|
||||
},
|
||||
{
|
||||
"name": "lightProj",
|
||||
"link": "_lightPlaneProj",
|
||||
|
@ -138,24 +143,38 @@
|
|||
"ifdef": ["_SinglePoint", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot0",
|
||||
"name": "LWVPSpotArray",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpotArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "pointLightDataArray",
|
||||
"link": "_pointLightsAtlasArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_ShadowMapAtlas"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot[0]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot0",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot1",
|
||||
"name": "LWVPSpot[1]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot1",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot2",
|
||||
"name": "LWVPSpot[2]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot2",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot3",
|
||||
"name": "LWVPSpot[3]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
}
|
||||
],
|
||||
"vertex_shader": "../include/pass_viewray.vert.glsl",
|
||||
|
|
|
@ -12,8 +12,10 @@ uniform vec3 eyeLook;
|
|||
uniform vec2 screenSize;
|
||||
uniform mat4 invVP;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp11;
|
||||
uniform vec3 PPComp12;
|
||||
#endif
|
||||
|
||||
in vec2 texCoord;
|
||||
in vec3 viewRay;
|
||||
|
@ -23,12 +25,12 @@ void main() {
|
|||
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
||||
if (depth == 1.0) { fragColor = 1.0; return; }
|
||||
|
||||
vec2 enc = textureLod(gbuffer0, texCoord, 0.0).rg;
|
||||
vec2 enc = textureLod(gbuffer0, texCoord, 0.0).rg;
|
||||
vec3 n;
|
||||
n.z = 1.0 - abs(enc.x) - abs(enc.y);
|
||||
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
|
||||
n = normalize(n);
|
||||
|
||||
|
||||
vec3 vray = normalize(viewRay);
|
||||
vec3 currentPos = getPosNoEye(eyeLook, vray, depth, cameraProj);
|
||||
// vec3 currentPos = getPos2NoEye(eye, invVP, depth, texCoord);
|
||||
|
@ -53,7 +55,7 @@ void main() {
|
|||
vec3 pos = getPos2NoEye(eye, invVP, depth, texCoord + k) - currentPos;
|
||||
fragColor += max(0, dot(pos, n) - currentDistanceB) / (dot(pos, pos) + 0.015);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _CPostprocess
|
||||
fragColor *= (PPComp12.x * 0.3) / samples;
|
||||
#else
|
||||
|
|
|
@ -28,11 +28,13 @@
|
|||
},
|
||||
{
|
||||
"name": "PPComp11",
|
||||
"link": "_PPComp11"
|
||||
"link": "_PPComp11",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
},
|
||||
{
|
||||
"name": "PPComp12",
|
||||
"link": "_PPComp12"
|
||||
"link": "_PPComp12",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
|
|
@ -12,8 +12,10 @@ uniform mat4 P;
|
|||
uniform mat3 V3;
|
||||
uniform vec2 cameraProj;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp9;
|
||||
uniform vec3 PPComp10;
|
||||
#endif
|
||||
|
||||
in vec3 viewRay;
|
||||
in vec2 texCoord;
|
||||
|
|
|
@ -24,11 +24,13 @@
|
|||
},
|
||||
{
|
||||
"name": "PPComp9",
|
||||
"link": "_PPComp9"
|
||||
"link": "_PPComp9",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
},
|
||||
{
|
||||
"name": "PPComp10",
|
||||
"link": "_PPComp10"
|
||||
"link": "_PPComp10",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
|
||||
const int maxLights = 16;
|
||||
const int maxLightsCluster = 4; // Ensure fast loop unroll before going higher
|
||||
const float clusterNear = 3.0;
|
||||
const vec3 clusterSlices = vec3(16, 16, 16);
|
||||
|
||||
int getClusterI(vec2 tc, float viewz, vec2 cameraPlane) {
|
||||
|
@ -11,6 +8,10 @@ int getClusterI(vec2 tc, float viewz, vec2 cameraPlane) {
|
|||
float z = log(viewz - cnear + 1.0) / log(cameraPlane.y - cnear + 1.0);
|
||||
sliceZ = int(z * (clusterSlices.z - 1)) + 1;
|
||||
}
|
||||
// address gap between near plane and cluster near offset
|
||||
else if (viewz >= cameraPlane.x) {
|
||||
sliceZ = 1;
|
||||
}
|
||||
return int(tc.x * clusterSlices.x) +
|
||||
int(int(tc.y * clusterSlices.y) * clusterSlices.x) +
|
||||
int(sliceZ * clusterSlices.x * clusterSlices.y);
|
||||
|
|
|
@ -21,27 +21,41 @@
|
|||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot0;
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
#ifndef _LTC
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot1;
|
||||
uniform mat4 LWVPSpot2;
|
||||
uniform mat4 LWVPSpot3;
|
||||
#ifdef _Clusters
|
||||
#ifdef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlas;
|
||||
#endif
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
|
||||
#endif
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _LTC
|
||||
uniform vec3 lightArea0;
|
||||
|
@ -51,17 +65,14 @@ uniform vec3 lightArea3;
|
|||
uniform sampler2D sltcMat;
|
||||
uniform sampler2D sltcMag;
|
||||
#ifdef _ShadowMap
|
||||
#ifndef _Spot
|
||||
#ifndef _Spot
|
||||
#ifdef _SinglePoint
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot1;
|
||||
uniform mat4 LWVPSpot2;
|
||||
uniform mat4 LWVPSpot3;
|
||||
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -132,24 +143,24 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
if (index == 0) {
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 1) {
|
||||
vec4 lPos = LWVPSpot1 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[1] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 2) {
|
||||
vec4 lPos = LWVPSpot2 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[2] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 3) {
|
||||
vec4 lPos = LWVPSpot3 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[3] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
#endif
|
||||
|
@ -168,26 +179,26 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
if (index == 0) {
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 1) {
|
||||
vec4 lPos = LWVPSpot1 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 2) {
|
||||
vec4 lPos = LWVPSpot2 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 3) {
|
||||
vec4 lPos = LWVPSpot3 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= shadowTest(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSpot
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, bias
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -207,10 +218,21 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], ld, -l, bias, lightProj, n);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], ld, -l, bias, lightProj, n);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], ld, -l, bias, lightProj, n);
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= PCFFakeCube(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasPoint
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
, ld, -l, bias, lightProj, n, index
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], ld, -l, bias, lightProj, n);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], ld, -l, bias, lightProj, n);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], ld, -l, bias, lightProj, n);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -8,27 +8,39 @@
|
|||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot0;
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot1;
|
||||
uniform mat4 LWVPSpot2;
|
||||
uniform mat4 LWVPSpot3;
|
||||
#ifdef _Clusters
|
||||
#ifdef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlas;
|
||||
#endif
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
|
||||
#endif
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
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
|
||||
|
@ -62,26 +74,26 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
if (index == 0) {
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 1) {
|
||||
vec4 lPos = LWVPSpot1 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 2) {
|
||||
vec4 lPos = LWVPSpot2 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 3) {
|
||||
vec4 lPos = LWVPSpot3 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= shadowTest(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSpot
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, bias
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -90,20 +102,32 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
#ifndef _Spot
|
||||
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
#ifndef _Spot
|
||||
direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], ld, -l, bias, lightProj, n);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], ld, -l, bias, lightProj, n);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], ld, -l, bias, lightProj, n);
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= PCFFakeCube(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasPoint
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
, ld, -l, bias, lightProj, n, index
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], ld, -l, bias, lightProj, n);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], ld, -l, bias, lightProj, n);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], ld, -l, bias, lightProj, n);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return direct;
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@ float rand(const vec2 co) { // Unreliable
|
|||
}
|
||||
|
||||
vec2 rand2(const vec2 coord) {
|
||||
const float width = 1100;
|
||||
const float height = 500;
|
||||
const float width = 1100.0;
|
||||
const float height = 500.0;
|
||||
float noiseX = ((fract(1.0 - coord.s * (width / 2.0)) * 0.25) + (fract(coord.t * (height / 2.0)) * 0.75)) * 2.0 - 1.0;
|
||||
float noiseY = ((fract(1.0 - coord.s * (width / 2.0)) * 0.75) + (fract(coord.t * (height / 2.0)) * 0.25)) * 2.0 - 1.0;
|
||||
float noiseY = ((fract(1.0 - coord.s * (width / 2.0)) * 0.75) + (fract(coord.t * (height / 2.0)) * 0.25)) * 2.0 - 1.0;
|
||||
return vec2(noiseX, noiseY);
|
||||
}
|
||||
|
||||
|
@ -40,4 +40,9 @@ float attenuate(const float dist) {
|
|||
// 1.0 / (quadratic * dist * dist);
|
||||
}
|
||||
|
||||
float safe_acos(const float x) {
|
||||
// acos is undefined if |x| > 1
|
||||
return acos(clamp(x, -1.0, 1.0));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
53
Shaders/std/morph_target.glsl
Normal file
53
Shaders/std/morph_target.glsl
Normal file
|
@ -0,0 +1,53 @@
|
|||
uniform sampler2D morphDataPos;
|
||||
uniform sampler2D morphDataNor;
|
||||
uniform vec2 morphScaleOffset;
|
||||
uniform vec2 morphDataDim;
|
||||
uniform vec4 morphWeights[8];
|
||||
|
||||
void getMorphedVertex(vec2 uvCoord, inout vec3 A){
|
||||
for(int i = 0; i<8; i++ )
|
||||
{
|
||||
vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 1) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 2) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 3) * morphDataDim.y);
|
||||
|
||||
vec3 morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.x)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].x * morph;
|
||||
|
||||
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.y)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].y * morph;
|
||||
|
||||
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.z)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].z * morph;
|
||||
|
||||
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.w)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].w * morph;
|
||||
}
|
||||
}
|
||||
|
||||
void getMorphedNormal(vec2 uvCoord, vec3 oldNor, inout vec3 morphNor){
|
||||
|
||||
for(int i = 0; i<8; i++ )
|
||||
{
|
||||
vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 1) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 2) * 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);
|
||||
morphNor += norm;
|
||||
|
||||
norm = oldNor + morphWeights[i].y * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.y)).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);
|
||||
}
|
|
@ -11,6 +11,50 @@ uniform vec4 casData[shadowmapCascades * 4 + 4];
|
|||
uniform vec2 smSizeUniform;
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _Clusters
|
||||
#ifdef _ShadowMapAtlas
|
||||
uniform vec4 pointLightDataArray[maxLightsCluster * 6];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMapAtlas
|
||||
// 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/
|
||||
vec2 sampleCube(vec3 dir, out int faceIndex) {
|
||||
vec3 dirAbs = abs(dir);
|
||||
float ma;
|
||||
vec2 uv;
|
||||
if(dirAbs.z >= dirAbs.x && dirAbs.z >= dirAbs.y) {
|
||||
faceIndex = dir.z < 0.0 ? 5 : 4;
|
||||
ma = 0.5 / dirAbs.z;
|
||||
uv = vec2(dir.z < 0.0 ? -dir.x : dir.x, -dir.y);
|
||||
}
|
||||
else if(dirAbs.y >= dirAbs.x) {
|
||||
faceIndex = dir.y < 0.0 ? 3 : 2;
|
||||
ma = 0.5 / dirAbs.y;
|
||||
uv = vec2(dir.x, dir.y < 0.0 ? -dir.z : dir.z);
|
||||
}
|
||||
else {
|
||||
faceIndex = dir.x < 0.0 ? 1 : 0;
|
||||
ma = 0.5 / dirAbs.x;
|
||||
uv = vec2(dir.x < 0.0 ? dir.z : -dir.z, -dir.y);
|
||||
}
|
||||
// downscale uv a little to hide seams
|
||||
// transform coordinates from clip space to texture space
|
||||
#ifndef _FlipY
|
||||
return uv * 0.9976 * ma + 0.5;
|
||||
#else
|
||||
#ifdef HLSL
|
||||
return uv * 0.9976 * ma + 0.5;
|
||||
#else
|
||||
return vec2(uv.x * ma, uv.y * -ma) * 0.9976 + 0.5;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
float PCF(sampler2DShadow shadowMap, const vec2 uv, const float compare, const vec2 smSize) {
|
||||
float result = texture(shadowMap, vec3(uv + (vec2(-1.0, -1.0) / smSize), compare));
|
||||
result += texture(shadowMap, vec3(uv + (vec2(-1.0, 0.0) / smSize), compare));
|
||||
|
@ -50,6 +94,186 @@ float PCFCube(samplerCubeShadow shadowMapCube, const vec3 lp, vec3 ml, const flo
|
|||
return result / 9.0;
|
||||
}
|
||||
|
||||
#ifdef _ShadowMapAtlas
|
||||
// transform "out-of-bounds" coordinates to the correct face/coordinate system
|
||||
// https://www.khronos.org/opengl/wiki/File:CubeMapAxes.png
|
||||
vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 uv) {
|
||||
if (uv.x < 0.0) {
|
||||
if (faceIndex == 0) { // X+
|
||||
newFaceIndex = 4; // Z+
|
||||
}
|
||||
else if (faceIndex == 1) { // X-
|
||||
newFaceIndex = 5; // Z-
|
||||
}
|
||||
else if (faceIndex == 2) { // Y+
|
||||
newFaceIndex = 1; // X-
|
||||
}
|
||||
else if (faceIndex == 3) { // Y-
|
||||
newFaceIndex = 1; // X-
|
||||
}
|
||||
else if (faceIndex == 4) { // Z+
|
||||
newFaceIndex = 1; // X-
|
||||
}
|
||||
else { // Z-
|
||||
newFaceIndex = 0; // X+
|
||||
}
|
||||
uv = vec2(1.0 + uv.x, uv.y);
|
||||
}
|
||||
else if (uv.x > 1.0) {
|
||||
if (faceIndex == 0) { // X+
|
||||
newFaceIndex = 5; // Z-
|
||||
}
|
||||
else if (faceIndex == 1) { // X-
|
||||
newFaceIndex = 4; // Z+
|
||||
}
|
||||
else if (faceIndex == 2) { // Y+
|
||||
newFaceIndex = 0; // X+
|
||||
}
|
||||
else if (faceIndex == 3) { // Y-
|
||||
newFaceIndex = 0; // X+
|
||||
}
|
||||
else if (faceIndex == 4) { // Z+
|
||||
newFaceIndex = 0; // X+
|
||||
}
|
||||
else { // Z-
|
||||
newFaceIndex = 1; // X-
|
||||
}
|
||||
uv = vec2(1.0 - uv.x, uv.y);
|
||||
}
|
||||
else if (uv.y < 0.0) {
|
||||
if (faceIndex == 0) { // X+
|
||||
newFaceIndex = 2; // Y+
|
||||
}
|
||||
else if (faceIndex == 1) { // X-
|
||||
newFaceIndex = 2; // Y+
|
||||
}
|
||||
else if (faceIndex == 2) { // Y+
|
||||
newFaceIndex = 5; // Z-
|
||||
}
|
||||
else if (faceIndex == 3) { // Y-
|
||||
newFaceIndex = 4; // Z+
|
||||
}
|
||||
else if (faceIndex == 4) { // Z+
|
||||
newFaceIndex = 2; // Y+
|
||||
}
|
||||
else { // Z-
|
||||
newFaceIndex = 2; // Y+
|
||||
}
|
||||
uv = vec2(uv.x, 1.0 + uv.y);
|
||||
}
|
||||
else if (uv.y > 1.0) {
|
||||
if (faceIndex == 0) { // X+
|
||||
newFaceIndex = 3; // Y-
|
||||
}
|
||||
else if (faceIndex == 1) { // X-
|
||||
newFaceIndex = 3; // Y-
|
||||
}
|
||||
else if (faceIndex == 2) { // Y+
|
||||
newFaceIndex = 4; // Z+
|
||||
}
|
||||
else if (faceIndex == 3) { // Y-
|
||||
newFaceIndex = 5; // Z-
|
||||
}
|
||||
else if (faceIndex == 4) { // Z+
|
||||
newFaceIndex = 3; // Y-
|
||||
}
|
||||
else { // Z-
|
||||
newFaceIndex = 3; // Y-
|
||||
}
|
||||
uv = vec2(uv.x, 1.0 - uv.y);
|
||||
} else {
|
||||
newFaceIndex = faceIndex;
|
||||
}
|
||||
// cover corner cases too
|
||||
return uv;
|
||||
}
|
||||
|
||||
float PCFFakeCube(sampler2DShadow shadowMap, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const int index) {
|
||||
const vec2 smSize = smSizeUniform; // TODO: incorrect...
|
||||
const float compare = lpToDepth(lp, lightProj) - bias * 1.5;
|
||||
ml = ml + n * bias * 20;
|
||||
|
||||
int faceIndex = 0;
|
||||
const int lightIndex = index * 6;
|
||||
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
|
||||
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
|
||||
float result = texture(shadowMap, vec3(uvtiled, compare));
|
||||
// soft shadowing
|
||||
int newFaceIndex = 0;
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, 0.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 += 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 += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.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 += 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 += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.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 += 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 += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(1.0, 0.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 += 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 += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
return result / 9.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
float shadowTest(sampler2DShadow shadowMap, const vec3 lPos, const float shadowsBias) {
|
||||
#ifdef _SMSizeUniform
|
||||
vec2 smSize = smSizeUniform;
|
||||
|
@ -95,7 +319,7 @@ mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
|
|||
|
||||
float shadowTestCascade(sampler2DShadow shadowMap, const vec3 eye, const vec3 p, const float shadowsBias) {
|
||||
#ifdef _SMSizeUniform
|
||||
vec2 smSize = smSizeUniform * vec2(shadowmapCascades, 1.0);
|
||||
vec2 smSize = smSizeUniform;
|
||||
#else
|
||||
const vec2 smSize = shadowmapSize * vec2(shadowmapCascades, 1.0);
|
||||
#endif
|
||||
|
|
155
Shaders/std/sky.glsl
Normal file
155
Shaders/std/sky.glsl
Normal file
|
@ -0,0 +1,155 @@
|
|||
/* Various sky functions
|
||||
* =====================
|
||||
*
|
||||
* Nishita model is based on https://github.com/wwwtyro/glsl-atmosphere (Unlicense License)
|
||||
*
|
||||
* Changes to the original implementation:
|
||||
* - r and pSun parameters of nishita_atmosphere() are already normalized
|
||||
* - Some original parameters of nishita_atmosphere() are replaced with pre-defined values
|
||||
* - Implemented air, dust and ozone density node parameters (see Blender source)
|
||||
* - Replaced the inner integral calculation with a LUT lookup
|
||||
*
|
||||
* Reference for the sun's limb darkening and ozone calculations:
|
||||
* [Hill] Sebastien Hillaire. Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite
|
||||
* (https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/s2016-pbs-frostbite-sky-clouds-new.pdf)
|
||||
*
|
||||
* Cycles code used for reference: blender/intern/sky/source/sky_nishita.cpp
|
||||
* (https://github.com/blender/blender/blob/4429b4b77ef6754739a3c2b4fabd0537999e9bdc/intern/sky/source/sky_nishita.cpp)
|
||||
*/
|
||||
|
||||
#ifndef _SKY_GLSL_
|
||||
#define _SKY_GLSL_
|
||||
|
||||
#include "std/math.glsl"
|
||||
|
||||
uniform sampler2D nishitaLUT;
|
||||
uniform vec2 nishitaDensity;
|
||||
|
||||
#ifndef PI
|
||||
#define PI 3.141592
|
||||
#endif
|
||||
#ifndef HALF_PI
|
||||
#define HALF_PI 1.570796
|
||||
#endif
|
||||
|
||||
#define nishita_iSteps 16
|
||||
|
||||
// These values are taken from Cycles code if they
|
||||
// exist there, otherwise they are taken from the example
|
||||
// in the glsl-atmosphere repo
|
||||
#define nishita_sun_intensity 22.0
|
||||
#define nishita_atmo_radius 6420e3
|
||||
#define nishita_rayleigh_scale 8e3
|
||||
#define nishita_rayleigh_coeff vec3(5.5e-6, 13.0e-6, 22.4e-6)
|
||||
#define nishita_mie_scale 1.2e3
|
||||
#define nishita_mie_coeff 2e-5
|
||||
#define nishita_mie_dir 0.76 // Aerosols anisotropy ("direction")
|
||||
#define nishita_mie_dir_sq 0.5776 // Squared aerosols anisotropy
|
||||
|
||||
// Values from [Hill: 60]
|
||||
#define sun_limb_darkening_col vec3(0.397, 0.503, 0.652)
|
||||
|
||||
vec3 nishita_lookupLUT(const float height, const float sunTheta) {
|
||||
vec2 coords = vec2(
|
||||
sqrt(height * (1 / nishita_atmo_radius)),
|
||||
0.5 + 0.5 * sign(sunTheta - HALF_PI) * sqrt(abs(sunTheta * (1 / HALF_PI) - 1))
|
||||
);
|
||||
return textureLod(nishitaLUT, coords, 0.0).rgb;
|
||||
}
|
||||
|
||||
/* See raySphereIntersection() in armory/Sources/renderpath/Nishita.hx */
|
||||
vec2 nishita_rsi(const vec3 r0, const vec3 rd, const float sr) {
|
||||
float a = dot(rd, rd);
|
||||
float b = 2.0 * dot(rd, r0);
|
||||
float c = dot(r0, r0) - (sr * sr);
|
||||
float d = (b*b) - 4.0*a*c;
|
||||
|
||||
// If d < 0.0 the ray does not intersect the sphere
|
||||
return (d < 0.0) ? vec2(1e5,-1e5) : vec2((-b - sqrt(d))/(2.0*a), (-b + sqrt(d))/(2.0*a));
|
||||
}
|
||||
|
||||
/*
|
||||
* r: normalized ray direction
|
||||
* r0: ray origin
|
||||
* pSun: normalized sun direction
|
||||
* rPlanet: planet radius
|
||||
*/
|
||||
vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const float rPlanet) {
|
||||
// Calculate the step size of the primary ray
|
||||
vec2 p = nishita_rsi(r0, r, nishita_atmo_radius);
|
||||
if (p.x > p.y) return vec3(0.0);
|
||||
p.y = min(p.y, nishita_rsi(r0, r, rPlanet).x);
|
||||
float iStepSize = (p.y - p.x) / float(nishita_iSteps);
|
||||
|
||||
// Primary ray time
|
||||
float iTime = 0.0;
|
||||
|
||||
// Accumulators for Rayleigh and Mie scattering.
|
||||
vec3 totalRlh = vec3(0,0,0);
|
||||
vec3 totalMie = vec3(0,0,0);
|
||||
|
||||
// Optical depth accumulators for the primary ray
|
||||
float iOdRlh = 0.0;
|
||||
float iOdMie = 0.0;
|
||||
|
||||
// Calculate the Rayleigh and Mie phases
|
||||
float mu = dot(r, pSun);
|
||||
float mumu = mu * mu;
|
||||
float pRlh = 3.0 / (16.0 * PI) * (1.0 + mumu);
|
||||
float pMie = 3.0 / (8.0 * PI) * ((1.0 - nishita_mie_dir_sq) * (mumu + 1.0)) / (pow(1.0 + nishita_mie_dir_sq - 2.0 * mu * nishita_mie_dir, 1.5) * (2.0 + nishita_mie_dir_sq));
|
||||
|
||||
// Sample the primary ray
|
||||
for (int i = 0; i < nishita_iSteps; i++) {
|
||||
|
||||
// Calculate the primary ray sample position and height
|
||||
vec3 iPos = r0 + r * (iTime + iStepSize * 0.5);
|
||||
float iHeight = length(iPos) - rPlanet;
|
||||
|
||||
// Calculate the optical depth of the Rayleigh and Mie scattering for this step
|
||||
float odStepRlh = exp(-iHeight / nishita_rayleigh_scale) * nishitaDensity.x * iStepSize;
|
||||
float odStepMie = exp(-iHeight / nishita_mie_scale) * nishitaDensity.y * iStepSize;
|
||||
|
||||
// Accumulate optical depth
|
||||
iOdRlh += odStepRlh;
|
||||
iOdMie += odStepMie;
|
||||
|
||||
// Idea behind this: "Rotate" everything by iPos (-> iPos is the new zenith) and then all calculations for the
|
||||
// inner integral only depend on the sample height (iHeight) and sunTheta (angle between sun and new zenith).
|
||||
float sunTheta = safe_acos(dot(normalize(iPos), normalize(pSun)));
|
||||
vec3 jAttn = nishita_lookupLUT(iHeight, sunTheta);
|
||||
|
||||
// Calculate attenuation
|
||||
vec3 iAttn = exp(-(
|
||||
nishita_mie_coeff * iOdMie
|
||||
+ nishita_rayleigh_coeff * iOdRlh
|
||||
// + 0 for ozone
|
||||
));
|
||||
vec3 attn = iAttn * jAttn;
|
||||
|
||||
// Apply dithering to reduce visible banding
|
||||
attn *= 0.98 + rand(r.xy) * 0.04;
|
||||
|
||||
// Accumulate scattering
|
||||
totalRlh += odStepRlh * attn;
|
||||
totalMie += odStepMie * attn;
|
||||
|
||||
iTime += iStepSize;
|
||||
}
|
||||
|
||||
return nishita_sun_intensity * (pRlh * nishita_rayleigh_coeff * totalRlh + pMie * nishita_mie_coeff * totalMie);
|
||||
}
|
||||
|
||||
vec3 sun_disk(const vec3 n, const vec3 light_dir, const float disk_size, const float intensity) {
|
||||
// Normalized SDF
|
||||
float dist = distance(n, light_dir) / disk_size;
|
||||
|
||||
// Darken the edges of the sun
|
||||
// [Hill: 28, 60] (according to [Nec96])
|
||||
float invDist = 1.0 - dist;
|
||||
float mu = sqrt(invDist * invDist);
|
||||
vec3 limb_darkening = 1.0 - (1.0 - pow(vec3(mu), sun_limb_darkening_col));
|
||||
|
||||
return 1 + (1.0 - step(1.0, dist)) * nishita_sun_intensity * intensity * limb_darkening;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -12,7 +12,7 @@ uniform sampler2D gbufferD;
|
|||
uniform sampler2D snoise;
|
||||
|
||||
#ifdef _Clusters
|
||||
uniform vec4 lightsArray[maxLights * 2];
|
||||
uniform vec4 lightsArray[maxLights * 3];
|
||||
#ifdef _Spot
|
||||
uniform vec4 lightsArraySpot[maxLights];
|
||||
#endif
|
||||
|
@ -24,7 +24,7 @@ uniform vec2 cameraPlane;
|
|||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform vec2 lightProj;
|
||||
|
@ -35,10 +35,7 @@ uniform vec2 cameraPlane;
|
|||
uniform vec2 lightProj;
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot1;
|
||||
uniform mat4 LWVPSpot2;
|
||||
uniform mat4 LWVPSpot3;
|
||||
uniform mat4 LWVPSpot[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -47,7 +44,15 @@ uniform vec2 cameraPlane;
|
|||
uniform vec3 sunDir;
|
||||
uniform vec3 sunCol;
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSun;
|
||||
#else
|
||||
uniform sampler2DShadow shadowMapAtlas;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMap;
|
||||
#endif
|
||||
uniform float shadowsBias;
|
||||
#ifdef _CSM
|
||||
//!uniform vec4 casData[shadowmapCascades * 4 + 4];
|
||||
|
@ -98,12 +103,22 @@ void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatter
|
|||
#endif
|
||||
vec4 lPos = LWVP * vec4(curPos, 1.0);
|
||||
lPos.xyz /= lPos.w;
|
||||
visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias));
|
||||
visibility = texture(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
, vec3(lPos.xy, lPos.z - shadowsBias));
|
||||
#endif
|
||||
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
vec4 lPos = LWVPSpot0 * vec4(curPos, 1.0);
|
||||
vec4 lPos = LWVPSpot[0] * vec4(curPos, 1.0);
|
||||
visibility = shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, pointBias);
|
||||
float spotEffect = dot(spotDir, normalize(pointPos - curPos)); // lightDir
|
||||
if (spotEffect < spotData.x) { // x - cutoff, y - cutoff - exponent
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
},
|
||||
{
|
||||
"name": "LWVP",
|
||||
"link": "_biasLightWorldViewProjectionMatrix",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSun",
|
||||
"ifndef": ["_CSM"],
|
||||
"ifdef": ["_Sun", "_ShadowMap"]
|
||||
},
|
||||
|
@ -108,23 +108,32 @@
|
|||
"ifdef": ["_SinglePoint", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot0",
|
||||
"name": "LWVPSpotArray",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpotArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot[0]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot0",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot1",
|
||||
"name": "LWVPSpot[1]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot1",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot2",
|
||||
"name": "LWVPSpot[2]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot2",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot3",
|
||||
"name": "LWVPSpot[3]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
}
|
||||
],
|
||||
|
|
1
Sources/armory/import.hx
Normal file
1
Sources/armory/import.hx
Normal file
|
@ -0,0 +1 @@
|
|||
import armory.system.Assert.*;
|
114
Sources/armory/logicnode/AddPhysicsConstraintNode.hx
Normal file
114
Sources/armory/logicnode/AddPhysicsConstraintNode.hx
Normal file
|
@ -0,0 +1,114 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
#if arm_physics
|
||||
import armory.trait.physics.PhysicsConstraint;
|
||||
import armory.trait.physics.bullet.PhysicsConstraint.ConstraintType;
|
||||
#end
|
||||
|
||||
class AddPhysicsConstraintNode extends LogicNode {
|
||||
|
||||
public var property0: String;//Type
|
||||
public var object: Object;
|
||||
public var rb1: Object;
|
||||
public var rb2: Object;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var pivotObject: Object = inputs[1].get();
|
||||
rb1 = inputs[2].get();
|
||||
rb2 = inputs[3].get();
|
||||
|
||||
if (pivotObject == null || rb1 == null || rb2 == null) return;
|
||||
|
||||
#if arm_physics
|
||||
|
||||
var disableCollisions: Bool = inputs[4].get();
|
||||
var breakable: Bool = inputs[5].get();
|
||||
var breakingThreshold: Float = inputs[6].get();
|
||||
var type: ConstraintType = 0;
|
||||
|
||||
var con: PhysicsConstraint = pivotObject.getTrait(PhysicsConstraint);
|
||||
if (con == null) {
|
||||
switch (property0) {
|
||||
case "Fixed": type = Fixed;
|
||||
case "Point": type = Point;
|
||||
case "Hinge": type = Hinge;
|
||||
case "Slider": type = Slider;
|
||||
case "Piston": type = Piston;
|
||||
case "Generic Spring": type = Generic;
|
||||
}
|
||||
|
||||
if (!breakable) breakingThreshold = 0.0;
|
||||
|
||||
if (type != Generic) {
|
||||
|
||||
con = new PhysicsConstraint(rb1, rb2, type, disableCollisions, breakingThreshold);
|
||||
|
||||
switch (type) {
|
||||
case Hinge:
|
||||
var setLimit: Bool = inputs[7].get();
|
||||
var low: Float = inputs[8].get();
|
||||
var up: Float = inputs[9].get();
|
||||
con.setHingeConstraintLimits(setLimit, low, up);
|
||||
|
||||
case Slider:
|
||||
var setLimit: Bool = inputs[7].get();
|
||||
var low: Float = inputs[8].get();
|
||||
var up: Float = inputs[9].get();
|
||||
con.setSliderConstraintLimits(setLimit, low, up);
|
||||
|
||||
case Piston:
|
||||
var setLinLimit: Bool = inputs[7].get();
|
||||
var linLow: Float = inputs[8].get();
|
||||
var linUp: Float = inputs[9].get();
|
||||
var setAngLimit: Bool = inputs[10].get();
|
||||
var angLow: Float = inputs[11].get();
|
||||
var angUp: Float = inputs[12].get();
|
||||
con.setPistonConstraintLimits(setLinLimit, linLow, linUp, setAngLimit, angLow, angUp);
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
else {
|
||||
var spring: Bool = false;
|
||||
var prop: PhysicsConstraintNode;
|
||||
|
||||
for (inp in 7...inputs.length) {
|
||||
prop = inputs[inp].get();
|
||||
if (prop == null) continue;
|
||||
if (prop.isSpring) {
|
||||
spring = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (spring) {
|
||||
con = new PhysicsConstraint(rb1, rb2, GenericSpring, disableCollisions, breakingThreshold);
|
||||
}
|
||||
else {
|
||||
con = new PhysicsConstraint(rb1, rb2, Generic, disableCollisions, breakingThreshold);
|
||||
}
|
||||
|
||||
for (inp in 7...inputs.length) {
|
||||
prop = inputs[inp].get();
|
||||
if (prop == null) continue;
|
||||
|
||||
if (prop.isSpring) {
|
||||
con.setSpringParams(prop.isSpring, prop.value1, prop.value2, prop.axis, prop.isAngular);
|
||||
}
|
||||
else {
|
||||
con.setGenericConstraintLimits(true, prop.value1, prop.value2, prop.axis, prop.isAngular);
|
||||
}
|
||||
}
|
||||
}
|
||||
pivotObject.addTrait(con);
|
||||
}
|
||||
#end
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,17 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
#if arm_physics
|
||||
import armory.trait.physics.RigidBody;
|
||||
import armory.trait.physics.bullet.RigidBody.Shape;
|
||||
#end
|
||||
import iron.object.Object;
|
||||
import armory.trait.physics.RigidBody;
|
||||
|
||||
|
||||
class AddRigidBodyNode extends LogicNode {
|
||||
|
||||
public var property0: String;//Shape
|
||||
public var property1: String;//Advanced
|
||||
public var property0: String; //Shape
|
||||
public var property1: Bool; //Advanced
|
||||
public var object: Object;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
|
@ -18,6 +20,10 @@ class AddRigidBodyNode extends LogicNode {
|
|||
|
||||
override function run(from: Int) {
|
||||
object = inputs[1].get();
|
||||
if (object == null) return;
|
||||
|
||||
#if arm_physics
|
||||
|
||||
var mass: Float = inputs[2].get();
|
||||
var active: Bool = inputs[3].get();
|
||||
var animated: Bool = inputs[4].get();
|
||||
|
@ -38,8 +44,7 @@ class AddRigidBodyNode extends LogicNode {
|
|||
|
||||
var shape: Shape = 1;
|
||||
|
||||
if(property1 == 'true')
|
||||
{
|
||||
if (property1) {
|
||||
margin = inputs[9].get();
|
||||
marginLen = inputs[10].get();
|
||||
linDamp = inputs[11].get();
|
||||
|
@ -49,51 +54,34 @@ class AddRigidBodyNode extends LogicNode {
|
|||
angVelThreshold = inputs[15].get();
|
||||
group = inputs[16].get();
|
||||
mask = inputs[17].get();
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
#if arm_physics
|
||||
var rb: RigidBody = object.getTrait(RigidBody);
|
||||
if((group < 0) || (group > 32)) group = 1; //Limiting max groups to 32
|
||||
if((mask < 0) || (mask > 32)) mask = 1; //Limiting max masks to 32
|
||||
if(rb == null)
|
||||
{
|
||||
|
||||
switch (property0){
|
||||
|
||||
case 'Box':
|
||||
shape = Box;
|
||||
case 'Sphere':
|
||||
shape = Sphere;
|
||||
case 'Capsule':
|
||||
shape = Capsule;
|
||||
case 'Cone':
|
||||
shape = Cone;
|
||||
case 'Cylinder':
|
||||
shape = Cylinder;
|
||||
case 'Convex Hull':
|
||||
shape = ConvexHull;
|
||||
case 'Mesh':
|
||||
shape = Mesh;
|
||||
if ((group < 0) || (group > 32)) group = 1; //Limiting max groups to 32
|
||||
if ((mask < 0) || (mask > 32)) mask = 1; //Limiting max masks to 32
|
||||
if (rb == null) {
|
||||
switch (property0) {
|
||||
case "Box": shape = Box;
|
||||
case "Sphere": shape = Sphere;
|
||||
case "Capsule": shape = Capsule;
|
||||
case "Cone": shape = Cone;
|
||||
case "Cylinder": shape = Cylinder;
|
||||
case "Convex Hull": shape = ConvexHull;
|
||||
case "Mesh": shape = Mesh;
|
||||
}
|
||||
|
||||
rb = new RigidBody(shape, mass, friction, bounciness, group, mask);
|
||||
rb.animated = animated;
|
||||
rb.staticObj = ! active;
|
||||
rb.staticObj = !active;
|
||||
rb.isTriggerObject(trigger);
|
||||
if(property1 == 'true')
|
||||
{
|
||||
|
||||
if (property1) {
|
||||
rb.linearDamping = linDamp;
|
||||
rb.angularDamping = angDamp;
|
||||
if(margin) rb.collisionMargin = marginLen;
|
||||
if(useDeactiv) {
|
||||
rb.setDeactivation(true);
|
||||
rb.setDeactivationParams(linearVelThreshold, angVelThreshold, 0.0);
|
||||
if (margin) rb.collisionMargin = marginLen;
|
||||
if (useDeactiv) {
|
||||
rb.setUpDeactivation(true, linearVelThreshold, angVelThreshold, 0.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object.addTrait(rb);
|
||||
|
|
|
@ -10,10 +10,17 @@ class AddTraitNode extends LogicNode {
|
|||
|
||||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
var trait: Dynamic = inputs[2].get();
|
||||
var traitName: String = inputs[2].get();
|
||||
|
||||
if (object == null || trait == null) return;
|
||||
assert(Error, object != null, "Object should not be null");
|
||||
assert(Error, traitName != null, "Trait name should not be null");
|
||||
|
||||
var cname = Type.resolveClass(Main.projectPackage + "." + traitName);
|
||||
if (cname == null) cname = Type.resolveClass(Main.projectPackage + ".node." + traitName);
|
||||
assert(Error, cname != null, 'No trait with the name "$traitName" found, make sure that the trait is exported!');
|
||||
assert(Warning, object.getTrait(cname) == null, 'Object already has the trait "$traitName" applied');
|
||||
|
||||
var trait = Type.createInstance(cname, []);
|
||||
object.addTrait(trait);
|
||||
|
||||
runOutput(0);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
import iron.object.Object;
|
||||
import iron.object.BoneAnimation;
|
||||
import iron.math.Mat4;
|
||||
|
@ -26,19 +28,28 @@ class BoneFKNode extends LogicNode {
|
|||
var anim = object.animation != null ? cast(object.animation, BoneAnimation) : null;
|
||||
if (anim == null) anim = object.getParentArmature(object.name);
|
||||
|
||||
// Manipulating bone in world space
|
||||
// Get bone in armature
|
||||
var bone = anim.getBone(boneName);
|
||||
m = anim.getBoneMat(bone);
|
||||
w = anim.getAbsMat(bone);
|
||||
|
||||
function moveBone() {
|
||||
m.setFrom(w);
|
||||
m.multmat(transform);
|
||||
iw.getInverse(w);
|
||||
m.multmat(iw);
|
||||
|
||||
var t2 = Mat4.identity();
|
||||
var loc= new Vec4();
|
||||
var rot = new Quat();
|
||||
var scl = new Vec4();
|
||||
|
||||
// anim.removeUpdate(moveBone);
|
||||
// notified = false;
|
||||
//Set scale to Armature scale. Bone scaling not yet implemented
|
||||
t2.setFrom(transform);
|
||||
t2.decompose(loc, rot, scl);
|
||||
scl = object.transform.world.getScale();
|
||||
t2.compose(loc, rot, scl);
|
||||
|
||||
//Set the bone local transform from world transform
|
||||
anim.setBoneMatFromWorldMat(t2, bone);
|
||||
|
||||
//Remove this method from animation loop after FK
|
||||
anim.removeUpdate(moveBone);
|
||||
notified = false;
|
||||
}
|
||||
|
||||
if (!notified) {
|
||||
|
|
|
@ -7,6 +7,13 @@ import iron.math.Vec4;
|
|||
class BoneIKNode extends LogicNode {
|
||||
|
||||
var goal: Vec4;
|
||||
var pole: Vec4;
|
||||
var poleEnabled: Bool;
|
||||
var chainLength: Int;
|
||||
var maxIterartions: Int;
|
||||
var precision: Float;
|
||||
var rollAngle: Float;
|
||||
|
||||
var notified = false;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
|
@ -19,6 +26,12 @@ class BoneIKNode extends LogicNode {
|
|||
var object: Object = inputs[1].get();
|
||||
var boneName: String = inputs[2].get();
|
||||
goal = inputs[3].get();
|
||||
poleEnabled = inputs[4].get();
|
||||
pole = inputs[5].get();
|
||||
chainLength = inputs[6].get();
|
||||
maxIterartions = inputs[7].get();
|
||||
precision = inputs[8].get();
|
||||
rollAngle = inputs[9].get();
|
||||
|
||||
if (object == null || goal == null) return;
|
||||
var anim = object.animation != null ? cast(object.animation, BoneAnimation) : null;
|
||||
|
@ -26,11 +39,15 @@ class BoneIKNode extends LogicNode {
|
|||
|
||||
var bone = anim.getBone(boneName);
|
||||
|
||||
function solveBone() {
|
||||
anim.solveIK(bone, goal);
|
||||
if(! poleEnabled) pole = null;
|
||||
|
||||
// anim.removeUpdate(solveBone);
|
||||
// notified = false;
|
||||
function solveBone() {
|
||||
//Solve IK
|
||||
anim.solveIK(bone, goal, precision, maxIterartions, chainLength, pole, rollAngle);
|
||||
|
||||
//Remove this method from animation loop after IK
|
||||
anim.removeUpdate(solveBone);
|
||||
notified = false;
|
||||
}
|
||||
|
||||
if (!notified) {
|
||||
|
|
|
@ -12,11 +12,17 @@ class CallHaxeStaticNode extends LogicNode {
|
|||
|
||||
var path: String = inputs[1].get();
|
||||
if (path != "") {
|
||||
var args: Array<Dynamic> = [];
|
||||
|
||||
for (i in 2...inputs.length) {
|
||||
args.push(inputs[i].get());
|
||||
}
|
||||
|
||||
var dotIndex = path.lastIndexOf(".");
|
||||
var classPath = path.substr(0, dotIndex);
|
||||
var classType = Type.resolveClass(classPath);
|
||||
var funName = path.substr(dotIndex + 1);
|
||||
result = Reflect.callMethod(classType, Reflect.field(classType, funName), [tree]);
|
||||
result = Reflect.callMethod(classType, Reflect.field(classType, funName), args);
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
|
|
39
Sources/armory/logicnode/CanvasSetProgressBarColorNode.hx
Normal file
39
Sources/armory/logicnode/CanvasSetProgressBarColorNode.hx
Normal file
|
@ -0,0 +1,39 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import armory.trait.internal.CanvasScript;
|
||||
import kha.Color;
|
||||
import iron.math.Vec4;
|
||||
|
||||
class CanvasSetProgressBarColorNode extends LogicNode {
|
||||
|
||||
var canvas: CanvasScript;
|
||||
var element: String;
|
||||
var color = new Vec4();
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
#if arm_ui
|
||||
function update() {
|
||||
if (!canvas.ready) return;
|
||||
tree.removeUpdate(update);
|
||||
|
||||
var e = canvas.getElement(element);
|
||||
if (e != null) e.color_progress = Color.fromFloats(color.x, color.y, color.z, color.w);
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
element = inputs[1].get();
|
||||
color = inputs[2].get();
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
if (canvas == null) canvas = Scene.active.camera.getTrait(CanvasScript);
|
||||
|
||||
// Ensure canvas is ready
|
||||
tree.notifyOnUpdate(update);
|
||||
update();
|
||||
}
|
||||
#end
|
||||
}
|
|
@ -1,18 +1,18 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import kha.FastFloat;
|
||||
|
||||
class ClampNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var value: kha.FastFloat = inputs[0].get();
|
||||
var min: kha.FastFloat = inputs[1].get();
|
||||
var max: kha.FastFloat = inputs[2].get();
|
||||
override function get(from: Int): FastFloat {
|
||||
var value = inputs[0].get();
|
||||
var min = inputs[1].get();
|
||||
var max = inputs[2].get();
|
||||
|
||||
if (value == null || min == null || max == null) return null;
|
||||
|
||||
value <= min ? return min : value >= max ? return max : return value;
|
||||
return value < min ? min : value > max ? max : value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,11 @@ class CompareNode extends LogicNode {
|
|||
|
||||
switch (property0) {
|
||||
case "Equal":
|
||||
cond = Std.is(v1, Vec4) ? v1.equals(v2) : v1 == v2;
|
||||
cond = Std.isOfType(v1, Vec4) ? v1.equals(v2) : v1 == v2;
|
||||
case "Not Equal":
|
||||
cond = Std.isOfType(v1, Vec4) ? !v1.equals(v2) : v1 != v2;
|
||||
case "Almost Equal":
|
||||
cond = Std.is(v1, Vec4) ? v1.almostEquals(v2, property1) : Math.abs(v1 - v2) < property1;
|
||||
cond = Std.isOfType(v1, Vec4) ? v1.almostEquals(v2, property1) : Math.abs(v1 - v2) < property1;
|
||||
case "Greater":
|
||||
cond = v1 > v2;
|
||||
case "Greater Equal":
|
||||
|
@ -30,6 +32,9 @@ class CompareNode extends LogicNode {
|
|||
cond = v1 < v2;
|
||||
case "Less Equal":
|
||||
cond = v1 <= v2;
|
||||
case "Between":
|
||||
var v3: Dynamic = inputs[2].get();
|
||||
cond = v2 <= v1 && v1 <= v3;
|
||||
case "Or":
|
||||
for (input in inputs) {
|
||||
if (input.get()) {
|
||||
|
|
|
@ -18,9 +18,11 @@ class GateNode extends LogicNode {
|
|||
|
||||
switch (property0) {
|
||||
case "Equal":
|
||||
cond = Std.is(v1, Vec4) ? v1.equals(v2) : v1 == v2;
|
||||
cond = Std.isOfType(v1, Vec4) ? v1.equals(v2) : v1 == v2;
|
||||
case "Not Equal":
|
||||
cond = Std.isOfType(v1, Vec4) ? !v1.equals(v2) : v1 != v2;
|
||||
case "Almost Equal":
|
||||
cond = Std.is(v1, Vec4) ? v1.almostEquals(v2, property1) : Math.abs(v1 - v2) < property1;
|
||||
cond = Std.isOfType(v1, Vec4) ? v1.almostEquals(v2, property1) : Math.abs(v1 - v2) < property1;
|
||||
case "Greater":
|
||||
cond = v1 > v2;
|
||||
case "Greater Equal":
|
||||
|
@ -29,6 +31,9 @@ class GateNode extends LogicNode {
|
|||
cond = v1 < v2;
|
||||
case "Less Equal":
|
||||
cond = v1 <= v2;
|
||||
case "Between":
|
||||
var v3: Dynamic = inputs[3].get();
|
||||
cond = v2 <= v1 && v1 <= v3;
|
||||
case "Or":
|
||||
for (i in 1...inputs.length) {
|
||||
if (inputs[i].get()) {
|
||||
|
|
25
Sources/armory/logicnode/GetAgentDataNode.hx
Normal file
25
Sources/armory/logicnode/GetAgentDataNode.hx
Normal file
|
@ -0,0 +1,25 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class GetAgentDataNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Float {
|
||||
var object: Object = inputs[0].get();
|
||||
|
||||
assert(Error, object != null, "The object to naviagte should not be null");
|
||||
|
||||
#if arm_navigation
|
||||
var agent: armory.trait.NavAgent = object.getTrait(armory.trait.NavAgent);
|
||||
assert(Error, agent != null, "The object does not have NavAgent Trait");
|
||||
if(from == 0) return agent.speed;
|
||||
else return agent.turnDuration;
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
}
|
||||
}
|
31
Sources/armory/logicnode/GetBoneFkIkOnlyNode.hx
Normal file
31
Sources/armory/logicnode/GetBoneFkIkOnlyNode.hx
Normal file
|
@ -0,0 +1,31 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
import iron.object.BoneAnimation;
|
||||
|
||||
class GetBoneFkIkOnlyNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Bool {
|
||||
#if arm_skin
|
||||
|
||||
var object: Object = inputs[0].get();
|
||||
var boneName: String = inputs[1].get();
|
||||
|
||||
if (object == null) return null;
|
||||
var anim = object.animation != null ? cast(object.animation, BoneAnimation) : null;
|
||||
if (anim == null) anim = object.getParentArmature(object.name);
|
||||
|
||||
// Get bone in armature
|
||||
var bone = anim.getBone(boneName);
|
||||
|
||||
//Get bone transform in world coordinates
|
||||
return bone.is_ik_fk_only;
|
||||
|
||||
|
||||
#end
|
||||
}
|
||||
}
|
30
Sources/armory/logicnode/GetBoneTransformNode.hx
Normal file
30
Sources/armory/logicnode/GetBoneTransformNode.hx
Normal file
|
@ -0,0 +1,30 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
import iron.object.BoneAnimation;
|
||||
import iron.math.Mat4;
|
||||
|
||||
class GetBoneTransformNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Mat4 {
|
||||
#if arm_skin
|
||||
|
||||
var object: Object = inputs[0].get();
|
||||
var boneName: String = inputs[1].get();
|
||||
|
||||
if (object == null) return null;
|
||||
var anim = object.animation != null ? cast(object.animation, BoneAnimation) : null;
|
||||
if (anim == null) anim = object.getParentArmature(object.name);
|
||||
|
||||
// Get bone in armature
|
||||
var bone = anim.getBone(boneName);
|
||||
|
||||
return anim.getAbsWorldMat(bone);
|
||||
|
||||
#end
|
||||
}
|
||||
}
|
33
Sources/armory/logicnode/GetGamepadStartedNode.hx
Normal file
33
Sources/armory/logicnode/GetGamepadStartedNode.hx
Normal file
|
@ -0,0 +1,33 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.system.Input;
|
||||
|
||||
class GetGamepadStartedNode extends LogicNode {
|
||||
|
||||
var buttonStarted: Null<String>;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var g = Input.getGamepad(inputs[0].get());
|
||||
|
||||
buttonStarted = null;
|
||||
|
||||
for (b in Gamepad.buttons) {
|
||||
if (g.started(b)) {
|
||||
buttonStarted = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonStarted != null) {
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int) {
|
||||
return buttonStarted;
|
||||
}
|
||||
}
|
22
Sources/armory/logicnode/GetGlobalCanvasFontSizeNode.hx
Normal file
22
Sources/armory/logicnode/GetGlobalCanvasFontSizeNode.hx
Normal file
|
@ -0,0 +1,22 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import armory.trait.internal.CanvasScript;
|
||||
|
||||
class GetGlobalCanvasFontSizeNode extends LogicNode {
|
||||
|
||||
var canvas: CanvasScript;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
#if arm_ui
|
||||
override function get(from: Int): Dynamic {
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
if (canvas == null) canvas = Scene.active.camera.getTrait(CanvasScript);
|
||||
|
||||
return canvas.getCanvasFontSize();
|
||||
}
|
||||
#end
|
||||
}
|
22
Sources/armory/logicnode/GetGlobalCanvasScaleNode.hx
Normal file
22
Sources/armory/logicnode/GetGlobalCanvasScaleNode.hx
Normal file
|
@ -0,0 +1,22 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import armory.trait.internal.CanvasScript;
|
||||
|
||||
class GetGlobalCanvasScaleNode extends LogicNode {
|
||||
|
||||
var canvas: CanvasScript;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
#if arm_ui
|
||||
override function get(from: Int): Dynamic {
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
if (canvas == null) canvas = Scene.active.camera.getTrait(CanvasScript);
|
||||
|
||||
return canvas.getUiScale();
|
||||
}
|
||||
#end
|
||||
}
|
24
Sources/armory/logicnode/GetInputMapKeyNode.hx
Normal file
24
Sources/armory/logicnode/GetInputMapKeyNode.hx
Normal file
|
@ -0,0 +1,24 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class GetInputMapKeyNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var inputMap = inputs[0].get();
|
||||
var key = inputs[1].get();
|
||||
|
||||
var k = InputMap.getInputMapKey(inputMap, key);
|
||||
|
||||
if (k != null) {
|
||||
if (from == 0) return k.scale;
|
||||
else if (from == 1) return k.deadzone;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
32
Sources/armory/logicnode/GetKeyboardStartedNode.hx
Normal file
32
Sources/armory/logicnode/GetKeyboardStartedNode.hx
Normal file
|
@ -0,0 +1,32 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.system.Input;
|
||||
|
||||
class GetKeyboardStartedNode extends LogicNode {
|
||||
|
||||
var kb = Input.getKeyboard();
|
||||
var keyStarted: Null<String>;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
keyStarted = null;
|
||||
|
||||
for (k in Keyboard.keys) {
|
||||
if (kb.started(k)) {
|
||||
keyStarted = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyStarted != null) {
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int) {
|
||||
return keyStarted;
|
||||
}
|
||||
}
|
|
@ -10,9 +10,22 @@ class GetLocationNode extends LogicNode {
|
|||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: Object = inputs[0].get();
|
||||
var relative: Bool = inputs[1].get();
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
return object.transform.world.getLoc();
|
||||
var loc = object.transform.world.getLoc();
|
||||
|
||||
if (relative && object.parent != null) {
|
||||
loc.sub(object.parent.transform.world.getLoc()); // Add parent location influence
|
||||
|
||||
// Convert loc to parent local space
|
||||
var dotX = loc.dot(object.parent.transform.right());
|
||||
var dotY = loc.dot(object.parent.transform.look());
|
||||
var dotZ = loc.dot(object.parent.transform.up());
|
||||
loc.set(dotX, dotY, dotZ);
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.MeshObject;
|
||||
import iron.object.DecalObject;
|
||||
|
||||
class GetMaterialNode extends LogicNode {
|
||||
|
||||
|
@ -9,11 +10,27 @@ class GetMaterialNode extends LogicNode {
|
|||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: MeshObject = inputs[0].get();
|
||||
var slot: Int = inputs[1].get();
|
||||
|
||||
if (object == null) return null;
|
||||
var object = inputs[0].get();
|
||||
|
||||
return object.materials[slot];
|
||||
assert(Error, object != null, "The object input must not be null");
|
||||
|
||||
#if rp_decals
|
||||
if (Std.isOfType(object, DecalObject)) {
|
||||
var decal = cast(object, DecalObject);
|
||||
return decal.material;
|
||||
}
|
||||
#end
|
||||
|
||||
if (Std.isOfType(object, MeshObject)) {
|
||||
var mesh = cast(object, MeshObject);
|
||||
var slot: Int = inputs[1].get();
|
||||
|
||||
if (mesh == null) return null;
|
||||
|
||||
return mesh.materials[slot];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
32
Sources/armory/logicnode/GetMouseStartedNode.hx
Normal file
32
Sources/armory/logicnode/GetMouseStartedNode.hx
Normal file
|
@ -0,0 +1,32 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.system.Input;
|
||||
|
||||
class GetMouseStartedNode extends LogicNode {
|
||||
|
||||
var m = Input.getMouse();
|
||||
var buttonStarted: Null<String>;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
buttonStarted = null;
|
||||
|
||||
for (b in Mouse.buttons) {
|
||||
if (m.started(b)) {
|
||||
buttonStarted = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonStarted != null) {
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int) {
|
||||
return buttonStarted;
|
||||
}
|
||||
}
|
22
Sources/armory/logicnode/GetObjectByUidNode.hx
Normal file
22
Sources/armory/logicnode/GetObjectByUidNode.hx
Normal file
|
@ -0,0 +1,22 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.data.SceneFormat;
|
||||
import iron.object.Object;
|
||||
|
||||
class GetObjectByUidNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var objectUid: Int = inputs[0].get();
|
||||
|
||||
var obj = iron.Scene.active.getChildren(true);
|
||||
|
||||
for (obji in obj) if (obji.uid == objectUid) return obji;
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
|
@ -14,36 +14,7 @@ class GetObjectNode extends LogicNode {
|
|||
|
||||
override function get(from: Int): Dynamic {
|
||||
var objectName: String = inputs[0].get();
|
||||
|
||||
if (property0 == null || property0 == iron.Scene.active.raw.name) {
|
||||
return iron.Scene.active.getChild(objectName);
|
||||
}
|
||||
|
||||
#if arm_json
|
||||
property0 += ".json";
|
||||
#elseif arm_compress
|
||||
property0 += ".lz4";
|
||||
#end
|
||||
|
||||
var outObj: Null<Object> = null;
|
||||
|
||||
// Create the object in the active scene if it is from an inactive scene
|
||||
iron.data.Data.getSceneRaw(property0, (rawScene: TSceneFormat) -> {
|
||||
var objData: Null<TObj> = null;
|
||||
|
||||
for (o in rawScene.objects) {
|
||||
if (o.name == objectName) {
|
||||
objData = o;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (objData == null) return;
|
||||
|
||||
iron.Scene.active.createObject(objData, rawScene, null, null, (newObj: Object) -> {
|
||||
outObj = newObj;
|
||||
});
|
||||
});
|
||||
|
||||
return outObj;
|
||||
|
||||
return iron.Scene.active.getChild(objectName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
import iron.math.Vec3;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
|
||||
class GetRotationNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
@ -16,34 +19,16 @@ class GetRotationNode extends LogicNode {
|
|||
return null;
|
||||
}
|
||||
|
||||
var rot = object.transform.rot;
|
||||
|
||||
switch (from) {
|
||||
case 0:
|
||||
// euler angles
|
||||
return object.transform.rot.getEuler();
|
||||
case 1:
|
||||
// vector
|
||||
var sqrtW = Math.sqrt(1 - (rot.w * rot.w));
|
||||
if (sqrtW == 0) {
|
||||
return new Vec3(0, 0, 1);
|
||||
}
|
||||
return new Vec3(rot.x / sqrtW, rot.y / sqrtW, rot.z / sqrtW);
|
||||
case 2:
|
||||
// angle radians
|
||||
var angle = 2 * Math.acos(rot.w);
|
||||
return angle;
|
||||
case 3:
|
||||
// angle degrees
|
||||
var angle = 2 * Math.acos(rot.w);
|
||||
return angle * (180 / Math.PI);
|
||||
case 4:
|
||||
//quaternion xyz
|
||||
return new Vec3(rot.x, rot.y, rot.z);
|
||||
case 5:
|
||||
//quaternion w
|
||||
return rot.w;
|
||||
}
|
||||
switch(property0){
|
||||
case "Local":
|
||||
return object.transform.rot;
|
||||
case "Global":{
|
||||
var useless1 = new Vec4();
|
||||
var ret = new Quat();
|
||||
object.transform.world.decompose(useless1, ret, useless1);
|
||||
return ret;
|
||||
}}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,22 +3,24 @@ package armory.logicnode;
|
|||
class GetSystemName extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
super(tree);
|
||||
}
|
||||
|
||||
public static function equalsCI(a : String, b : String) return a.toLowerCase() == b.toLowerCase();
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var systemName: String = kha.System.systemId;
|
||||
|
||||
return switch (from) {
|
||||
case 0: systemName;
|
||||
case 1: equalsCI(kha.System.systemId, 'Windows');
|
||||
case 2: equalsCI(kha.System.systemId, 'Linux');
|
||||
case 3: equalsCI(kha.System.systemId, 'Mac');
|
||||
case 4: equalsCI(kha.System.systemId, 'HTML5');
|
||||
case 5: equalsCI(kha.System.systemId, 'Android');
|
||||
case 1: equalsCI(systemName, 'Windows');
|
||||
case 2: equalsCI(systemName, 'Linux');
|
||||
case 3: equalsCI(systemName, 'Mac');
|
||||
case 4: equalsCI(systemName, 'HTML5');
|
||||
case 5: equalsCI(systemName, 'Android');
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
|
||||
static inline function equalsCI(a: String, b: String): Bool {
|
||||
return a.toLowerCase() == b.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@ class GetTraitNameNode extends LogicNode {
|
|||
case 0: {
|
||||
// Check CanvasScript
|
||||
var cname = cast Type.resolveClass("armory.trait.internal.CanvasScript");
|
||||
if (Std.is(trait, cname)) {
|
||||
if (Std.isOfType(trait, cname)) {
|
||||
return trait.cnvName;
|
||||
}
|
||||
// Check WasmScript
|
||||
var cname = cast Type.resolveClass("armory.trait.internal.WasmScript");
|
||||
if (Std.is(trait, cname)) {
|
||||
if (Std.isOfType(trait, cname)) {
|
||||
return trait.wasmName;
|
||||
}
|
||||
// Other
|
||||
|
|
18
Sources/armory/logicnode/GetUidNode.hx
Normal file
18
Sources/armory/logicnode/GetUidNode.hx
Normal file
|
@ -0,0 +1,18 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class GetUidNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: Object = inputs[0].get();
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
return object.uid;
|
||||
}
|
||||
}
|
|
@ -13,15 +13,26 @@ class GoToLocationNode extends LogicNode {
|
|||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
var location: Vec4 = inputs[2].get();
|
||||
var speed: Float = inputs[3].get();
|
||||
var turnDuration: Float = inputs[4].get();
|
||||
|
||||
if (object == null || location == null) return;
|
||||
assert(Error, object != null, "The object input not be null");
|
||||
assert(Error, location != null, "The location to navigate to must not be null");
|
||||
assert(Error, speed != null, "Speed of Nav Agent should not be null");
|
||||
assert(Warning, speed >= 0, "Speed of Nav Agent should be positive");
|
||||
assert(Error, turnDuration != null, "Turn Duration of Nav Agent should not be null");
|
||||
assert(Warning, turnDuration >= 0, "Turn Duration of Nav Agent should be positive");
|
||||
|
||||
#if arm_navigation
|
||||
// Assume navmesh exists..
|
||||
var from = object.transform.world.getLoc();
|
||||
var to = location;
|
||||
|
||||
assert(Error, Navigation.active.navMeshes.length > 0, "No Navigation Mesh Present");
|
||||
Navigation.active.navMeshes[0].findPath(from, to, function(path: Array<iron.math.Vec4>) {
|
||||
var agent: armory.trait.NavAgent = object.getTrait(armory.trait.NavAgent);
|
||||
assert(Error, agent != null, "Object does not have a NavAgent trait");
|
||||
agent.speed = speed;
|
||||
agent.turnDuration = turnDuration;
|
||||
agent.setPath(path);
|
||||
});
|
||||
#end
|
||||
|
|
|
@ -1,31 +1,136 @@
|
|||
package armory.logicnode;
|
||||
|
||||
#if arm_patch @:keep @:keepSub #end
|
||||
class LogicNode {
|
||||
|
||||
var tree: LogicTree;
|
||||
var inputs: Array<LogicNodeInput> = [];
|
||||
var outputs: Array<Array<LogicNode>> = [];
|
||||
var inputs: Array<LogicNodeLink> = [];
|
||||
var outputs: Array<Array<LogicNodeLink>> = [];
|
||||
|
||||
#if arm_debug
|
||||
#if (arm_debug || arm_patch)
|
||||
public var name = "";
|
||||
public function watch(b: Bool) { // Watch in debug console
|
||||
var nodes = armory.trait.internal.DebugConsole.watchNodes;
|
||||
b ? nodes.push(this) : nodes.remove(this);
|
||||
}
|
||||
|
||||
#if (arm_debug)
|
||||
public function watch(b: Bool) { // Watch in debug console
|
||||
var nodes = armory.trait.internal.DebugConsole.watchNodes;
|
||||
b ? nodes.push(this) : nodes.remove(this);
|
||||
}
|
||||
#end
|
||||
#end
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
this.tree = tree;
|
||||
}
|
||||
|
||||
public function addInput(node: LogicNode, from: Int) {
|
||||
inputs.push(new LogicNodeInput(node, from));
|
||||
/**
|
||||
Resize the inputs array to a given size to minimize dynamic
|
||||
reallocation and over-allocation later.
|
||||
**/
|
||||
inline function preallocInputs(amount: Int) {
|
||||
this.inputs.resize(amount);
|
||||
}
|
||||
|
||||
public function addOutputs(nodes: Array<LogicNode>) {
|
||||
outputs.push(nodes);
|
||||
/**
|
||||
Resize the outputs array to a given size to minimize dynamic
|
||||
reallocation and over-allocation later.
|
||||
**/
|
||||
inline function preallocOutputs(amount: Int) {
|
||||
this.outputs.resize(amount);
|
||||
for (i in 0...outputs.length) {
|
||||
outputs[i] = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Add a link between to nodes to the tree.
|
||||
**/
|
||||
public static function addLink(fromNode: LogicNode, toNode: LogicNode, fromIndex: Int, toIndex: Int): LogicNodeLink {
|
||||
var link = new LogicNodeLink(fromNode, toNode, fromIndex, toIndex);
|
||||
|
||||
if (toNode.inputs.length <= toIndex) {
|
||||
toNode.inputs.resize(toIndex + 1);
|
||||
}
|
||||
toNode.inputs[toIndex] = link;
|
||||
|
||||
var fromNodeOuts = fromNode.outputs;
|
||||
var outLen = fromNodeOuts.length;
|
||||
if (outLen <= fromIndex) {
|
||||
fromNodeOuts.resize(fromIndex + 1);
|
||||
|
||||
// Initialize with empty arrays
|
||||
for (i in outLen...fromIndex + 1) {
|
||||
fromNodeOuts[i] = [];
|
||||
}
|
||||
}
|
||||
fromNodeOuts[fromIndex].push(link);
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
#if arm_patch
|
||||
/**
|
||||
Removes a link from the tree.
|
||||
**/
|
||||
static function removeLink(link: LogicNodeLink) {
|
||||
link.fromNode.outputs[link.fromIndex].remove(link);
|
||||
|
||||
// Reuse the same link and connect a default input node to it.
|
||||
// That's why this function is only available in arm_patch mode, we need
|
||||
// access to the link's type and value.
|
||||
link.fromNode = LogicNode.createSocketDefaultNode(link.toNode.tree, link.toType, link.toValue);
|
||||
link.fromIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Removes all inputs and their links from this node.
|
||||
Warning: this function changes the amount of node inputs to 0!
|
||||
**/
|
||||
function clearInputs() {
|
||||
for (link in inputs) {
|
||||
link.fromNode.outputs[link.fromIndex].remove(link);
|
||||
}
|
||||
inputs.resize(0);
|
||||
}
|
||||
|
||||
/**
|
||||
Removes all outputs and their links from this node.
|
||||
Warning: this function changes the amount of node inputs to 0!
|
||||
**/
|
||||
function clearOutputs() {
|
||||
for (links in outputs) {
|
||||
for (link in links) {
|
||||
var defaultNode = LogicNode.createSocketDefaultNode(tree, link.toType, link.toValue);
|
||||
link.fromNode = defaultNode;
|
||||
link.fromIndex = 0;
|
||||
defaultNode.outputs[0] = [link];
|
||||
}
|
||||
}
|
||||
outputs.resize(0);
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a default node for a socket so that get() and set() can be
|
||||
used without null checks.
|
||||
Loosely equivalent to `make_logic.build_default_node()` in Python.
|
||||
**/
|
||||
static inline function createSocketDefaultNode(tree: LogicTree, socketType: String, value: Dynamic): LogicNode {
|
||||
// Make sure to not add these nodes to the LogicTree.nodes array as they
|
||||
// won't be garbage collected then if unlinked later.
|
||||
return switch (socketType) {
|
||||
case "VECTOR": new armory.logicnode.VectorNode(tree, value[0], value[1], value[2]);
|
||||
case "RGBA": new armory.logicnode.ColorNode(tree, value[0], value[1], value[2], value[3]);
|
||||
case "RGB": new armory.logicnode.ColorNode(tree, value[0], value[1], value[2]);
|
||||
case "VALUE": new armory.logicnode.FloatNode(tree, value);
|
||||
case "INT": new armory.logicnode.IntegerNode(tree, value);
|
||||
case "BOOLEAN": new armory.logicnode.BooleanNode(tree, value);
|
||||
case "STRING": new armory.logicnode.StringNode(tree, value);
|
||||
case "NONE": new armory.logicnode.NullNode(tree);
|
||||
case "OBJECT": new armory.logicnode.ObjectNode(tree, value);
|
||||
default: new armory.logicnode.DynamicNode(tree, value);
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
/**
|
||||
Called when this node is activated.
|
||||
@param from impulse index
|
||||
|
@ -38,42 +143,45 @@ class LogicNode {
|
|||
**/
|
||||
function runOutput(i: Int) {
|
||||
if (i >= outputs.length) return;
|
||||
for (o in outputs[i]) {
|
||||
// Check which input activated the node
|
||||
for (j in 0...o.inputs.length) {
|
||||
if (o.inputs[j].node == this) {
|
||||
o.run(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (outLink in outputs[i]) {
|
||||
outLink.toNode.run(outLink.toIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@:allow(armory.logicnode.LogicNodeInput)
|
||||
@:allow(armory.logicnode.LogicNodeLink)
|
||||
function get(from: Int): Dynamic { return this; }
|
||||
|
||||
@:allow(armory.logicnode.LogicNodeInput)
|
||||
@:allow(armory.logicnode.LogicNodeLink)
|
||||
function set(value: Dynamic) {}
|
||||
}
|
||||
|
||||
class LogicNodeInput {
|
||||
@:allow(armory.logicnode.LogicNode)
|
||||
@:allow(armory.logicnode.LogicTree)
|
||||
class LogicNodeLink {
|
||||
|
||||
@:allow(armory.logicnode.LogicNode)
|
||||
var node: LogicNode;
|
||||
var from: Int; // Socket index
|
||||
var fromNode: LogicNode;
|
||||
var toNode: LogicNode;
|
||||
var fromIndex: Int;
|
||||
var toIndex: Int;
|
||||
|
||||
public function new(node: LogicNode, from: Int) {
|
||||
this.node = node;
|
||||
this.from = from;
|
||||
#if arm_patch
|
||||
var fromType: String;
|
||||
var toType: String;
|
||||
var toValue: Dynamic;
|
||||
#end
|
||||
|
||||
inline function new(fromNode: LogicNode, toNode: LogicNode, fromIndex: Int, toIndex: Int) {
|
||||
this.fromNode = fromNode;
|
||||
this.toNode = toNode;
|
||||
this.fromIndex = fromIndex;
|
||||
this.toIndex = toIndex;
|
||||
}
|
||||
|
||||
@:allow(armory.logicnode.LogicNode)
|
||||
function get(): Dynamic {
|
||||
return node.get(from);
|
||||
inline function get(): Dynamic {
|
||||
return fromNode.get(fromIndex);
|
||||
}
|
||||
|
||||
@:allow(armory.logicnode.LogicNode)
|
||||
function set(value: Dynamic) {
|
||||
node.set(value);
|
||||
inline function set(value: Dynamic) {
|
||||
fromNode.set(value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,26 @@ package armory.logicnode;
|
|||
|
||||
class LogicTree extends iron.Trait {
|
||||
|
||||
#if arm_patch
|
||||
/**
|
||||
Stores all trait instances of the tree via its name.
|
||||
**/
|
||||
public static var nodeTrees = new Map<String, Array<LogicTree>>();
|
||||
|
||||
/**
|
||||
[node name => logic node] for later node replacement for live patching.
|
||||
**/
|
||||
public var nodes: Map<String, LogicNode>;
|
||||
#end
|
||||
|
||||
public var loopBreak = false; // Trigger break from loop nodes
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
#if arm_patch
|
||||
nodes = new Map<String, LogicNode>();
|
||||
#end
|
||||
}
|
||||
|
||||
public function add() {}
|
||||
|
|
|
@ -37,6 +37,6 @@ class LookAtNode extends LogicNode {
|
|||
v2.setFrom(vto).sub(vfrom).normalize();
|
||||
|
||||
q.fromTo(v1, v2);
|
||||
return q.getEuler();
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package armory.logicnode;
|
|||
class MathNode extends LogicNode {
|
||||
|
||||
public var property0: String; // Operation
|
||||
public var property1: String; // Clamp
|
||||
public var property1: Bool; // Clamp
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
@ -80,8 +80,8 @@ class MathNode extends LogicNode {
|
|||
}
|
||||
}
|
||||
// Clamp
|
||||
if (property1 == "true") r = r < 0.0 ? 0.0 : (r > 1.0 ? 1.0 : r);
|
||||
if (property1) r = r < 0.0 ? 0.0 : (r > 1.0 ? 1.0 : r);
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,31 @@ package armory.logicnode;
|
|||
|
||||
class MergeNode extends LogicNode {
|
||||
|
||||
/** Execution mode. **/
|
||||
public var property0: String;
|
||||
|
||||
var lastInputIndex = -1;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
tree.notifyOnLateUpdate(lateUpdate);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
// Check if there already were executions on the same frame
|
||||
if (lastInputIndex != -1 && property0 == "once_per_frame") {
|
||||
return;
|
||||
}
|
||||
|
||||
lastInputIndex = from;
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
return lastInputIndex;
|
||||
}
|
||||
|
||||
function lateUpdate() {
|
||||
lastInputIndex = -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ class MixNode extends LogicNode {
|
|||
|
||||
public var property0: String; // Type
|
||||
public var property1: String; // Ease
|
||||
public var property2: String; // Clamp
|
||||
public var property2: Bool; // Clamp
|
||||
|
||||
var ease: Float->Float = null;
|
||||
|
||||
|
@ -50,7 +50,9 @@ class MixNode extends LogicNode {
|
|||
var v2: Float = inputs[2].get();
|
||||
var f = v1 + (v2 - v1) * ease(k);
|
||||
|
||||
if (property2 == "true") f = f < 0 ? 0 : f > 1 ? 1 : f;
|
||||
// Clamp
|
||||
if (property2) f = f < 0 ? 0 : f > 1 ? 1 : f;
|
||||
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class ObjectNode extends LogicNode {
|
|||
override function set(value: Dynamic) {
|
||||
if (inputs.length > 0) inputs[0].set(value);
|
||||
else {
|
||||
objectName = value.name;
|
||||
objectName = value != null ? value.name : "";
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import armory.trait.internal.CanvasScript;
|
|||
import iron.Scene;
|
||||
|
||||
#if arm_ui
|
||||
import zui.Canvas.Anchor;
|
||||
import armory.ui.Canvas.Anchor;
|
||||
#end
|
||||
|
||||
class OnCanvasElementNode extends LogicNode {
|
||||
|
|
35
Sources/armory/logicnode/OnInputMapNode.hx
Normal file
35
Sources/armory/logicnode/OnInputMapNode.hx
Normal file
|
@ -0,0 +1,35 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class OnInputMapNode extends LogicNode {
|
||||
|
||||
var inputMap: Null<InputMap>;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
||||
tree.notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
function update() {
|
||||
var i = inputs[0].get();
|
||||
|
||||
inputMap = InputMap.getInputMap(i);
|
||||
|
||||
if (inputMap != null) {
|
||||
if (inputMap.started()) {
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
if (inputMap.released()) {
|
||||
runOutput(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
if (from == 2) return inputMap.value();
|
||||
else return inputMap.lastKeyPressed;
|
||||
}
|
||||
}
|
|
@ -120,8 +120,8 @@ class OnSwipeNode extends LogicNode {
|
|||
switch (from) {
|
||||
// UP
|
||||
case 1: {
|
||||
// 68 - 121
|
||||
if ((angle >= 68) && (angle < 121)) return true;
|
||||
// 68 - 112
|
||||
if ((angle >= 68) && (angle < 112)) return true;
|
||||
return false;
|
||||
}
|
||||
// DOWN
|
||||
|
@ -144,8 +144,8 @@ class OnSwipeNode extends LogicNode {
|
|||
}
|
||||
// UP-LEFT
|
||||
case 5: {
|
||||
// 121 - 158
|
||||
if ((angle >= 121) && (angle < 158)) return true;
|
||||
// 112 - 158
|
||||
if ((angle >= 112) && (angle < 158)) return true;
|
||||
return false;
|
||||
}
|
||||
// UP-RIGHT
|
||||
|
|
|
@ -37,11 +37,11 @@ class OnVolumeTriggerNode extends LogicNode {
|
|||
|
||||
var b = false;
|
||||
switch (property0) {
|
||||
case "enter":
|
||||
case "begin":
|
||||
b = overlap && !lastOverlap;
|
||||
case "overlap":
|
||||
b = overlap;
|
||||
case "leave":
|
||||
case "end":
|
||||
b = !overlap && lastOverlap;
|
||||
}
|
||||
|
||||
|
|
22
Sources/armory/logicnode/OncePerFrameNode.hx
Normal file
22
Sources/armory/logicnode/OncePerFrameNode.hx
Normal file
|
@ -0,0 +1,22 @@
|
|||
package armory.logicnode;
|
||||
|
||||
class OncePerFrameNode extends LogicNode {
|
||||
|
||||
var c = false;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
tree.notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
if(c) {
|
||||
c = false;
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
c = true;
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ class PauseTraitNode extends LogicNode {
|
|||
|
||||
override function run(from: Int) {
|
||||
var trait: Dynamic = inputs[1].get();
|
||||
if (trait == null || !Std.is(trait, LogicTree)) return;
|
||||
if (trait == null || !Std.isOfType(trait, LogicTree)) return;
|
||||
|
||||
cast(trait, LogicTree).pause();
|
||||
|
||||
|
|
41
Sources/armory/logicnode/PhysicsConstraintNode.hx
Normal file
41
Sources/armory/logicnode/PhysicsConstraintNode.hx
Normal file
|
@ -0,0 +1,41 @@
|
|||
package armory.logicnode;
|
||||
|
||||
#if arm_physics
|
||||
import armory.trait.physics.bullet.PhysicsConstraint.ConstraintAxis;
|
||||
#end
|
||||
|
||||
class PhysicsConstraintNode extends LogicNode {
|
||||
|
||||
public var property0: String; //Linear or Angular
|
||||
public var property1: String; //Axis
|
||||
public var property2: Bool; //Is a spring
|
||||
|
||||
#if arm_physics
|
||||
public var value1: Float; //Lower limit or Spring Stiffness
|
||||
public var value2: Float; //Upper limit or Spring Damping
|
||||
public var isAngular: Bool;
|
||||
public var axis: ConstraintAxis;
|
||||
public var isSpring: Bool;
|
||||
#end
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): PhysicsConstraintNode {
|
||||
#if arm_physics
|
||||
value1 = inputs[0].get();
|
||||
value2 = inputs[1].get();
|
||||
|
||||
isAngular = property0 != "Linear";
|
||||
isSpring = property2;
|
||||
|
||||
switch (property1) {
|
||||
case "X": axis = X;
|
||||
case "Y": axis = Y;
|
||||
case "Z": axis = Z;
|
||||
}
|
||||
#end
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ class PickLocationNode extends LogicNode {
|
|||
var object: Object = inputs[0].get();
|
||||
var coords: Vec4 = inputs[1].get();
|
||||
|
||||
if (object == null || coords == null) null;
|
||||
if (object == null || coords == null) return null;
|
||||
|
||||
#if arm_physics
|
||||
var physics = armory.trait.physics.PhysicsWorld.active;
|
||||
|
|
|
@ -4,28 +4,32 @@ import iron.math.Vec4;
|
|||
|
||||
class PickObjectNode extends LogicNode {
|
||||
|
||||
var v = new Vec4();
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var coords: Vec4 = inputs[0].get();
|
||||
var mask: Int = inputs[1].get();
|
||||
|
||||
if (coords == null) return null;
|
||||
|
||||
#if arm_physics
|
||||
var physics = armory.trait.physics.PhysicsWorld.active;
|
||||
var rb = physics.pickClosest(coords.x, coords.y);
|
||||
var rb = physics.pickClosest(coords.x, coords.y, mask);
|
||||
if (rb == null) return null;
|
||||
|
||||
if (from == 0) { // Object
|
||||
return rb.object;
|
||||
}
|
||||
else { // Hit
|
||||
else if(from == 1){ // Hit
|
||||
var v = new Vec4();
|
||||
return v.set(physics.hitPointWorld.x, physics.hitPointWorld.y, physics.hitPointWorld.z);
|
||||
}
|
||||
else { // Normal
|
||||
var v = new Vec4();
|
||||
return v.set(physics.hitNormalWorld.x, physics.hitNormalWorld.y, physics.hitNormalWorld.z, 0);
|
||||
}
|
||||
#end
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ class PlayActionFromNode extends LogicNode {
|
|||
var action: String = inputs[2].get();
|
||||
var startFrame:Int = inputs[3].get();
|
||||
var blendTime: Float = inputs[4].get();
|
||||
var speed: Float = inputs[5].get();
|
||||
var loop: Bool = inputs[6].get();
|
||||
|
||||
|
||||
if (object == null) return;
|
||||
|
@ -22,7 +24,7 @@ class PlayActionFromNode extends LogicNode {
|
|||
|
||||
animation.play(action, function() {
|
||||
runOutput(1);
|
||||
},blendTime);
|
||||
}, blendTime, speed, loop);
|
||||
animation.update(startFrame*Scene.active.raw.frame_time);
|
||||
|
||||
runOutput(0);
|
||||
|
|
|
@ -12,6 +12,8 @@ class PlaySoundRawNode extends LogicNode {
|
|||
public var property3: Bool;
|
||||
/** Playback sample rate */
|
||||
public var property4: Int;
|
||||
/** Whether to stream the sound from disk **/
|
||||
public var property5: Bool;
|
||||
|
||||
var sound: kha.Sound = null;
|
||||
var channel: kha.audio1.AudioChannel = null;
|
||||
|
@ -37,7 +39,7 @@ class PlaySoundRawNode extends LogicNode {
|
|||
// Start
|
||||
else if (sound != null) {
|
||||
if (property3) sound.sampleRate = property4;
|
||||
channel = iron.system.Audio.play(sound, property1);
|
||||
channel = iron.system.Audio.play(sound, property1, property5);
|
||||
}
|
||||
|
||||
tree.notifyOnUpdate(this.onUpdate);
|
||||
|
|
|
@ -19,7 +19,7 @@ class QuaternionMathNode extends LogicNode {
|
|||
|
||||
override function get(from: Int): Dynamic {
|
||||
switch (property0) {
|
||||
// 1 argument: Module, Normalize, GetEuler
|
||||
// 1 argument: Module, Normalize
|
||||
case "Module": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
|
@ -32,159 +32,106 @@ class QuaternionMathNode extends LogicNode {
|
|||
res_q.setFrom(q);
|
||||
res_q = res_q.normalize();
|
||||
}
|
||||
case "GetEuler": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
res_v = res_q.getEuler();
|
||||
}
|
||||
// 2 arguments: FromTo, FromMat, FromRotationMat, ToAxisAngle
|
||||
case "FromTo": {
|
||||
var v1: Vec4 = inputs[0].get();
|
||||
var v2: Vec4 = inputs[1].get();
|
||||
if ((v1 == null) || (v2 == null)) return null;
|
||||
res_q.fromTo(v1, v2);
|
||||
}
|
||||
case "FromMat": {
|
||||
var q: Quat = inputs[0].get();
|
||||
var m: Mat4 = inputs[1].get();
|
||||
if ((q == null) || (m == null)) return null;
|
||||
res_q.setFrom(q);
|
||||
res_q = res_q.fromMat(m);
|
||||
}
|
||||
case "FromRotationMat": {
|
||||
var q: Quat = inputs[0].get();
|
||||
var m: Mat4 = inputs[1].get();
|
||||
if ((q == null) || (m == null)) return null;
|
||||
res_q.setFrom(q);
|
||||
res_q = res_q.fromRotationMat(m);
|
||||
}
|
||||
case "ToAxisAngle": {
|
||||
var q: Quat = inputs[0].get();
|
||||
var v: Vec4 = inputs[1].get();
|
||||
if ((q == null) || (v == null)) return null;
|
||||
res_q.setFrom(q);
|
||||
res_f = res_q.toAxisAngle(v);
|
||||
}
|
||||
// # 3 arguments: Lerp, Slerp, FromAxisAngle, FromEuler
|
||||
case "Lerp": {
|
||||
var from: Quat = inputs[0].get();
|
||||
var to: Quat = inputs[1].get();
|
||||
var f: Float = inputs[2].get();
|
||||
if ((from == null) || (to == null)) return null;
|
||||
res_q = res_q.lerp(from, to, f);
|
||||
}
|
||||
case "Slerp": {
|
||||
var from: Quat = inputs[0].get();
|
||||
var to: Quat = inputs[1].get();
|
||||
var f: Float = inputs[2].get();
|
||||
if ((from == null) || (to == null)) return null;
|
||||
res_q = res_q.slerp(from, to, f);
|
||||
}
|
||||
case "FromAxisAngle": {
|
||||
var q: Quat = inputs[0].get();
|
||||
var axis: Vec4 = inputs[1].get();
|
||||
var angle: Float = inputs[2].get();
|
||||
if ((q == null) || (axis == null)) return null;
|
||||
res_q.setFrom(q);
|
||||
res_q = res_q.fromAxisAngle(axis, angle);
|
||||
}
|
||||
case "FromEuler": {
|
||||
var x: Float = inputs[0].get();
|
||||
var y: Float = inputs[1].get();
|
||||
var z: Float = inputs[2].get();
|
||||
res_q = res_q.fromEuler(x, y, z);
|
||||
}
|
||||
// Many arguments: Add, Subtract, DotProduct, Multiply
|
||||
case "Add": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
var q2 = new Quat();
|
||||
res_v = inputs[0].get();
|
||||
res_f = inputs[1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
|
||||
res_q.set(res_v.x, res_v.y, res_v.z, res_f);
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
q2 = inputs[i].get();
|
||||
if (q2 == null) return null;
|
||||
res_q.add(q2);
|
||||
while (2*i+1 < inputs.length) {
|
||||
res_v = inputs[2*i].get();
|
||||
res_f = inputs[2*i+1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
res_q.x += res_v.x;
|
||||
res_q.y += res_v.y;
|
||||
res_q.z += res_v.z;
|
||||
res_q.w += res_f;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "Subtract": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
var q2 = new Quat();
|
||||
res_v = inputs[0].get();
|
||||
res_f = inputs[1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
|
||||
res_q.set(res_v.x, res_v.y, res_v.z, res_f);
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
q2 = inputs[i].get();
|
||||
if (q2 == null) return null;
|
||||
res_q.sub(q2);
|
||||
while (2*i+1 < inputs.length) {
|
||||
res_v = inputs[2*i].get();
|
||||
res_f = inputs[2*i+1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
res_q.x -= res_v.x;
|
||||
res_q.y -= res_v.y;
|
||||
res_q.z -= res_v.z;
|
||||
res_q.w -= res_f;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "Multiply": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
var q2 = new Quat();
|
||||
res_v = inputs[0].get();
|
||||
res_f = inputs[1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
|
||||
res_q.set(res_v.x, res_v.y, res_v.z, res_f);
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
q2 = inputs[i].get();
|
||||
if (q2 == null) return null;
|
||||
res_q.mult(q2);
|
||||
while (2*i+1 < inputs.length) {
|
||||
res_v = inputs[2*i].get();
|
||||
res_f = inputs[2*i+1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
var temp_q = new Quat(res_v.x, res_v.y, res_v.z, res_f);
|
||||
res_q.mult(temp_q);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "MultiplyFloats": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
res_v = inputs[0].get();
|
||||
res_f = inputs[1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
|
||||
res_q.set(res_v.x, res_v.y, res_v.z, res_f);
|
||||
var f: Float = 1.0;
|
||||
var i = 1;
|
||||
var i = 2;
|
||||
while (i < inputs.length) {
|
||||
f = inputs[i].get();
|
||||
res_q.scale(f);
|
||||
f *= inputs[i].get();
|
||||
if (f == null) return null;
|
||||
i++;
|
||||
}
|
||||
res_q.scale(f);
|
||||
}
|
||||
case "DotProduct": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
var q2 = new Quat();
|
||||
case "DotProduct": { // what this does with more than 2 terms is not *remotely* intuitive. Heck, you could consider it a footgun!
|
||||
|
||||
res_v = inputs[0].get();
|
||||
var temp_f = inputs[1].get();
|
||||
if (res_v == null || temp_f == null) return null;
|
||||
|
||||
res_q.set(res_v.x, res_v.y, res_v.z, temp_f);
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
q2 = inputs[i].get();
|
||||
if (q2 == null) return null;
|
||||
res_f = res_q.dot(q2);
|
||||
while (2*i+1 < inputs.length) {
|
||||
res_v = inputs[2*i].get();
|
||||
temp_f = inputs[2*i+1].get();
|
||||
if (res_v == null || temp_f == null) return null;
|
||||
var temp_q = new Quat(res_v.x, res_v.y, res_v.z, temp_f);
|
||||
res_f = res_q.dot(temp_q);
|
||||
res_q.set(res_f, res_f, res_f, res_f);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return and check separator
|
||||
switch (from) {
|
||||
case 0: {
|
||||
if (property0 == 'GetEuler')
|
||||
return res_v;
|
||||
else
|
||||
return res_q;
|
||||
return res_q;
|
||||
}
|
||||
case 1:
|
||||
if (property1) {
|
||||
return res_q.x;
|
||||
} else {
|
||||
if (property0 == "DotProduct" || property0 == "Module") {
|
||||
return res_f;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
case 2:
|
||||
if (property1) return res_q.y;
|
||||
case 3:
|
||||
if (property1) return res_q.z;
|
||||
case 4:
|
||||
if (property1) return res_q.w;
|
||||
case 5:
|
||||
if (property1) return res_f;
|
||||
default: {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -11,10 +11,10 @@ class QuaternionNode extends LogicNode {
|
|||
super(tree);
|
||||
|
||||
if (x != null) {
|
||||
addInput(new FloatNode(tree, x), 0);
|
||||
addInput(new FloatNode(tree, y), 0);
|
||||
addInput(new FloatNode(tree, z), 0);
|
||||
addInput(new FloatNode(tree, w), 0);
|
||||
LogicNode.addLink(new FloatNode(tree, x), this, 0, 0);
|
||||
LogicNode.addLink(new FloatNode(tree, y), this, 0, 1);
|
||||
LogicNode.addLink(new FloatNode(tree, z), this, 0, 2);
|
||||
LogicNode.addLink(new FloatNode(tree, w), this, 0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,15 +27,15 @@ class QuaternionNode extends LogicNode {
|
|||
switch (from){
|
||||
case 0:
|
||||
return value;
|
||||
case 1:
|
||||
var value1 = new Vec4();
|
||||
case 1:
|
||||
var value1 = new Vec4();
|
||||
value1.x = value.x;
|
||||
value1.y = value.y;
|
||||
value1.z = value.z;
|
||||
value1.w = 0; // use 0 to avoid this vector being translated.
|
||||
return value1;
|
||||
case 2:
|
||||
return value.w;
|
||||
return value.w;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -4,18 +4,17 @@ import iron.math.Vec4;
|
|||
|
||||
class RandomColorNode extends LogicNode {
|
||||
|
||||
var v = new Vec4();
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
|
||||
var r = Math.random();
|
||||
var g = Math.random();
|
||||
var b = Math.random();
|
||||
// var a = Math.random();
|
||||
v.set(r, g, b);
|
||||
var v = new Vec4(r, g, b);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
|
19
Sources/armory/logicnode/RemoveInputMapKeyNode.hx
Normal file
19
Sources/armory/logicnode/RemoveInputMapKeyNode.hx
Normal file
|
@ -0,0 +1,19 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class RemoveInputMapKeyNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var inputMap = inputs[1].get();
|
||||
var key = inputs[2].get();
|
||||
|
||||
if (InputMap.removeInputMapKey(inputMap, key)) {
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ class ResumeTraitNode extends LogicNode {
|
|||
|
||||
override function run(from: Int) {
|
||||
var trait: Dynamic = inputs[1].get();
|
||||
if (trait == null || !Std.is(trait, LogicTree)) return;
|
||||
if (trait == null || !Std.isOfType(trait, LogicTree)) return;
|
||||
|
||||
cast(trait, LogicTree).resume();
|
||||
|
||||
|
|
|
@ -2,13 +2,11 @@ package armory.logicnode;
|
|||
|
||||
import iron.object.Object;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
import armory.trait.physics.RigidBody;
|
||||
|
||||
class RotateObjectNode extends LogicNode {
|
||||
|
||||
public var property0 = "Euler Angles";
|
||||
var q = new Quat();
|
||||
public var property0 = "Local";
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
@ -16,32 +14,19 @@ class RotateObjectNode extends LogicNode {
|
|||
|
||||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
var vec: Vec4 = inputs[2].get();
|
||||
var q: Quat = inputs[2].get();
|
||||
|
||||
// note: here, the next line is disabled because old versions of the node don't have a third input.
|
||||
// when those old versions will be considered remove, feel free to uncomment that, and replace the other `inputs[3].get()` by `w` in this file.
|
||||
//var w: Float = inputs[3].get();
|
||||
if (object == null || q == null) return;
|
||||
|
||||
if (object == null || vec == null) return;
|
||||
|
||||
switch (property0) {
|
||||
case "Euler Angles":
|
||||
q.fromEuler(vec.x, vec.y, vec.z);
|
||||
case "Angle Axies (Degrees)" | "Angle Axies (Radians)":
|
||||
var angle: Float = inputs[3].get();
|
||||
if (property0 == "Angle Axies (Degrees)") {
|
||||
angle = angle * (Math.PI / 180);
|
||||
}
|
||||
var angleSin = Math.sin(angle / 2);
|
||||
vec = vec.normalize();
|
||||
var angleCos = Math.cos(angle / 2);
|
||||
q = new Quat(vec.x * angleSin, vec.y * angleSin, vec.z * angleSin, angleCos);
|
||||
case "Quaternion":
|
||||
q = new Quat(vec.x, vec.y, vec.z, inputs[3].get());
|
||||
q.normalize();
|
||||
q.normalize();
|
||||
switch (property0){
|
||||
case "Local":
|
||||
object.transform.rot.mult(q);
|
||||
case "Global":
|
||||
object.transform.rot.multquats(q, object.transform.rot);
|
||||
// that function call (Quat.multquats) is weird: it both modifies the object, and returns `this`
|
||||
}
|
||||
|
||||
object.transform.rot.mult(q);
|
||||
|
||||
object.transform.buildMatrix();
|
||||
|
||||
#if arm_physics
|
||||
|
|
96
Sources/armory/logicnode/RotationMathNode.hx
Normal file
96
Sources/armory/logicnode/RotationMathNode.hx
Normal file
|
@ -0,0 +1,96 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Mat4;
|
||||
import kha.FastFloat;
|
||||
|
||||
class RotationMathNode extends LogicNode {
|
||||
|
||||
public var property0: String; // Operation
|
||||
var res_q = new Quat();
|
||||
var res_v = new Vec4();
|
||||
var res_f: FastFloat = 0.0;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
//var q: Quat = inputs[0].get();
|
||||
//if (q==null) return null;
|
||||
|
||||
//var res_q: Quat = new Quat();
|
||||
switch (property0) {
|
||||
// 1 argument: Normalize, Inverse
|
||||
case "Normalize": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q==null) return null;
|
||||
res_q.setFrom(q);
|
||||
res_q = res_q.normalize();
|
||||
}
|
||||
case "Inverse": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q==null) return null;
|
||||
var modl = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
|
||||
modl = -1/modl;
|
||||
res_q.w = -q.w*modl;
|
||||
res_q.x = q.x*modl;
|
||||
res_q.y = q.y*modl;
|
||||
res_q.z = q.z*modl;
|
||||
}
|
||||
// 2 arguments: Compose, Amplify, FromTo, FromRotationMat,
|
||||
case "FromTo": {
|
||||
var v1: Vec4 = inputs[0].get();
|
||||
var v2: Vec4 = inputs[1].get();
|
||||
if ((v1 == null) || (v2 == null)) return null;
|
||||
res_q.fromTo(v1, v2);
|
||||
}
|
||||
case "Compose": {
|
||||
var v1: Quat = inputs[0].get();
|
||||
var v2: Quat = inputs[1].get();
|
||||
if ((v1 == null) || (v2 == null)) return null;
|
||||
res_q.multquats(v1,v2);
|
||||
}
|
||||
case "Amplify": {
|
||||
var v1: Quat = inputs[0].get();
|
||||
var v2: Float = inputs[1].get();
|
||||
if ((v1 == null) || (v2 == null)) return null;
|
||||
res_q.setFrom(v1);
|
||||
var fac2 = Math.sqrt(1- res_q.w*res_q.w);
|
||||
if (fac2 > 0.001) {
|
||||
var fac1 = v2*Math.acos(res_q.w);
|
||||
res_q.w = Math.cos(fac1);
|
||||
fac1 = Math.sin(fac1)/fac2;
|
||||
res_q.x *= fac1;
|
||||
res_q.y *= fac1;
|
||||
res_q.z *= fac1;
|
||||
}
|
||||
}
|
||||
//case "FromRotationMat": {
|
||||
// var m: Mat4 = inputs[1].get();
|
||||
// if (m == null) return null;
|
||||
|
||||
// res_q = res_q.fromMat(m);
|
||||
//}
|
||||
// # 3 arguments: Lerp, Slerp, FromAxisAngle, FromEuler
|
||||
case "Lerp": {
|
||||
//var from = q;
|
||||
var from: Quat = inputs[0].get();
|
||||
var to: Quat = inputs[1].get();
|
||||
var f: Float = inputs[2].get();
|
||||
if ((from == null) || (f == null) || (to == null)) return null;
|
||||
res_q = res_q.lerp(from, to, f);
|
||||
}
|
||||
case "Slerp": {
|
||||
//var from = q;
|
||||
var from:Quat = inputs[0].get();
|
||||
var to: Quat = inputs[1].get();
|
||||
var f: Float = inputs[2].get();
|
||||
if ((from == null) || (f == null) || (to == null)) return null;
|
||||
res_q = res_q.slerp(from, to, f);
|
||||
}
|
||||
}
|
||||
return res_q;
|
||||
}
|
||||
}
|
120
Sources/armory/logicnode/RotationNode.hx
Normal file
120
Sources/armory/logicnode/RotationNode.hx
Normal file
|
@ -0,0 +1,120 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import kha.FastFloat;
|
||||
|
||||
class RotationNode extends LogicNode {
|
||||
|
||||
static inline var toRAD: FastFloat = 0.017453292519943295; // 180/pi
|
||||
|
||||
public var property0: String; // type of input (EulerAngles, AxisAngle, Quaternion)
|
||||
public var property1: String; // angle unit (Deg, Rad)
|
||||
public var property2: String; // euler order (XYZ, XZY, etc…)
|
||||
|
||||
public var value: Quat;
|
||||
//var input0_cache: Vec4 = new Vec4();
|
||||
//var input1_cache: Float = 0;
|
||||
var input_length: Int = 0;
|
||||
|
||||
public function new(tree: LogicTree, x: Null<Float> = null,
|
||||
y: Null<Float> = null,
|
||||
z: Null<Float> = null,
|
||||
w: Null<Float> = null
|
||||
) {
|
||||
super(tree);
|
||||
this.value = new Quat();
|
||||
if (x!=null) this.value.set(x,y,z,w);
|
||||
for (input in inputs) {
|
||||
if (input !=null)
|
||||
this.input_length +=1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
//var inp0 = inputs[0].get();
|
||||
//var inp
|
||||
//if (inputs[0].get())
|
||||
if (inputs.length == 0){
|
||||
return this.value;
|
||||
}
|
||||
|
||||
switch (property0){
|
||||
case "Quaternion": {
|
||||
if (inputs[0]!=null && inputs[1]!=null) {
|
||||
var vect: Vec4 = inputs[0].get();
|
||||
value.x = vect.x;
|
||||
value.y = vect.y;
|
||||
value.z = vect.z;
|
||||
value.w = inputs[1].get();
|
||||
}
|
||||
}
|
||||
case "AxisAngle": {
|
||||
if (inputs[0]!=null && inputs[1]!=null){
|
||||
var vec: Vec4 = inputs[0].get();
|
||||
var angle: FastFloat = inputs[1].get();
|
||||
if (property1=="Deg")
|
||||
angle *= toRAD;
|
||||
value.fromAxisAngle(vec, angle);
|
||||
}
|
||||
}
|
||||
case "EulerAngles": {
|
||||
if (inputs[0] != null){
|
||||
var vec: Vec4 = new Vec4().setFrom(inputs[0].get());
|
||||
if (property1=="Deg"){
|
||||
vec.x *= toRAD;
|
||||
vec.y *= toRAD;
|
||||
vec.z *= toRAD;
|
||||
}
|
||||
this.value.fromEulerOrdered(vec, property2);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return property0;
|
||||
}
|
||||
}
|
||||
return this.value;
|
||||
}
|
||||
|
||||
override function set(value: Dynamic) {
|
||||
switch (property0){
|
||||
case "Quaternion": {
|
||||
if (input_length>1) {
|
||||
var vect = new Vec4();
|
||||
vect.x = value.x;
|
||||
vect.y = value.y;
|
||||
vect.z = value.z;
|
||||
inputs[0].set(vect);
|
||||
inputs[1].set(value.w);
|
||||
}
|
||||
}
|
||||
case "AxisAngle": {
|
||||
if (input_length>1){
|
||||
var vec = new Vec4();
|
||||
var angle = this.value.toAxisAngle(vec);
|
||||
if (property1=="Deg")
|
||||
angle /= toRAD;
|
||||
inputs[0].set(vec);
|
||||
inputs[1].set(angle);
|
||||
|
||||
}
|
||||
}
|
||||
case "EulerAngles": {
|
||||
if (input_length>0){
|
||||
var vec:Vec4 = value.toEulerOrdered(property2);
|
||||
if (property1=="Deg"){
|
||||
vec.x /= toRAD;
|
||||
vec.y /= toRAD;
|
||||
vec.z /= toRAD;
|
||||
}
|
||||
inputs[0].set(vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (input_length > 0){
|
||||
// NYI
|
||||
}else this.value=value;
|
||||
}
|
||||
}
|
37
Sources/armory/logicnode/SelectNode.hx
Normal file
37
Sources/armory/logicnode/SelectNode.hx
Normal file
|
@ -0,0 +1,37 @@
|
|||
package armory.logicnode;
|
||||
|
||||
class SelectNode extends LogicNode {
|
||||
|
||||
/** Execution mode. **/
|
||||
public var property0: String;
|
||||
|
||||
var value: Dynamic = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
// Get value according to the activated input (run() can only be called
|
||||
// if the execution mode is from_input).
|
||||
value = inputs[from + Std.int(inputs.length / 2)].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
if (property0 == "from_index") {
|
||||
var index = inputs[0].get() + 2;
|
||||
|
||||
// Return default value for invalid index
|
||||
if (index < 2 || index >= inputs.length) {
|
||||
return inputs[1].get();
|
||||
}
|
||||
|
||||
return inputs[index].get();
|
||||
}
|
||||
|
||||
// from_input
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -5,8 +5,6 @@ import armory.system.Event;
|
|||
|
||||
class SendEventNode extends LogicNode {
|
||||
|
||||
var entries: Array<TEvent> = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
@ -17,13 +15,9 @@ class SendEventNode extends LogicNode {
|
|||
|
||||
if (object == null) return;
|
||||
|
||||
var all = Event.get(name);
|
||||
if (all != null) {
|
||||
entries = [];
|
||||
for (e in all) if (e.mask == object.uid) entries.push(e);
|
||||
}
|
||||
var entries = Event.get(name);
|
||||
if (entries == null) return;
|
||||
for (e in entries) e.onEvent();
|
||||
for (e in entries) if (e.mask == object.uid) e.onEvent();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@ import armory.system.Event;
|
|||
|
||||
class SendGlobalEventNode extends LogicNode {
|
||||
|
||||
var entries: Array<TEvent> = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
@ -13,7 +11,7 @@ class SendGlobalEventNode extends LogicNode {
|
|||
override function run(from: Int) {
|
||||
var name: String = inputs[1].get();
|
||||
|
||||
entries = Event.get(name);
|
||||
var entries = Event.get(name);
|
||||
if (entries == null) return; // Event does not exist
|
||||
for (e in entries) e.onEvent();
|
||||
|
||||
|
|
60
Sources/armory/logicnode/SeparateRotationNode.hx
Normal file
60
Sources/armory/logicnode/SeparateRotationNode.hx
Normal file
|
@ -0,0 +1,60 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import kha.FastFloat;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
|
||||
class SeparateRotationNode extends LogicNode {
|
||||
|
||||
public var property0 = "EulerAngles"; // EulerAngles, AxisAngle, or Quat
|
||||
public var property1 = "Rad"; // Rad or Deg
|
||||
public var property2 = "XYZ";
|
||||
|
||||
static inline var toDEG:FastFloat = 57.29577951308232; // 180/pi
|
||||
|
||||
var input_cache = new Quat();
|
||||
var euler_cache = new Vec4();
|
||||
var aa_axis_cache = new Vec4();
|
||||
var aa_angle_cache: Float = 0;
|
||||
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
q.normalize();
|
||||
|
||||
switch (property0) {
|
||||
case "EulerAngles":
|
||||
if (q!=this.input_cache)
|
||||
euler_cache = q.toEulerOrdered(property2);
|
||||
if (from>0)
|
||||
return null;
|
||||
|
||||
switch (property1){
|
||||
case "Rad": return euler_cache;
|
||||
case "Deg": return new Vec4(euler_cache.x*toDEG, euler_cache.y*toDEG, euler_cache.z*toDEG);
|
||||
}
|
||||
|
||||
case "AxisAngle":
|
||||
if (q!=this.input_cache)
|
||||
aa_angle_cache = q.toAxisAngle(aa_axis_cache);
|
||||
switch (from){
|
||||
case 0: return aa_axis_cache;
|
||||
case 1: switch(property1){
|
||||
case "Rad": return aa_angle_cache;
|
||||
case "Deg": return toDEG*aa_angle_cache;
|
||||
}
|
||||
}
|
||||
case "Quaternion":
|
||||
switch(from){
|
||||
case 0: return new Vec4(q.x,q.y,q.z);
|
||||
case 1: return q.w;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ class SeparateTransformNode extends LogicNode {
|
|||
matrix.decompose(loc, rot, scale);
|
||||
|
||||
if (from == 0) return loc;
|
||||
else if (from == 1) return rot.getEuler();
|
||||
else if (from == 1) return rot;
|
||||
else return scale;
|
||||
}
|
||||
}
|
||||
|
|
35
Sources/armory/logicnode/SetBoneFkIkOnlyNode.hx
Normal file
35
Sources/armory/logicnode/SetBoneFkIkOnlyNode.hx
Normal file
|
@ -0,0 +1,35 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
import iron.object.Object;
|
||||
import iron.object.BoneAnimation;
|
||||
|
||||
class SetBoneFkIkOnlyNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if arm_skin
|
||||
|
||||
var object: Object = inputs[1].get();
|
||||
var boneName: String = inputs[2].get();
|
||||
var fk_ik_only: Bool = inputs[3].get();
|
||||
|
||||
if (object == null) return;
|
||||
var anim = object.animation != null ? cast(object.animation, BoneAnimation) : null;
|
||||
if (anim == null) anim = object.getParentArmature(object.name);
|
||||
|
||||
// Get bone in armature
|
||||
var bone = anim.getBone(boneName);
|
||||
|
||||
//Set bone animated by FK or IK only
|
||||
bone.is_ik_fk_only = fk_ik_only;
|
||||
|
||||
runOutput(0);
|
||||
|
||||
#end
|
||||
}
|
||||
}
|
25
Sources/armory/logicnode/SetGlobalCanvasFontSizeNode.hx
Normal file
25
Sources/armory/logicnode/SetGlobalCanvasFontSizeNode.hx
Normal file
|
@ -0,0 +1,25 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import armory.trait.internal.CanvasScript;
|
||||
|
||||
class SetGlobalCanvasFontSizeNode extends LogicNode {
|
||||
|
||||
var canvas: CanvasScript;
|
||||
var factor: Int;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
#if arm_ui
|
||||
override function run(from: Int) {
|
||||
factor = inputs[1].get();
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
if (canvas == null) canvas = Scene.active.camera.getTrait(CanvasScript);
|
||||
|
||||
canvas.setCanvasFontSize(factor);
|
||||
runOutput(0);
|
||||
}
|
||||
#end
|
||||
}
|
25
Sources/armory/logicnode/SetGlobalCanvasScaleNode.hx
Normal file
25
Sources/armory/logicnode/SetGlobalCanvasScaleNode.hx
Normal file
|
@ -0,0 +1,25 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import armory.trait.internal.CanvasScript;
|
||||
|
||||
class SetGlobalCanvasScaleNode extends LogicNode {
|
||||
|
||||
var canvas: CanvasScript;
|
||||
var factor: Float;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
#if arm_ui
|
||||
override function run(from: Int) {
|
||||
factor = inputs[1].get();
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
if (canvas == null) canvas = Scene.active.camera.getTrait(CanvasScript);
|
||||
|
||||
canvas.setUiScale(factor);
|
||||
runOutput(0);
|
||||
}
|
||||
#end
|
||||
}
|
46
Sources/armory/logicnode/SetInputMapKeyNode.hx
Normal file
46
Sources/armory/logicnode/SetInputMapKeyNode.hx
Normal file
|
@ -0,0 +1,46 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class SetInputMapKeyNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var inputMap = inputs[1].get();
|
||||
var key = inputs[2].get();
|
||||
var scale = inputs[3].get();
|
||||
var deadzone = inputs[4].get();
|
||||
var index = inputs[5].get();
|
||||
|
||||
var i = InputMap.getInputMap(inputMap);
|
||||
|
||||
if (i == null) {
|
||||
i = InputMap.addInputMap(inputMap);
|
||||
}
|
||||
|
||||
var k = InputMap.getInputMapKey(inputMap, key);
|
||||
|
||||
if (k == null) {
|
||||
switch(property0) {
|
||||
case "keyboard": k = i.addKeyboard(key, scale);
|
||||
case "mouse": k = i.addMouse(key, scale, deadzone);
|
||||
case "gamepad": {
|
||||
k = i.addGamepad(key, scale, deadzone);
|
||||
k.setIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
k.scale = scale;
|
||||
k.deadzone = deadzone;
|
||||
k.setIndex(index);
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
|
@ -13,9 +13,21 @@ class SetLocationNode extends LogicNode {
|
|||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
var vec: Vec4 = inputs[2].get();
|
||||
var relative: Bool = inputs[3].get();
|
||||
|
||||
if (object == null || vec == null) return;
|
||||
|
||||
if (!relative && object.parent != null) {
|
||||
var loc = vec.clone();
|
||||
loc.sub(object.parent.transform.world.getLoc()); // Remove parent location influence
|
||||
|
||||
// Convert vec to parent local space
|
||||
var dotX = loc.dot(object.parent.transform.right());
|
||||
var dotY = loc.dot(object.parent.transform.look());
|
||||
var dotZ = loc.dot(object.parent.transform.up());
|
||||
vec.set(dotX, dotY, dotZ);
|
||||
}
|
||||
|
||||
object.transform.loc.setFrom(vec);
|
||||
object.transform.buildMatrix();
|
||||
|
||||
|
@ -26,4 +38,4 @@ class SetLocationNode extends LogicNode {
|
|||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +1,40 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import iron.data.MaterialData;
|
||||
import iron.object.Object;
|
||||
import armory.trait.internal.UniformsManager;
|
||||
|
||||
class SetMaterialImageParamNode extends LogicNode {
|
||||
|
||||
static var registered = false;
|
||||
static var map = new Map<MaterialData, Map<String, kha.Image>>();
|
||||
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
if (!registered) {
|
||||
registered = true;
|
||||
iron.object.Uniforms.externalTextureLinks.push(textureLink);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var mat = inputs[1].get();
|
||||
if (mat == null) return;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) {
|
||||
entry = new Map();
|
||||
map.set(mat, entry);
|
||||
var perObject: Null<Bool>;
|
||||
|
||||
var object = inputs[1].get();
|
||||
if(object == null) return;
|
||||
|
||||
perObject = inputs[2].get();
|
||||
if(perObject == null) perObject = false;
|
||||
|
||||
var mat = inputs[3].get();
|
||||
if(mat == null) return;
|
||||
|
||||
if(! perObject){
|
||||
UniformsManager.removeObjectFromMap(object, Texture);
|
||||
object = Scene.active.root;
|
||||
}
|
||||
|
||||
iron.data.Data.getImage(inputs[3].get(), function(image: kha.Image) {
|
||||
entry.set(inputs[2].get(), image); // Node name, value
|
||||
var img = inputs[5].get();
|
||||
if(img == null) return;
|
||||
iron.data.Data.getImage(img, function(image: kha.Image) {
|
||||
UniformsManager.setTextureValue(mat, object, inputs[4].get(), image);
|
||||
});
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
static function textureLink(object: Object, mat: MaterialData, link: String): kha.Image {
|
||||
if (mat == null) return null;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) return null;
|
||||
return entry.get(link);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,35 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import iron.math.Vec4;
|
||||
import iron.data.MaterialData;
|
||||
import iron.object.Object;
|
||||
import armory.trait.internal.UniformsManager;
|
||||
|
||||
class SetMaterialRgbParamNode extends LogicNode {
|
||||
|
||||
static var registered = false;
|
||||
static var map = new Map<MaterialData, Map<String, Vec4>>();
|
||||
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
if (!registered) {
|
||||
registered = true;
|
||||
iron.object.Uniforms.externalVec3Links.push(vec3Link);
|
||||
}
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var mat = inputs[1].get();
|
||||
if (mat == null) return;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) {
|
||||
entry = new Map();
|
||||
map.set(mat, entry);
|
||||
var perObject: Null<Bool>;
|
||||
|
||||
var object = inputs[1].get();
|
||||
if(object == null) return;
|
||||
|
||||
perObject = inputs[2].get();
|
||||
if(perObject == null) perObject = false;
|
||||
|
||||
var mat = inputs[3].get();
|
||||
if(mat == null) return;
|
||||
|
||||
if(! perObject){
|
||||
UniformsManager.removeObjectFromMap(object, Vector);
|
||||
object = Scene.active.root;
|
||||
}
|
||||
entry.set(inputs[2].get(), inputs[3].get()); // Node name, value
|
||||
|
||||
UniformsManager.setVec3Value(mat, object, inputs[4].get(), inputs[5].get());
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
if (mat == null) return null;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) return null;
|
||||
return entry.get(link);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,35 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import iron.data.MaterialData;
|
||||
import iron.object.Object;
|
||||
import armory.trait.internal.UniformsManager;
|
||||
|
||||
class SetMaterialValueParamNode extends LogicNode {
|
||||
|
||||
static var registered = false;
|
||||
static var map = new Map<MaterialData, Map<String, Null<kha.FastFloat>>>();
|
||||
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
if (!registered) {
|
||||
registered = true;
|
||||
iron.object.Uniforms.externalFloatLinks.push(floatLink);
|
||||
}
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var mat = inputs[1].get();
|
||||
if (mat == null) return;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) {
|
||||
entry = new Map();
|
||||
map.set(mat, entry);
|
||||
var perObject: Null<Bool>;
|
||||
|
||||
var object = inputs[1].get();
|
||||
if(object == null) return;
|
||||
|
||||
perObject = inputs[2].get();
|
||||
if(perObject == null) perObject = false;
|
||||
|
||||
var mat = inputs[3].get();
|
||||
if(mat == null) return;
|
||||
|
||||
if(! perObject){
|
||||
UniformsManager.removeObjectFromMap(object, Float);
|
||||
object = Scene.active.root;
|
||||
}
|
||||
entry.set(inputs[2].get(), inputs[3].get()); // Node name, value
|
||||
|
||||
UniformsManager.setFloatValue(mat, object, inputs[4].get(), inputs[5].get());
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
static function floatLink(object: Object, mat: MaterialData, link: String): Null<kha.FastFloat> {
|
||||
if (mat == null) return null;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) return null;
|
||||
return entry.get(link);
|
||||
}
|
||||
}
|
||||
|
|
25
Sources/armory/logicnode/SetObjectShapeKeyNode.hx
Normal file
25
Sources/armory/logicnode/SetObjectShapeKeyNode.hx
Normal file
|
@ -0,0 +1,25 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.MeshObject;
|
||||
|
||||
class SetObjectShapeKeyNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if arm_morph_target
|
||||
var object: Dynamic = inputs[1].get();
|
||||
var shapeKey: String = inputs[2].get();
|
||||
var value: Dynamic = inputs[3].get();
|
||||
|
||||
assert(Error, object != null, "Object should not be null");
|
||||
var morph = cast(object, MeshObject).morphTarget;
|
||||
|
||||
assert(Error, morph != null, "Object does not have shape keys");
|
||||
morph.setMorphValue(shapeKey, value);
|
||||
#end
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
|
@ -14,8 +14,9 @@ class SetParentNode extends LogicNode {
|
|||
|
||||
var parent: Object;
|
||||
var isUnparent = false;
|
||||
if (Std.is(inputs[2].node, ObjectNode)) {
|
||||
var parentNode = cast(inputs[2].node, ObjectNode);
|
||||
|
||||
if (Std.isOfType(inputs[2].fromNode, ObjectNode)) {
|
||||
var parentNode = cast(inputs[2].fromNode, ObjectNode);
|
||||
isUnparent = parentNode.objectName == "";
|
||||
}
|
||||
if (isUnparent) parent = iron.Scene.active.root;
|
||||
|
@ -24,7 +25,7 @@ class SetParentNode extends LogicNode {
|
|||
if (object == null || parent == null || object.parent == parent) return;
|
||||
|
||||
object.parent.removeChild(object, isUnparent); // keepTransform
|
||||
|
||||
|
||||
#if arm_physics
|
||||
var rigidBody = object.getTrait(RigidBody);
|
||||
if (rigidBody != null) rigidBody.setActivationState(0);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
|
||||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
import armory.trait.physics.RigidBody;
|
||||
|
||||
class SetRotationNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
public var property0: String; // UNUSED
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
@ -16,27 +16,13 @@ class SetRotationNode extends LogicNode {
|
|||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
if (object == null) return;
|
||||
var vec: Vec4 = inputs[2].get();
|
||||
if (vec == null) return;
|
||||
var w: Float = inputs[3].get();
|
||||
var q: Quat = inputs[2].get();
|
||||
if (q == null) return;
|
||||
|
||||
switch (property0) {
|
||||
case "Euler Angles":
|
||||
object.transform.rot.fromEuler(vec.x, vec.y, vec.z);
|
||||
case "Angle Axies (Degrees)" | "Angle Axies (Radians)":
|
||||
var angle: Float = w;
|
||||
if (property0 == "Angle Axies (Degrees)") {
|
||||
angle = angle * (Math.PI / 180);
|
||||
}
|
||||
var angleSin = Math.sin(angle / 2);
|
||||
vec = vec.normalize();
|
||||
var angleCos = Math.cos(angle / 2);
|
||||
object.transform.rot = new Quat(vec.x * angleSin, vec.y * angleSin, vec.z * angleSin, angleCos);
|
||||
case "Quaternion":
|
||||
object.transform.rot = new Quat(vec.x, vec.y, vec.z, w);
|
||||
object.transform.rot.normalize();
|
||||
}
|
||||
q.normalize();
|
||||
object.transform.rot = q;
|
||||
object.transform.buildMatrix();
|
||||
|
||||
#if arm_physics
|
||||
var rigidBody = object.getTrait(RigidBody);
|
||||
if (rigidBody != null) {
|
||||
|
|
65
Sources/armory/logicnode/SetShaderUniformNode.hx
Normal file
65
Sources/armory/logicnode/SetShaderUniformNode.hx
Normal file
|
@ -0,0 +1,65 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.data.MaterialData;
|
||||
import iron.object.Object;
|
||||
|
||||
class SetShaderUniformNode extends LogicNode {
|
||||
|
||||
static var registered = false;
|
||||
static var intMap = new Map<String, Null<Int>>();
|
||||
static var floatMap = new Map<String, Null<kha.FastFloat>>();
|
||||
static var vec2Map = new Map<String, iron.math.Vec4>();
|
||||
static var vec3Map = new Map<String, iron.math.Vec4>();
|
||||
static var vec4Map = new Map<String, iron.math.Vec4>();
|
||||
|
||||
/** Uniform type **/
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
if (!registered) {
|
||||
registered = true;
|
||||
iron.object.Uniforms.externalIntLinks.push(intLink);
|
||||
iron.object.Uniforms.externalFloatLinks.push(floatLink);
|
||||
iron.object.Uniforms.externalVec2Links.push(vec2Link);
|
||||
iron.object.Uniforms.externalVec3Links.push(vec3Link);
|
||||
iron.object.Uniforms.externalVec4Links.push(vec4Link);
|
||||
}
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var uniformName: String = inputs[1].get();
|
||||
if (uniformName == null) return;
|
||||
|
||||
switch (property0) {
|
||||
case "int": intMap.set(uniformName, inputs[2].get());
|
||||
case "float": floatMap.set(uniformName, inputs[2].get());
|
||||
case "vec2": vec2Map.set(uniformName, inputs[2].get());
|
||||
case "vec3": vec3Map.set(uniformName, inputs[2].get());
|
||||
case "vec4": vec4Map.set(uniformName, inputs[2].get());
|
||||
default:
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
static function intLink(object: Object, mat: MaterialData, link: String): Null<Int> {
|
||||
return intMap.get(link);
|
||||
}
|
||||
|
||||
static function floatLink(object: Object, mat: MaterialData, link: String): Null<kha.FastFloat> {
|
||||
return floatMap.get(link);
|
||||
}
|
||||
|
||||
static function vec2Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
return vec2Map.get(link);
|
||||
}
|
||||
|
||||
static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
return vec3Map.get(link);
|
||||
}
|
||||
|
||||
static function vec4Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
return vec4Map.get(link);
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ class SetTraitPausedNode extends LogicNode {
|
|||
var trait: Dynamic = inputs[1].get();
|
||||
var paused: Bool = inputs[2].get();
|
||||
|
||||
if (trait == null || !Std.is(trait, LogicTree)) return;
|
||||
if (trait == null || !Std.isOfType(trait, LogicTree)) return;
|
||||
|
||||
paused ? cast(trait, LogicTree).pause() : cast(trait, LogicTree).resume();
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue