Compare commits
616 Commits
ebridgewat
...
v1.45.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d786d59ea1 | ||
|
|
79116905aa | ||
|
|
763950ec18 | ||
|
|
13571868de | ||
|
|
0f2c89b140 | ||
|
|
f8b70e8ec5 | ||
|
|
7abdea5a2e | ||
|
|
cb3e808e8d | ||
|
|
b2e0b97bad | ||
|
|
9c0cbed214 | ||
|
|
c531a9c077 | ||
|
|
2a1f762e23 | ||
|
|
4dd98e63e4 | ||
|
|
1b7187f427 | ||
|
|
0dddd94eab | ||
|
|
2ef0244266 | ||
|
|
0774bf9501 | ||
|
|
8f5b2fd230 | ||
|
|
274191036f | ||
|
|
13afbc2876 | ||
|
|
a7bb0a60fb | ||
|
|
0650b13358 | ||
|
|
6cd851e77e | ||
|
|
87a8cb3872 | ||
|
|
a4869eaf19 | ||
|
|
1740220f6a | ||
|
|
5deccffdce | ||
|
|
a76eacba67 | ||
|
|
ee31ca6fc0 | ||
|
|
7dd6686087 | ||
|
|
fdffd93949 | ||
|
|
f0a0a9b2e1 | ||
|
|
e743e9243f | ||
|
|
8e13d53b1e | ||
|
|
ff274c8387 | ||
|
|
e08e1c209b | ||
|
|
de310ed9ad | ||
|
|
d01b29fa01 | ||
|
|
8cba3d4366 | ||
|
|
be1e51ad91 | ||
|
|
29ce1cad84 | ||
|
|
6a967ad007 | ||
|
|
fe2bb3d9a4 | ||
|
|
cd7973bdcf | ||
|
|
e6384e0e92 | ||
|
|
e63dc17f54 | ||
|
|
af338cf2ec | ||
|
|
f1d8a04337 | ||
|
|
b13497e2a0 | ||
|
|
175c9f9966 | ||
|
|
1a50420b46 | ||
|
|
bbad75a012 | ||
|
|
25c08f19e3 | ||
|
|
59063fb7b4 | ||
|
|
71f60de0ad | ||
|
|
743661109d | ||
|
|
5014cbb023 | ||
|
|
4142e7a1cf | ||
|
|
a721e648b7 | ||
|
|
358e89ef08 | ||
|
|
e023e90e7a | ||
|
|
a5b5b0c3a7 | ||
|
|
b7b4d3c295 | ||
|
|
a445c4e156 | ||
|
|
1432c59499 | ||
|
|
4c7c10fad0 | ||
|
|
7c8a0d1967 | ||
|
|
11fbacea20 | ||
|
|
8cd70454c3 | ||
|
|
1d988182fc | ||
|
|
dba49f00df | ||
|
|
89c0b44da9 | ||
|
|
4f450fd5c4 | ||
|
|
f0943cfca2 | ||
|
|
9aa52b79d4 | ||
|
|
a82125dbbd | ||
|
|
24fcb299b5 | ||
|
|
753aa9ca61 | ||
|
|
a33eada7ec | ||
|
|
676a2be874 | ||
|
|
c95d466cdd | ||
|
|
3d8ac384ad | ||
|
|
57424cc7e9 | ||
|
|
78fe4ba547 | ||
|
|
a3d25cd22b | ||
|
|
56bf841bac | ||
|
|
dfdf0db794 | ||
|
|
bf6bd4eca8 | ||
|
|
36c69dda9c | ||
|
|
f14fdc11f5 | ||
|
|
0157487b1f | ||
|
|
1716c856c3 | ||
|
|
31521c70c2 | ||
|
|
8cac90d81e | ||
|
|
388b4f5efb | ||
|
|
f9b5a7f301 | ||
|
|
00c78cc225 | ||
|
|
2bdb8b560c | ||
|
|
a974fddd4c | ||
|
|
83a3e243da | ||
|
|
f286e308bf | ||
|
|
29af3be2e3 | ||
|
|
6623dcbebf | ||
|
|
89dc43f361 | ||
|
|
b77aac43ea | ||
|
|
0d63fa02ee | ||
|
|
e187bc442d | ||
|
|
d62268fbfb | ||
|
|
3b73e3de60 | ||
|
|
7685736d6c | ||
|
|
b8a3a7f221 | ||
|
|
732628acf5 | ||
|
|
7bd00d2b30 | ||
|
|
0759797e61 | ||
|
|
fddc5160c7 | ||
|
|
2a579c460f | ||
|
|
efdc801cff | ||
|
|
dd654c575a | ||
|
|
0c2599b6ca | ||
|
|
979d6742e0 | ||
|
|
4a7a033d04 | ||
|
|
5c2bbcb4a1 | ||
|
|
dec903a0ee | ||
|
|
e9475b322b | ||
|
|
d9aead8aac | ||
|
|
ce148ebeb1 | ||
|
|
e1315fbaa7 | ||
|
|
1690549392 | ||
|
|
c73710e343 | ||
|
|
092a0489da | ||
|
|
1c6279366f | ||
|
|
2ac85049a9 | ||
|
|
ea428a27d1 | ||
|
|
3bef718238 | ||
|
|
e9daaa0503 | ||
|
|
6d3ea21993 | ||
|
|
f39127605d | ||
|
|
db476f00f7 | ||
|
|
e54d8ec0a4 | ||
|
|
b95ac854b4 | ||
|
|
96443f6dac | ||
|
|
e5e3dff9fa | ||
|
|
31d9da38fd | ||
|
|
c5a59bb6b1 | ||
|
|
e6854148d7 | ||
|
|
001daf0350 | ||
|
|
d26c48110d | ||
|
|
15a070f0c9 | ||
|
|
93230b06cf | ||
|
|
4c55fc3c48 | ||
|
|
a4797a631e | ||
|
|
5868e857aa | ||
|
|
32ba063bd7 | ||
|
|
02f0839f9b | ||
|
|
e50f3c4c91 | ||
|
|
7ca15bfc16 | ||
|
|
b7b7afb62a | ||
|
|
b8ff6a9ad9 | ||
|
|
a1dcb4f259 | ||
|
|
c3501393fd | ||
|
|
a03de75a4e | ||
|
|
0c3d59aba3 | ||
|
|
ce1987f291 | ||
|
|
7eae926ed7 | ||
|
|
606af52eda | ||
|
|
8ea30aea80 | ||
|
|
72dea695ba | ||
|
|
1c0cf56ed0 | ||
|
|
bcb4eb35cd | ||
|
|
bce2676335 | ||
|
|
510097d722 | ||
|
|
5784118a12 | ||
|
|
b5de0f2d23 | ||
|
|
04df3f4dad | ||
|
|
093ca4d623 | ||
|
|
a3ed1558d3 | ||
|
|
fe379070ae | ||
|
|
ead0a2f597 | ||
|
|
5dbc593f90 | ||
|
|
d47dc12bf0 | ||
|
|
4392f63e57 | ||
|
|
f64b7aca79 | ||
|
|
3762ec5750 | ||
|
|
4591fdd9c0 | ||
|
|
d3068d2a0e | ||
|
|
ca0a4bc23a | ||
|
|
433c163c61 | ||
|
|
c867fda883 | ||
|
|
566540ae6d | ||
|
|
759f490dae | ||
|
|
867d4d44f5 | ||
|
|
65747d5877 | ||
|
|
bd357f6076 | ||
|
|
9e960b7d45 | ||
|
|
0c54d4a6a1 | ||
|
|
526e846a81 | ||
|
|
8bcfa373d4 | ||
|
|
db9a0f2c1f | ||
|
|
646b1e2193 | ||
|
|
41bd30f81d | ||
|
|
bd626aea27 | ||
|
|
8a03f75485 | ||
|
|
dc9594fbdf | ||
|
|
fad0b533c0 | ||
|
|
4d773e9453 | ||
|
|
e0c610b013 | ||
|
|
0da4f36c33 | ||
|
|
11d17e1db3 | ||
|
|
b8c318d923 | ||
|
|
e563cc6f5e | ||
|
|
cb8914ab96 | ||
|
|
2fecda7bdc | ||
|
|
543d8efb25 | ||
|
|
396b1079a7 | ||
|
|
eedcd9f8cb | ||
|
|
ab252b210c | ||
|
|
1071b8ea90 | ||
|
|
a9c5bbf185 | ||
|
|
8dd4bff7a7 | ||
|
|
77c54446af | ||
|
|
4a0bc0af57 | ||
|
|
a171e75e70 | ||
|
|
f5ffa092fe | ||
|
|
8de5fdd551 | ||
|
|
ecca3abe98 | ||
|
|
8570e35224 | ||
|
|
84df9f9a03 | ||
|
|
5f93fb9613 | ||
|
|
75f77fdbdd | ||
|
|
7825d582c2 | ||
|
|
5deb0ba933 | ||
|
|
18e917aaf2 | ||
|
|
a165f3890a | ||
|
|
f88b6d9c97 | ||
|
|
db8ecd9952 | ||
|
|
b5ec06c2d2 | ||
|
|
dfbac8385e | ||
|
|
eaab737b2c | ||
|
|
45991cda0a | ||
|
|
09a016bb6f | ||
|
|
31607d355d | ||
|
|
a67d50b9e2 | ||
|
|
8d42f53c80 | ||
|
|
5e21a55bce | ||
|
|
85930ea2e8 | ||
|
|
4b3cde8b39 | ||
|
|
eedfa85355 | ||
|
|
bb54c6c807 | ||
|
|
c23f905858 | ||
|
|
8c7be0a1d0 | ||
|
|
878497b3d5 | ||
|
|
a155561769 | ||
|
|
8b86a0ed2e | ||
|
|
26f9a9b122 | ||
|
|
6e5f6978fb | ||
|
|
0d31d7b2de | ||
|
|
dd862b7e0a | ||
|
|
52065f2cbd | ||
|
|
77c02d5831 | ||
|
|
f7e4c8d16d | ||
|
|
b7410474ff | ||
|
|
384cc4ebf6 | ||
|
|
7c0643f122 | ||
|
|
58abae3067 | ||
|
|
4742693869 | ||
|
|
6c39e474ea | ||
|
|
5c8977c906 | ||
|
|
6b3cc2e2f3 | ||
|
|
76b2edd6ea | ||
|
|
8ebb37d011 | ||
|
|
3366db83ef | ||
|
|
5415254aac | ||
|
|
caacc61602 | ||
|
|
e902df19b2 | ||
|
|
40b372dda7 | ||
|
|
fd330a98aa | ||
|
|
90c23a7d5d | ||
|
|
5710304114 | ||
|
|
0f684820bc | ||
|
|
e1d2d6ade6 | ||
|
|
e0b6f2ca71 | ||
|
|
2a35ee279b | ||
|
|
5abf780360 | ||
|
|
181f158ea9 | ||
|
|
f4087fc81d | ||
|
|
82793f9b82 | ||
|
|
537576e84a | ||
|
|
375d1f55e3 | ||
|
|
597218963f | ||
|
|
0d29b3ddc8 | ||
|
|
e0e3b42623 | ||
|
|
0995ca6614 | ||
|
|
3d741fc8d4 | ||
|
|
c20772b458 | ||
|
|
4a6b659098 | ||
|
|
2b93f08ca5 | ||
|
|
fca62b8fff | ||
|
|
dee6d9de2c | ||
|
|
574e3e7521 | ||
|
|
29fdf82ac5 | ||
|
|
c8cf2a54e8 | ||
|
|
bfd32e67d4 | ||
|
|
95915367fa | ||
|
|
b769cfda62 | ||
|
|
40ac88dfed | ||
|
|
6d96082f07 | ||
|
|
21f913db1c | ||
|
|
699a578966 | ||
|
|
babbfa1394 | ||
|
|
73f0d58e10 | ||
|
|
9cb4b74bbd | ||
|
|
f2c8456971 | ||
|
|
e571600c30 | ||
|
|
e84c94d3eb | ||
|
|
e791d4818f | ||
|
|
cdadb43e50 | ||
|
|
edaff60fbf | ||
|
|
3f64e46557 | ||
|
|
32dab23bc6 | ||
|
|
362de7dd31 | ||
|
|
6b01fbb903 | ||
|
|
4934d9f7bc | ||
|
|
ed73955b00 | ||
|
|
3f1f2726c4 | ||
|
|
1a7bd7ea8d | ||
|
|
946ea43436 | ||
|
|
7f42385f5f | ||
|
|
8845ac2b75 | ||
|
|
da85001d4d | ||
|
|
8d15079937 | ||
|
|
adc542b5cd | ||
|
|
72feb044a3 | ||
|
|
c0ba260ddf | ||
|
|
2da215e8e7 | ||
|
|
4d0368b5f1 | ||
|
|
d11c78857d | ||
|
|
e829d90c4a | ||
|
|
a8006acd33 | ||
|
|
86ec502040 | ||
|
|
b19a73cc50 | ||
|
|
a99c695932 | ||
|
|
8cd720b53a | ||
|
|
04df79e58f | ||
|
|
a4b3717762 | ||
|
|
1035e442ee | ||
|
|
60d3638f15 | ||
|
|
3e7d3c9035 | ||
|
|
eb360be2ad | ||
|
|
485ac8704d | ||
|
|
dc74540423 | ||
|
|
96219c22db | ||
|
|
f3b7048775 | ||
|
|
aaed6fb376 | ||
|
|
35a5d3310f | ||
|
|
9da79a1d2d | ||
|
|
595b355d1b | ||
|
|
3a67d769f4 | ||
|
|
6fb536a937 | ||
|
|
bb460d78d8 | ||
|
|
838835a715 | ||
|
|
63acd53e23 | ||
|
|
fcd2d0457b | ||
|
|
58fc26461b | ||
|
|
fd82f6b04e | ||
|
|
cef3200533 | ||
|
|
634500c398 | ||
|
|
b3e294ac54 | ||
|
|
2bf7535ad0 | ||
|
|
3315f75de9 | ||
|
|
bbe7dbfa92 | ||
|
|
5697922a65 | ||
|
|
4da83df2b9 | ||
|
|
8f156d6588 | ||
|
|
cec0871c11 | ||
|
|
41a809368b | ||
|
|
ea53eb9290 | ||
|
|
05875057c9 | ||
|
|
44125926d1 | ||
|
|
60734349de | ||
|
|
fbfd5ec0ec | ||
|
|
a74a95cc65 | ||
|
|
bc0ea16ff0 | ||
|
|
b2dc8aa84c | ||
|
|
9987e8b6ab | ||
|
|
0d9bdcc008 | ||
|
|
b5c634045e | ||
|
|
1f05531d53 | ||
|
|
88f382f0e3 | ||
|
|
3e59925900 | ||
|
|
ea404f8d4f | ||
|
|
602a550d93 | ||
|
|
12abbe2d23 | ||
|
|
fb0ee97588 | ||
|
|
56ef48c9c3 | ||
|
|
47c3dd3dd1 | ||
|
|
c181648bfa | ||
|
|
0cf78b3abe | ||
|
|
22889a7ad9 | ||
|
|
a14451d0ac | ||
|
|
5dfdab10b7 | ||
|
|
d6f2e3b8e9 | ||
|
|
df30517743 | ||
|
|
8f80643c1a | ||
|
|
5aea9be2fb | ||
|
|
ad02e483d0 | ||
|
|
f463d53036 | ||
|
|
b8d4408524 | ||
|
|
fef70be848 | ||
|
|
bdb12d9b24 | ||
|
|
43ad283a83 | ||
|
|
2e4936afc4 | ||
|
|
891ffabd11 | ||
|
|
e2c19498b4 | ||
|
|
c32630b265 | ||
|
|
bf21e78d02 | ||
|
|
525d4e08a3 | ||
|
|
2e9bf6d694 | ||
|
|
e845f01d85 | ||
|
|
bef48be7b4 | ||
|
|
b54fdc9e6e | ||
|
|
cedbf2e30b | ||
|
|
592f8d1b0d | ||
|
|
29612a684e | ||
|
|
e6d5807399 | ||
|
|
fa2553251f | ||
|
|
7387718852 | ||
|
|
a503a6209a | ||
|
|
ce3e5f74e8 | ||
|
|
f37112358e | ||
|
|
f368b14621 | ||
|
|
6960b1148a | ||
|
|
3cc23aac25 | ||
|
|
11dc8740f2 | ||
|
|
4b797cff88 | ||
|
|
fe1c1736cd | ||
|
|
4058ef5f09 | ||
|
|
d25ca01624 | ||
|
|
d96f87dbbf | ||
|
|
8a2e31023f | ||
|
|
1ea8e171d9 | ||
|
|
e2be3dd0ac | ||
|
|
1c51164e7b | ||
|
|
f190f03530 | ||
|
|
055fc7cbc1 | ||
|
|
9073fc3dc3 | ||
|
|
2409dc9bc4 | ||
|
|
6586c8d70b | ||
|
|
ac0c94da69 | ||
|
|
d19d6a72b0 | ||
|
|
c81b5d98ef | ||
|
|
756866675f | ||
|
|
ebcd4925f7 | ||
|
|
13bed4fdf9 | ||
|
|
1dae5c6b6c | ||
|
|
8e6663e4b0 | ||
|
|
ba804444b8 | ||
|
|
58cfb85004 | ||
|
|
ab46481b45 | ||
|
|
4296782399 | ||
|
|
ef375a7103 | ||
|
|
fd258b7765 | ||
|
|
147de8d372 | ||
|
|
eb2a1928b6 | ||
|
|
35b033102f | ||
|
|
7bc65421a9 | ||
|
|
736514cf37 | ||
|
|
db0158dae8 | ||
|
|
e706695ed1 | ||
|
|
e8877ffe2d | ||
|
|
1fd5d9dae6 | ||
|
|
cd48089318 | ||
|
|
6379ab22c9 | ||
|
|
0bf02b75d5 | ||
|
|
c4259b5598 | ||
|
|
6b3c1179bc | ||
|
|
c1a0e61e8e | ||
|
|
fc06298ed4 | ||
|
|
4ca87b188c | ||
|
|
f1f60c3e0d | ||
|
|
76d21b56af | ||
|
|
0ab0e50a4f | ||
|
|
34f4c06a5c | ||
|
|
6de36f1e53 | ||
|
|
2a9a3b1ac2 | ||
|
|
84b73a3770 | ||
|
|
662a10e273 | ||
|
|
ecce02502e | ||
|
|
d17875aea1 | ||
|
|
b8897a68f9 | ||
|
|
84efd4871e | ||
|
|
85ea5a6b70 | ||
|
|
77891acb92 | ||
|
|
74fe102035 | ||
|
|
25cc554925 | ||
|
|
d787a521b5 | ||
|
|
46e52c71e1 | ||
|
|
1dad27a172 | ||
|
|
60d230b380 | ||
|
|
d7cb38e706 | ||
|
|
ce00cca6ee | ||
|
|
d627d57bad | ||
|
|
8ffc776f1c | ||
|
|
be032b52c1 | ||
|
|
4388e81e5f | ||
|
|
71a185d139 | ||
|
|
d2cf5985ac | ||
|
|
debcbb8e5c | ||
|
|
b9dd62c7d3 | ||
|
|
dc2b430f34 | ||
|
|
e5ef4e8868 | ||
|
|
c0d6cd3ac3 | ||
|
|
b63ab2dc19 | ||
|
|
5d8dad561c | ||
|
|
8933be1ae2 | ||
|
|
6b66b48b1d | ||
|
|
9c23eb6e33 | ||
|
|
baea54a3fc | ||
|
|
d9f800454c | ||
|
|
f9ee0de07a | ||
|
|
2786d0a9f7 | ||
|
|
491e8032e6 | ||
|
|
ef3f13f5d3 | ||
|
|
bcb5b2d790 | ||
|
|
02de3f2e2a | ||
|
|
0e7bb53c07 | ||
|
|
759109d478 | ||
|
|
54d5af6edf | ||
|
|
38fbe47ced | ||
|
|
f066c925ba | ||
|
|
994fdf4e1d | ||
|
|
50b50d65e3 | ||
|
|
0aaa985649 | ||
|
|
29564f8eae | ||
|
|
c15db68a5b | ||
|
|
3452fb3e56 | ||
|
|
35eb8e7be1 | ||
|
|
834b774128 | ||
|
|
5aa0eb9f9d | ||
|
|
d9a6e2e649 | ||
|
|
cb823b16a1 | ||
|
|
0bd41e877e | ||
|
|
ecc3e73967 | ||
|
|
464b4c24f9 | ||
|
|
32367516e8 | ||
|
|
1709a55606 | ||
|
|
58b4455979 | ||
|
|
ea1dede19c | ||
|
|
20ea3381fa | ||
|
|
7aa6fccd7c | ||
|
|
adbd54f4f8 | ||
|
|
9d54261f18 | ||
|
|
a97757c9ae | ||
|
|
7c79d9f89d | ||
|
|
bf0914f813 | ||
|
|
b96bc30fbd | ||
|
|
62b50eb8ba | ||
|
|
b4932e384a | ||
|
|
5e68dc5f8d | ||
|
|
f222f1b925 | ||
|
|
22e4a54782 | ||
|
|
1289922c5f | ||
|
|
2839c352b8 | ||
|
|
6a01cbc312 | ||
|
|
6193156556 | ||
|
|
fe23aa917d | ||
|
|
eb8a29a332 | ||
|
|
0626902530 | ||
|
|
042bfe2597 | ||
|
|
97133f3591 | ||
|
|
d06cc4390e | ||
|
|
6047d3235f | ||
|
|
2cda6e35bd | ||
|
|
8f8d51e17b | ||
|
|
6919e3b274 | ||
|
|
10bf944410 | ||
|
|
9a2f6fdb53 | ||
|
|
761977d385 | ||
|
|
21248f15b5 | ||
|
|
4f32817f6d | ||
|
|
cc9e05e711 | ||
|
|
419d68d4db | ||
|
|
8450232448 | ||
|
|
cc51726590 | ||
|
|
318e22af51 | ||
|
|
68ac87dc24 | ||
|
|
acb8f00075 | ||
|
|
06d9183aaa | ||
|
|
75af25419d | ||
|
|
f6b90d2a31 | ||
|
|
a3822f4af0 | ||
|
|
bcdad769ff | ||
|
|
be4fb4fdbb | ||
|
|
65394f6301 | ||
|
|
b0beee03bc | ||
|
|
fe1de41b8e | ||
|
|
a37b431e87 | ||
|
|
98107016b9 | ||
|
|
8bccfc2863 | ||
|
|
f54a0a3452 | ||
|
|
6778ab0624 | ||
|
|
269d636785 | ||
|
|
39862c91ce | ||
|
|
523f4026b4 | ||
|
|
a6bf162431 | ||
|
|
826e8d181c | ||
|
|
16dfadbba0 | ||
|
|
5cbb97551f | ||
|
|
defee767c3 | ||
|
|
9560318521 | ||
|
|
ef09feb048 | ||
|
|
39f323fe09 | ||
|
|
11b95304ea | ||
|
|
b7c30a7916 | ||
|
|
4cae48fc77 | ||
|
|
d1a93f0557 | ||
|
|
b93059fad7 |
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.45.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.45.1'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.45.0'
|
||||
pod 'Filament', '~> 1.45.1'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
@@ -15,7 +15,6 @@ Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
- engine: New tone mapper: `AgXTonemapper`.
|
||||
- matinfo: Add support for viewing ESSL 1.0 shaders
|
||||
- engine: Add `Renderer::getClearOptions()` [b/243846268]
|
||||
- engine: Fix stable shadows (again) when an IBL rotation is used
|
||||
|
||||
## v1.45.0
|
||||
|
||||
|
||||
@@ -71,6 +71,13 @@ Java_com_google_android_filament_Scene_nRemoveEntities(JNIEnv *env, jclass type,
|
||||
env->ReleaseIntArrayElements(entities, (jint*) nativeEntities, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Scene_nGetEntityCount(JNIEnv *env, jclass type,
|
||||
jlong nativeScene) {
|
||||
Scene* scene = (Scene*) nativeScene;
|
||||
return (jint) scene->getEntityCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Scene_nGetRenderableCount(JNIEnv *env, jclass type,
|
||||
jlong nativeScene) {
|
||||
|
||||
@@ -146,18 +146,29 @@ public class Scene {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of {@link RenderableManager} components in the <code>Scene</code>.
|
||||
* Returns the total number of Entities in the <code>Scene</code>, whether alive or not.
|
||||
*
|
||||
* @return number of {@link RenderableManager} components in the <code>Scene</code>..
|
||||
* @return the total number of Entities in the <code>Scene</code>.
|
||||
*/
|
||||
public int getEntityCount() {
|
||||
return nGetEntityCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of active (alive) {@link RenderableManager} components in the
|
||||
* <code>Scene</code>.
|
||||
*
|
||||
* @return number of {@link RenderableManager} components in the <code>Scene</code>.
|
||||
*/
|
||||
public int getRenderableCount() {
|
||||
return nGetRenderableCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of {@link LightManager} components in the <code>Scene</code>.
|
||||
* Returns the number of active (alive) {@link LightManager} components in the
|
||||
* <code>Scene</code>.
|
||||
*
|
||||
* @return number of {@link LightManager} components in the <code>Scene</code>..
|
||||
* @return number of {@link LightManager} components in the <code>Scene</code>.
|
||||
*/
|
||||
public int getLightCount() {
|
||||
return nGetLightCount(getNativeObject());
|
||||
@@ -189,6 +200,7 @@ public class Scene {
|
||||
private static native void nAddEntities(long nativeScene, int[] entities);
|
||||
private static native void nRemove(long nativeScene, int entity);
|
||||
private static native void nRemoveEntities(long nativeScene, int[] entities);
|
||||
private static native int nGetEntityCount(long nativeScene);
|
||||
private static native int nGetRenderableCount(long nativeScene);
|
||||
private static native int nGetLightCount(long nativeScene);
|
||||
private static native boolean nHasEntity(long nativeScene, int entity);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.45.0
|
||||
VERSION_NAME=1.45.1
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -114,6 +114,7 @@ public:
|
||||
* Platform. The <insert> and <retrieve> Invocables may be called at any time and
|
||||
* from any thread from the time at which setBlobFunc is called until the time that Platform
|
||||
* is destroyed. Concurrent calls to these functions from different threads is also allowed.
|
||||
* Either function can be null.
|
||||
*
|
||||
* @param insertBlob an Invocable that inserts a new value into the cache and associates
|
||||
* it with the given key
|
||||
@@ -123,9 +124,21 @@ public:
|
||||
void setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept;
|
||||
|
||||
/**
|
||||
* @return true if setBlobFunc was called.
|
||||
* @return true if insertBlob is valid.
|
||||
*/
|
||||
bool hasBlobFunc() const noexcept;
|
||||
bool hasInsertBlobFunc() const noexcept;
|
||||
|
||||
/**
|
||||
* @return true if retrieveBlob is valid.
|
||||
*/
|
||||
bool hasRetrieveBlobFunc() const noexcept;
|
||||
|
||||
/**
|
||||
* @return true if either of insertBlob or retrieveBlob are valid.
|
||||
*/
|
||||
bool hasBlobFunc() const noexcept {
|
||||
return hasInsertBlobFunc() || hasRetrieveBlobFunc();
|
||||
}
|
||||
|
||||
/**
|
||||
* To insert a new binary value into the cache and associate it with a given
|
||||
|
||||
@@ -239,14 +239,16 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// FIXME: We should be using a Spinlock here, at least on platforms where mutexes are not
|
||||
// efficient (i.e. non-Linux). However, we've seen some hangs on that spinlock, which
|
||||
// we don't understand well (b/308029108).
|
||||
#ifndef NDEBUG
|
||||
using HandleArena = utils::Arena<Allocator,
|
||||
utils::LockingPolicy::SpinLock,
|
||||
utils::LockingPolicy::Mutex,
|
||||
utils::TrackingPolicy::DebugAndHighWatermark>;
|
||||
#else
|
||||
using HandleArena = utils::Arena<Allocator,
|
||||
utils::LockingPolicy::SpinLock>;
|
||||
utils::LockingPolicy::Mutex>;
|
||||
#endif
|
||||
|
||||
// allocateHandle()/deallocateHandle() selects the pool to use at compile-time based on the
|
||||
|
||||
@@ -28,14 +28,16 @@ bool Platform::pumpEvents() noexcept {
|
||||
}
|
||||
|
||||
void Platform::setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept {
|
||||
if (!mInsertBlob && !mRetrieveBlob) {
|
||||
mInsertBlob = std::move(insertBlob);
|
||||
mRetrieveBlob = std::move(retrieveBlob);
|
||||
}
|
||||
mInsertBlob = std::move(insertBlob);
|
||||
mRetrieveBlob = std::move(retrieveBlob);
|
||||
}
|
||||
|
||||
bool Platform::hasBlobFunc() const noexcept {
|
||||
return mInsertBlob && mRetrieveBlob;
|
||||
bool Platform::hasInsertBlobFunc() const noexcept {
|
||||
return bool(mInsertBlob);
|
||||
}
|
||||
|
||||
bool Platform::hasRetrieveBlobFunc() const noexcept {
|
||||
return bool(mRetrieveBlob);
|
||||
}
|
||||
|
||||
void Platform::insertBlob(void const* key, size_t keySize, void const* value, size_t valueSize) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include "OpenGLBlobCache.h"
|
||||
|
||||
#include "OpenGLContext.h"
|
||||
|
||||
#include <backend/Platform.h>
|
||||
#include <backend/Program.h>
|
||||
|
||||
@@ -28,17 +30,18 @@ struct OpenGLBlobCache::Blob {
|
||||
char data[];
|
||||
};
|
||||
|
||||
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
Program const& program) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
OpenGLBlobCache::OpenGLBlobCache(OpenGLContext& gl) noexcept
|
||||
: mCachingSupported(gl.gets.num_program_binary_formats >= 1) {
|
||||
}
|
||||
|
||||
if (!platform.hasBlobFunc()) {
|
||||
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
Program const& program) const noexcept {
|
||||
SYSTRACE_CALL();
|
||||
if (!mCachingSupported || !platform.hasRetrieveBlobFunc()) {
|
||||
// the key is never updated in that case
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYSTRACE_CONTEXT();
|
||||
|
||||
GLuint programId = 0;
|
||||
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
@@ -64,8 +67,10 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
|
||||
programId = glCreateProgram();
|
||||
|
||||
SYSTRACE_NAME("glProgramBinary");
|
||||
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
|
||||
{ // scope for systrace
|
||||
SYSTRACE_NAME("glProgramBinary");
|
||||
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
|
||||
}
|
||||
|
||||
if (UTILS_UNLIKELY(glGetError() != GL_NO_ERROR)) {
|
||||
// glProgramBinary can fail if for instance the driver has been updated
|
||||
@@ -85,46 +90,36 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
|
||||
void OpenGLBlobCache::insert(Platform& platform,
|
||||
BlobCacheKey const& key, GLuint program) noexcept {
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
SYSTRACE_CALL();
|
||||
if (platform.hasBlobFunc()) {
|
||||
SYSTRACE_CONTEXT();
|
||||
GLenum format;
|
||||
GLint programBinarySize = 0;
|
||||
if (!mCachingSupported || !platform.hasInsertBlobFunc()) {
|
||||
// the key is never updated in that case
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
GLenum format;
|
||||
GLint programBinarySize = 0;
|
||||
{ // scope for systrace
|
||||
SYSTRACE_NAME("glGetProgramiv");
|
||||
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinarySize);
|
||||
if (programBinarySize) {
|
||||
size_t const size = sizeof(Blob) + programBinarySize;
|
||||
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
||||
if (UTILS_LIKELY(blob)) {
|
||||
}
|
||||
if (programBinarySize) {
|
||||
size_t const size = sizeof(Blob) + programBinarySize;
|
||||
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
||||
if (UTILS_LIKELY(blob)) {
|
||||
{ // scope for systrace
|
||||
SYSTRACE_NAME("glGetProgramBinary");
|
||||
glGetProgramBinary(program, programBinarySize, &programBinarySize, &format,
|
||||
blob->data);
|
||||
GLenum const error = glGetError();
|
||||
if (error == GL_NO_ERROR) {
|
||||
blob->format = format;
|
||||
platform.insertBlob(key.data(), key.size(), blob.get(), size);
|
||||
}
|
||||
glGetProgramBinary(program, programBinarySize,
|
||||
&programBinarySize, &format, blob->data);
|
||||
}
|
||||
GLenum const error = glGetError();
|
||||
if (error == GL_NO_ERROR) {
|
||||
blob->format = format;
|
||||
platform.insertBlob(key.data(), key.size(), blob.get(), size);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLBlobCache::insert(Platform& platform, BlobCacheKey const& key,
|
||||
GLenum format, void* data, GLsizei programBinarySize) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
if (platform.hasBlobFunc()) {
|
||||
if (programBinarySize) {
|
||||
size_t const size = sizeof(Blob) + programBinarySize;
|
||||
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
||||
if (UTILS_LIKELY(blob)) {
|
||||
blob->format = format;
|
||||
memcpy(blob->data, data, programBinarySize);
|
||||
platform.insertBlob(key.data(), key.size(), blob.get(), size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -25,20 +25,21 @@ namespace filament::backend {
|
||||
|
||||
class Platform;
|
||||
class Program;
|
||||
class OpenGLContext;
|
||||
|
||||
class OpenGLBlobCache {
|
||||
public:
|
||||
static GLuint retrieve(BlobCacheKey* key, Platform& platform,
|
||||
Program const& program) noexcept;
|
||||
explicit OpenGLBlobCache(OpenGLContext& gl) noexcept;
|
||||
|
||||
static void insert(Platform& platform,
|
||||
GLuint retrieve(BlobCacheKey* key, Platform& platform,
|
||||
Program const& program) const noexcept;
|
||||
|
||||
void insert(Platform& platform,
|
||||
BlobCacheKey const& key, GLuint program) noexcept;
|
||||
|
||||
static void insert(Platform& platform, BlobCacheKey const& key,
|
||||
GLenum format, void* data, GLsizei programBinarySize) noexcept;
|
||||
|
||||
private:
|
||||
struct Blob;
|
||||
bool mCachingSupported = false;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -99,38 +99,41 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
|
||||
if (mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,
|
||||
&gets.max_uniform_block_size);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
|
||||
&gets.max_uniform_buffer_bindings);
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
|
||||
&gets.uniform_buffer_offset_alignment);
|
||||
glGetIntegerv(GL_MAX_SAMPLES,
|
||||
&gets.max_samples);
|
||||
glGetIntegerv(GL_MAX_DRAW_BUFFERS,
|
||||
&gets.max_draw_buffers);
|
||||
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
|
||||
&gets.max_transform_feedback_separate_attribs);
|
||||
#ifdef GL_EXT_texture_filter_anisotropic
|
||||
if (ext.EXT_texture_filter_anisotropic) {
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gets.max_anisotropy);
|
||||
}
|
||||
#endif
|
||||
glGetIntegerv(GL_MAX_DRAW_BUFFERS,
|
||||
&gets.max_draw_buffers);
|
||||
glGetIntegerv(GL_MAX_SAMPLES,
|
||||
&gets.max_samples);
|
||||
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
|
||||
&gets.max_transform_feedback_separate_attribs);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,
|
||||
&gets.max_uniform_block_size);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
|
||||
&gets.max_uniform_buffer_bindings);
|
||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS,
|
||||
&gets.num_program_binary_formats);
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
|
||||
&gets.uniform_buffer_offset_alignment);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
else {
|
||||
gets.max_anisotropy = 1;
|
||||
gets.max_draw_buffers = 1;
|
||||
gets.max_samples = 1;
|
||||
gets.max_transform_feedback_separate_attribs = 0;
|
||||
gets.max_uniform_block_size = 0;
|
||||
gets.max_uniform_buffer_bindings = 0;
|
||||
gets.num_program_binary_formats = 0;
|
||||
gets.uniform_buffer_offset_alignment = 0;
|
||||
gets.max_samples = 1;
|
||||
gets.max_draw_buffers = 1;
|
||||
gets.max_transform_feedback_separate_attribs = 0;
|
||||
gets.max_anisotropy = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
slog.v << "Feature level: " << +mFeatureLevel << '\n';
|
||||
slog.v << "Active workarounds: " << '\n';
|
||||
UTILS_NOUNROLL
|
||||
@@ -143,13 +146,18 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
|
||||
#ifndef NDEBUG
|
||||
// this is useful for development
|
||||
slog.v << "GL_MAX_DRAW_BUFFERS = " << gets.max_draw_buffers << '\n'
|
||||
<< "GL_MAX_RENDERBUFFER_SIZE = " << gets.max_renderbuffer_size << '\n'
|
||||
<< "GL_MAX_SAMPLES = " << gets.max_samples << '\n'
|
||||
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = " << gets.max_anisotropy << '\n'
|
||||
<< "GL_MAX_UNIFORM_BLOCK_SIZE = " << gets.max_uniform_block_size << '\n'
|
||||
<< "GL_MAX_TEXTURE_IMAGE_UNITS = " << gets.max_texture_image_units << '\n'
|
||||
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = " << gets.uniform_buffer_offset_alignment << '\n'
|
||||
slog.v
|
||||
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT" << gets.max_anisotropy << '\n'
|
||||
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS" << gets.max_combined_texture_image_units << '\n'
|
||||
<< "GL_MAX_DRAW_BUFFERS" << gets.max_draw_buffers << '\n'
|
||||
<< "GL_MAX_RENDERBUFFER_SIZE" << gets.max_renderbuffer_size << '\n'
|
||||
<< "GL_MAX_SAMPLES" << gets.max_samples << '\n'
|
||||
<< "GL_MAX_TEXTURE_IMAGE_UNITS" << gets.max_texture_image_units << '\n'
|
||||
<< "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS" << gets.max_transform_feedback_separate_attribs << '\n'
|
||||
<< "GL_MAX_UNIFORM_BLOCK_SIZE" << gets.max_uniform_block_size << '\n'
|
||||
<< "GL_MAX_UNIFORM_BUFFER_BINDINGS" << gets.max_uniform_buffer_bindings << '\n'
|
||||
<< "GL_NUM_PROGRAM_BINARY_FORMATS" << gets.num_program_binary_formats << '\n'
|
||||
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT" << gets.uniform_buffer_offset_alignment << '\n'
|
||||
;
|
||||
flush(slog.v);
|
||||
#endif
|
||||
|
||||
@@ -153,14 +153,15 @@ public:
|
||||
// glGet*() values
|
||||
struct Gets {
|
||||
GLfloat max_anisotropy;
|
||||
GLint max_combined_texture_image_units;
|
||||
GLint max_draw_buffers;
|
||||
GLint max_renderbuffer_size;
|
||||
GLint max_samples;
|
||||
GLint max_uniform_block_size;
|
||||
GLint max_texture_image_units;
|
||||
GLint max_combined_texture_image_units;
|
||||
GLint max_transform_feedback_separate_attribs;
|
||||
GLint max_uniform_buffer_bindings;
|
||||
GLint max_uniform_block_size;
|
||||
GLint max_uniform_buffer_bindings;
|
||||
GLint num_program_binary_formats;
|
||||
GLint uniform_buffer_offset_alignment;
|
||||
} gets = {};
|
||||
|
||||
|
||||
@@ -140,6 +140,7 @@ void* ShaderCompilerService::getUserData(const program_token_t& token) noexcept
|
||||
|
||||
ShaderCompilerService::ShaderCompilerService(OpenGLDriver& driver)
|
||||
: mDriver(driver),
|
||||
mBlobCache(driver.getContext()),
|
||||
mCallbackManager(driver),
|
||||
KHR_parallel_shader_compile(driver.getContext().ext.KHR_parallel_shader_compile) {
|
||||
}
|
||||
@@ -219,7 +220,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
||||
token->attributes = std::move(program.getAttributes());
|
||||
}
|
||||
|
||||
token->gl.program = OpenGLBlobCache::retrieve(&token->key, mDriver.mPlatform, program);
|
||||
token->gl.program = mBlobCache.retrieve(&token->key, mDriver.mPlatform, program);
|
||||
if (token->gl.program) {
|
||||
return token;
|
||||
}
|
||||
@@ -264,7 +265,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
||||
// caching must be the last thing we do
|
||||
if (token->key && status == GL_TRUE) {
|
||||
// Attempt to cache. This calls glGetProgramBinary.
|
||||
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, glProgram);
|
||||
mBlobCache.insert(mDriver.mPlatform, token->key, glProgram);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -317,7 +318,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
||||
// do this later, maybe depending on CPU usage?
|
||||
// attempt to cache if we don't have a thread pool (otherwise it's done
|
||||
// by the pool).
|
||||
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, token->gl.program);
|
||||
mBlobCache.insert(mDriver.mPlatform, token->key, token->gl.program);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -431,7 +432,7 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) noexcept {
|
||||
mCallbackManager.put(token->handle);
|
||||
|
||||
if (token->key) {
|
||||
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, token->gl.program);
|
||||
mBlobCache.insert(mDriver.mPlatform, token->key, token->gl.program);
|
||||
}
|
||||
} else {
|
||||
// if we don't have a program yet, block until we get it.
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "CallbackManager.h"
|
||||
#include "CompilerThreadPool.h"
|
||||
#include "OpenGLBlobCache.h"
|
||||
|
||||
#include <backend/CallbackHandler.h>
|
||||
#include <backend/Program.h>
|
||||
@@ -95,6 +96,7 @@ public:
|
||||
|
||||
private:
|
||||
OpenGLDriver& mDriver;
|
||||
OpenGLBlobCache mBlobCache;
|
||||
CallbackManager mCallbackManager;
|
||||
CompilerThreadPool mCompilerThreadPool;
|
||||
|
||||
|
||||
@@ -110,6 +110,10 @@ public:
|
||||
* @return The maximum capacity of the BufferObject.
|
||||
*/
|
||||
size_t getByteCount() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~BufferObject() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -565,6 +565,10 @@ public:
|
||||
* @return effective full field of view in degrees
|
||||
*/
|
||||
static double computeEffectiveFov(double fovInDegrees, double focusDistance) noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Camera() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -478,6 +478,10 @@ public:
|
||||
private:
|
||||
friend class FColorGrading;
|
||||
};
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~ColorGrading() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -142,6 +142,10 @@ public:
|
||||
float pid_i = 0.0f;
|
||||
float pid_d = 0.0f;
|
||||
};
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~DebugRegistry() = default;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -75,6 +75,10 @@ public:
|
||||
* FenceStatus::ERROR otherwise.
|
||||
*/
|
||||
static FenceStatus waitAndDestroy(Fence* fence, Mode mode = Mode::FLUSH);
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Fence() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -49,8 +49,6 @@ public:
|
||||
// prevent heap allocation
|
||||
static void *operator new (size_t) = delete;
|
||||
static void *operator new[] (size_t) = delete;
|
||||
static void operator delete (void*) = delete;
|
||||
static void operator delete[](void*) = delete;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -118,6 +118,10 @@ public:
|
||||
* @return The number of indices the IndexBuffer holds.
|
||||
*/
|
||||
size_t getIndexCount() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~IndexBuffer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -342,6 +342,10 @@ public:
|
||||
/** @deprecated use static versions instead */
|
||||
UTILS_DEPRECATED
|
||||
math::float4 getColorEstimate(math::float3 direction) const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~IndirectLight() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -91,6 +91,10 @@ public:
|
||||
* @param offset index of the first instance to set local transforms
|
||||
*/
|
||||
void setLocalTransforms(math::mat4f const* localTransforms, size_t count, size_t offset = 0);
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~InstanceBuffer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -143,20 +143,13 @@ public:
|
||||
using Instance = utils::EntityInstance<LightManager>;
|
||||
|
||||
/**
|
||||
* Returns the number of component in the LightManager, not that component are not
|
||||
* Returns the number of component in the LightManager, note that component are not
|
||||
* guaranteed to be active. Use the EntityManager::isAlive() before use if needed.
|
||||
*
|
||||
* @return number of component in the LightManager
|
||||
*/
|
||||
size_t getComponentCount() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the list of Entity for all components. Use getComponentCount() to know the size
|
||||
* of the list.
|
||||
* @return a pointer to Entity
|
||||
*/
|
||||
utils::Entity const* getEntities() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns whether a particular Entity is associated with a component of this LightManager
|
||||
* @param e An Entity.
|
||||
@@ -164,6 +157,24 @@ public:
|
||||
*/
|
||||
bool hasComponent(utils::Entity e) const noexcept;
|
||||
|
||||
/**
|
||||
* @return true if the this manager has no components
|
||||
*/
|
||||
bool empty() const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the `Entity` of the component from its `Instance`.
|
||||
* @param i Instance of the component obtained from getInstance()
|
||||
* @return
|
||||
*/
|
||||
utils::Entity getEntity(Instance i) const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the Entities of all the components of this manager.
|
||||
* @return A list, in no particular order, of all the entities managed by this manager.
|
||||
*/
|
||||
utils::Entity const* getEntities() const noexcept;
|
||||
|
||||
/**
|
||||
* Gets an Instance representing the Light component associated with the given Entity.
|
||||
* @param e An Entity.
|
||||
@@ -953,19 +964,9 @@ public:
|
||||
*/
|
||||
bool isShadowCaster(Instance i) const noexcept;
|
||||
|
||||
/**
|
||||
* Helper to process all components with a given function
|
||||
* @tparam F a void(Entity entity, Instance instance)
|
||||
* @param func a function of type F
|
||||
*/
|
||||
template<typename F>
|
||||
void forEachComponent(F func) noexcept {
|
||||
utils::Entity const* const pEntity = getEntities();
|
||||
for (size_t i = 0, c = getComponentCount(); i < c; i++) {
|
||||
// Instance 0 is the invalid instance
|
||||
func(pEntity[i], Instance(i + 1));
|
||||
}
|
||||
}
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~LightManager() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -375,6 +375,10 @@ public:
|
||||
|
||||
//! Returns this material's default instance.
|
||||
MaterialInstance const* getDefaultInstance() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Material() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -479,6 +479,10 @@ public:
|
||||
*/
|
||||
void setStencilWriteMask(uint8_t writeMask,
|
||||
StencilFace face = StencilFace::FRONT_AND_BACK) noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~MaterialInstance() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -136,6 +136,10 @@ public:
|
||||
* @return The number of targets the MorphTargetBuffer holds.
|
||||
*/
|
||||
size_t getCount() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~MorphTargetBuffer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -180,6 +180,10 @@ public:
|
||||
* @return Number of color attachments usable in a render target.
|
||||
*/
|
||||
uint8_t getSupportedColorAttachmentsCount() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~RenderTarget() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -102,6 +102,29 @@ public:
|
||||
*/
|
||||
Instance getInstance(utils::Entity e) const noexcept;
|
||||
|
||||
/**
|
||||
* @return the number of Components
|
||||
*/
|
||||
size_t getComponentCount() const noexcept;
|
||||
|
||||
/**
|
||||
* @return true if the this manager has no components
|
||||
*/
|
||||
bool empty() const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the `Entity` of the component from its `Instance`.
|
||||
* @param i Instance of the component obtained from getInstance()
|
||||
* @return
|
||||
*/
|
||||
utils::Entity getEntity(Instance i) const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the Entities of all the components of this manager.
|
||||
* @return A list, in no particular order, of all the entities managed by this manager.
|
||||
*/
|
||||
utils::Entity const* getEntities() const noexcept;
|
||||
|
||||
/**
|
||||
* The transformation associated with a skinning joint.
|
||||
*
|
||||
@@ -829,6 +852,10 @@ public:
|
||||
typename = typename is_supported_index_type<INDEX>::type>
|
||||
static Box computeAABB(VECTOR const* vertices, INDEX const* indices, size_t count,
|
||||
size_t stride = sizeof(VECTOR)) noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~RenderableManager() = default;
|
||||
};
|
||||
|
||||
RenderableManager::Builder& RenderableManager::Builder::morphing(uint8_t level, size_t primitiveIndex,
|
||||
|
||||
@@ -579,6 +579,10 @@ public:
|
||||
* getUserTime()
|
||||
*/
|
||||
void resetUserTime();
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Renderer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -140,16 +140,22 @@ public:
|
||||
void removeEntities(const utils::Entity* entities, size_t count);
|
||||
|
||||
/**
|
||||
* Returns the number of Renderable objects in the Scene.
|
||||
* Returns the total number of Entities in the Scene, whether alive or not.
|
||||
* @return Total number of Entities in the Scene.
|
||||
*/
|
||||
size_t getEntityCount() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the number of active (alive) Renderable objects in the Scene.
|
||||
*
|
||||
* @return number of Renderable objects in the Scene.
|
||||
* @return The number of active (alive) Renderable objects in the Scene.
|
||||
*/
|
||||
size_t getRenderableCount() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the total number of Light objects in the Scene.
|
||||
* Returns the number of active (alive) Light objects in the Scene.
|
||||
*
|
||||
* @return The total number of Light objects in the Scene.
|
||||
* @return The number of active (alive) Light objects in the Scene.
|
||||
*/
|
||||
size_t getLightCount() const noexcept;
|
||||
|
||||
@@ -168,6 +174,10 @@ public:
|
||||
* @param functor User provided functor called for each entity in the scene
|
||||
*/
|
||||
void forEach(utils::Invocable<void(utils::Entity entity)>&& functor) const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Scene() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -115,6 +115,10 @@ public:
|
||||
* @return The number of bones the SkinningBuffer holds.
|
||||
*/
|
||||
size_t getBoneCount() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~SkinningBuffer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -174,6 +174,10 @@ public:
|
||||
* @return the associated texture, or null if it does not exist
|
||||
*/
|
||||
Texture const* getTexture() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Skybox() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -207,6 +207,10 @@ public:
|
||||
* @return timestamp in nanosecond.
|
||||
*/
|
||||
int64_t getTimestamp() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Stream() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -286,6 +286,10 @@ public:
|
||||
void setFrameCompletedCallback(backend::CallbackHandler* handler = nullptr,
|
||||
FrameCompletedCallback&& callback = {}) noexcept;
|
||||
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~SwapChain() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -541,6 +541,10 @@ public:
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Texture() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -118,6 +118,29 @@ public:
|
||||
*/
|
||||
Instance getInstance(utils::Entity e) const noexcept;
|
||||
|
||||
/**
|
||||
* @return the number of Components
|
||||
*/
|
||||
size_t getComponentCount() const noexcept;
|
||||
|
||||
/**
|
||||
* @return true if the this manager has no components
|
||||
*/
|
||||
bool empty() const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the `Entity` of the component from its `Instance`.
|
||||
* @param i Instance of the component obtained from getInstance()
|
||||
* @return
|
||||
*/
|
||||
utils::Entity getEntity(Instance i) const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the Entities of all the components of this manager.
|
||||
* @return A list, in no particular order, of all the entities managed by this manager.
|
||||
*/
|
||||
utils::Entity const* getEntities() const noexcept;
|
||||
|
||||
/**
|
||||
* Enables or disable the accurate translation mode. Disabled by default.
|
||||
*
|
||||
@@ -261,7 +284,7 @@ public:
|
||||
* returns the value set by setTransform().
|
||||
* @see setTransform()
|
||||
*/
|
||||
const math::mat4 getTransformAccurate(Instance ci) const noexcept;
|
||||
math::mat4 getTransformAccurate(Instance ci) const noexcept;
|
||||
|
||||
/**
|
||||
* Return the world transform of a transform component.
|
||||
@@ -279,7 +302,7 @@ public:
|
||||
* composition of this component's local transform with its parent's world transform.
|
||||
* @see setTransform()
|
||||
*/
|
||||
const math::mat4 getWorldTransformAccurate(Instance ci) const noexcept;
|
||||
math::mat4 getWorldTransformAccurate(Instance ci) const noexcept;
|
||||
|
||||
/**
|
||||
* Opens a local transform transaction. During a transaction, getWorldTransform() can
|
||||
@@ -308,6 +331,10 @@ public:
|
||||
* @see openLocalTransformTransaction(), setTransform()
|
||||
*/
|
||||
void commitLocalTransformTransaction() noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~TransformManager() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -207,6 +207,10 @@ public:
|
||||
* @param bufferObject The handle to the GPU data that will be used in this buffer slot.
|
||||
*/
|
||||
void setBufferObjectAt(Engine& engine, uint8_t bufferIndex, BufferObject const* bufferObject);
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~VertexBuffer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -894,6 +894,10 @@ public:
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
AmbientOcclusion getAmbientOcclusion() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~View() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -22,16 +22,24 @@ namespace filament {
|
||||
|
||||
using namespace math;
|
||||
|
||||
bool LightManager::hasComponent(Entity e) const noexcept {
|
||||
return downcast(this)->hasComponent(e);
|
||||
}
|
||||
|
||||
size_t LightManager::getComponentCount() const noexcept {
|
||||
return downcast(this)->getComponentCount();
|
||||
}
|
||||
|
||||
utils::Entity const* LightManager::getEntities() const noexcept {
|
||||
return downcast(this)->getEntities();
|
||||
bool LightManager::empty() const noexcept {
|
||||
return downcast(this)->empty();
|
||||
}
|
||||
|
||||
bool LightManager::hasComponent(Entity e) const noexcept {
|
||||
return downcast(this)->hasComponent(e);
|
||||
utils::Entity LightManager::getEntity(LightManager::Instance i) const noexcept {
|
||||
return downcast(this)->getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* LightManager::getEntities() const noexcept {
|
||||
return downcast(this)->getEntities();
|
||||
}
|
||||
|
||||
LightManager::Instance LightManager::getInstance(Entity e) const noexcept {
|
||||
|
||||
@@ -60,7 +60,7 @@ void PerShadowMapUniforms::prepareCamera(Transaction const& transaction,
|
||||
s.viewFromClipMatrix = viewFromClip; // 1/projection
|
||||
s.clipFromWorldMatrix[0] = clipFromWorld; // projection * view
|
||||
s.worldFromClipMatrix = worldFromClip; // 1/(projection * view)
|
||||
s.userWorldFromWorldMatrix = mat4f(inverse(camera.worldTransform));
|
||||
s.userWorldFromWorldMatrix = mat4f(inverse(camera.worldOrigin));
|
||||
s.clipTransform = camera.clipTransform;
|
||||
s.cameraFar = camera.zf;
|
||||
s.oneOverFarMinusNear = 1.0f / (camera.zf - camera.zn);
|
||||
|
||||
@@ -75,7 +75,7 @@ void PerViewUniforms::prepareCamera(FEngine& engine, const CameraInfo& camera) n
|
||||
s.clipFromViewMatrix = clipFromView; // projection
|
||||
s.viewFromClipMatrix = viewFromClip; // 1/projection
|
||||
s.worldFromClipMatrix = worldFromClip; // 1/(projection * view)
|
||||
s.userWorldFromWorldMatrix = mat4f(inverse(camera.worldTransform));
|
||||
s.userWorldFromWorldMatrix = mat4f(inverse(camera.worldOrigin));
|
||||
s.clipTransform = camera.clipTransform;
|
||||
s.cameraFar = camera.zf;
|
||||
s.oneOverFarMinusNear = 1.0f / (camera.zf - camera.zn);
|
||||
@@ -151,7 +151,7 @@ void PerViewUniforms::prepareFog(FEngine& engine, const CameraInfo& cameraInfo,
|
||||
// why we store the cofactor matrix.
|
||||
|
||||
mat4f const viewFromWorld = cameraInfo.view;
|
||||
mat4 const worldFromUserWorld = cameraInfo.worldTransform;
|
||||
mat4 const worldFromUserWorld = cameraInfo.worldOrigin;
|
||||
mat4 const worldFromFog = worldFromUserWorld * userWorldFromFog;
|
||||
mat4 const viewFromFog = viewFromWorld * worldFromFog;
|
||||
|
||||
|
||||
@@ -31,6 +31,22 @@ bool RenderableManager::hasComponent(utils::Entity e) const noexcept {
|
||||
return downcast(this)->hasComponent(e);
|
||||
}
|
||||
|
||||
size_t RenderableManager::getComponentCount() const noexcept {
|
||||
return downcast(this)->getComponentCount();
|
||||
}
|
||||
|
||||
bool RenderableManager::empty() const noexcept {
|
||||
return downcast(this)->empty();
|
||||
}
|
||||
|
||||
utils::Entity RenderableManager::getEntity(RenderableManager::Instance i) const noexcept {
|
||||
return downcast(this)->getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* RenderableManager::getEntities() const noexcept {
|
||||
return downcast(this)->getEntities();
|
||||
}
|
||||
|
||||
RenderableManager::Instance
|
||||
RenderableManager::getInstance(utils::Entity e) const noexcept {
|
||||
return downcast(this)->getInstance(e);
|
||||
|
||||
@@ -55,6 +55,10 @@ void Scene::removeEntities(const Entity* entities, size_t count) {
|
||||
downcast(this)->removeEntities(entities, count);
|
||||
}
|
||||
|
||||
size_t Scene::getEntityCount() const noexcept {
|
||||
return downcast(this)->getEntityCount();
|
||||
}
|
||||
|
||||
size_t Scene::getRenderableCount() const noexcept {
|
||||
return downcast(this)->getRenderableCount();
|
||||
}
|
||||
|
||||
@@ -77,13 +77,20 @@ void ShadowMap::initialize(size_t lightIndex, ShadowType shadowType,
|
||||
mFace = face;
|
||||
}
|
||||
|
||||
math::mat4f ShadowMap::getDirectionalLightViewMatrix(math::float3 direction, math::float3 up,
|
||||
math::float3 position) noexcept {
|
||||
// 1. we use the x-axis as the "up" reference so that the math is stable when the light
|
||||
// is pointing down, which is a common case for lights.
|
||||
// 2. we do the math in double to avoid some precision issues when the light is almost
|
||||
// straight (i.e. parallel to the x-axis)
|
||||
mat4f const Mm = mat4f{ mat4::lookTo(direction, position, up) };
|
||||
mat4f ShadowMap::getDirectionalLightViewMatrix(float3 direction, float3 position) noexcept {
|
||||
auto z_axis = direction;
|
||||
auto norm_up = float3{ 0, 1, 0 };
|
||||
if (UTILS_UNLIKELY(std::abs(dot(z_axis, norm_up)) > 0.999f)) {
|
||||
// Fix up vector if we're degenerate (looking straight up, basically)
|
||||
norm_up = { norm_up.z, norm_up.x, norm_up.y };
|
||||
}
|
||||
auto x_axis = normalize(cross(z_axis, norm_up));
|
||||
auto y_axis = cross(x_axis, z_axis);
|
||||
const mat4f Mm{
|
||||
float4{ x_axis, 0 },
|
||||
float4{ y_axis, 0 },
|
||||
float4{ -z_axis, 0 },
|
||||
float4{ position, 1 }};
|
||||
return FCamera::rigidTransformInverse(Mm);
|
||||
}
|
||||
|
||||
@@ -98,7 +105,7 @@ math::mat4f ShadowMap::getPointLightViewMatrix(backend::TextureCubemapFace face,
|
||||
case TextureCubemapFace::POSITIVE_Z: direction = { 0, 0, 1 }; break;
|
||||
case TextureCubemapFace::NEGATIVE_Z: direction = { 0, 0, -1 }; break;
|
||||
}
|
||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, { 0, 1, 0 }, position);
|
||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, position);
|
||||
return Mv;
|
||||
}
|
||||
|
||||
@@ -113,7 +120,7 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
FLightManager::ShadowParams const params = lcm.getShadowParams(li);
|
||||
|
||||
// We can't use LISPSM in stable mode
|
||||
const auto direction = lightData.elementAt<FScene::SHADOW_DIRECTION>(index);
|
||||
const auto direction = params.options.transform * lightData.elementAt<FScene::DIRECTION>(index);
|
||||
|
||||
auto [Mv, znear, zfar, lsClippedShadowVolume, vertexCount, visibleShadows] =
|
||||
computeDirectionalShadowBounds(engine, direction, params, camera, sceneInfo);
|
||||
@@ -159,22 +166,11 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
// This is the most important step to increase the quality of the shadow map.
|
||||
//
|
||||
// In LiPSM mode, we're using the warped space here.
|
||||
float4 f = computeFocusParams(LMpMv, WLMp,
|
||||
const mat4f F = computeFocusMatrix(LMpMv, WLMp,
|
||||
sceneInfo.wsShadowReceiversVolume,
|
||||
lsClippedShadowVolume, vertexCount,
|
||||
camera, sceneInfo.csNearFar,
|
||||
params.options.shadowFar, params.options.stable);
|
||||
|
||||
if (params.options.stable) {
|
||||
const auto lsRef = lightData.elementAt<FScene::SHADOW_REF>(index);
|
||||
snapLightFrustum(f.xy, f.zw, lsRef, shadowMapInfo.shadowDimension);
|
||||
}
|
||||
|
||||
const mat4f F(mat4f::row_major_init {
|
||||
f.x, 0.0f, 0.0f, f.z,
|
||||
0.0f, f.y, 0.0f, f.w,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f,
|
||||
});
|
||||
shadowMapInfo.shadowDimension, params.options.stable);
|
||||
|
||||
/*
|
||||
* Final shadow map transform
|
||||
@@ -226,7 +222,7 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
mCamera->setCustomProjection(mat4(Mn * F * WLMp), znear, zfar);
|
||||
|
||||
// for the debug camera, we need to undo the world origin
|
||||
mDebugCamera->setCustomProjection(mat4(S * b * camera.worldTransform), znear, zfar);
|
||||
mDebugCamera->setCustomProjection(mat4(S * b * camera.worldOrigin), znear, zfar);
|
||||
|
||||
mHasVisibleShadows = true;
|
||||
|
||||
@@ -301,7 +297,7 @@ ShadowMap::ShaderParameters ShadowMap::updateSpot(FEngine& engine,
|
||||
auto radius = lightData.elementAt<FScene::POSITION_RADIUS>(index).w;
|
||||
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
const FLightManager::ShadowParams& params = lcm.getShadowParams(li);
|
||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, { 0, 1, 0 }, position);
|
||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, position);
|
||||
|
||||
// We only keep this for reference. updateSceneInfoSpot() is quite expensive on large scenes
|
||||
// currently, and only needed to find a near/far. Instead, we just use a small near and the
|
||||
@@ -405,8 +401,7 @@ ShadowMap::DirectionalShadowBounds ShadowMap::computeDirectionalShadowBounds(
|
||||
// We compute the directional light's model matrix using the origin's as the light position.
|
||||
// The choice of the light's origin initially doesn't matter for a directional light.
|
||||
// This will be adjusted later because of how we compute the depth metric for VSM.
|
||||
mat4f const MvAtOrigin = ShadowMap::getDirectionalLightViewMatrix(direction,
|
||||
normalize(camera.worldTransform[0].xyz));
|
||||
mat4f const MvAtOrigin = ShadowMap::getDirectionalLightViewMatrix(direction);
|
||||
|
||||
|
||||
Aabb lsLightFrustumBounds = computeLightFrustumBounds(
|
||||
@@ -460,6 +455,10 @@ ShadowMap::DirectionalShadowBounds ShadowMap::computeDirectionalShadowBounds(
|
||||
std::max(lsLightFrustumBounds.min.z, sceneInfo.lsCastersNearFar[1]);
|
||||
}
|
||||
|
||||
// Now that we know the znear (-lsLightFrustumBounds.max.z), adjust the light's position such
|
||||
// that znear = 0, this is only needed for VSM, but doesn't hurt PCF.
|
||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, direction * -lsLightFrustumBounds.max.z);
|
||||
|
||||
// near / far planes are specified relative to the direction the eye is looking at
|
||||
// i.e. the -z axis (see: ortho)
|
||||
const float znear = 0.0f;
|
||||
@@ -474,11 +473,6 @@ ShadowMap::DirectionalShadowBounds ShadowMap::computeDirectionalShadowBounds(
|
||||
v.z -= lsLightFrustumBounds.max.z;
|
||||
}
|
||||
|
||||
// Now that we know the znear (-lsLightFrustumBounds.max.z), adjust the light's position such
|
||||
// that znear = 0, this is only needed for VSM, but doesn't hurt PCF.
|
||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, normalize(camera.worldTransform[0].xyz),
|
||||
direction * -lsLightFrustumBounds.max.z);
|
||||
|
||||
return { Mv, znear, zfar, lsClippedShadowVolume, vertexCount, true };
|
||||
}
|
||||
|
||||
@@ -583,36 +577,65 @@ math::mat4f ShadowMap::computeLightRotation(math::float3 const& lsDirection) noe
|
||||
return L;
|
||||
}
|
||||
|
||||
math::float4 ShadowMap::computeFocusParams(
|
||||
mat4f const& LMpMv,
|
||||
mat4f const& WLMp,
|
||||
math::mat4f ShadowMap::computeFocusMatrix(
|
||||
const mat4f& LMpMv, const mat4f& WLMp,
|
||||
Aabb const& wsShadowReceiversVolume,
|
||||
FrustumBoxIntersection const& lsShadowVolume, size_t vertexCount,
|
||||
filament::CameraInfo const& camera, float2 const& csNearFar,
|
||||
float shadowFar, bool stable) noexcept {
|
||||
uint16_t shadowDimension, bool stable) noexcept {
|
||||
|
||||
float2 s, o;
|
||||
float4 wsViewVolumeBoundingSphere = {};
|
||||
|
||||
if (stable) {
|
||||
// In stable mode, the light frustum size must be fixed, so we choose the
|
||||
// whole view frustum.
|
||||
// We simply take the view volume bounding sphere, but we calculate it
|
||||
// In stable mode, the light frustum size must be fixed, so we can choose either the
|
||||
// whole view frustum, or the whole scene bounding volume. We simply pick whichever
|
||||
// is smaller.
|
||||
|
||||
// in stable mode we simply take the shadow receivers volume
|
||||
const float4 shadowReceiverVolumeBoundingSphere = computeBoundingSphere(
|
||||
wsShadowReceiversVolume.getCorners().data(), 8);
|
||||
|
||||
// in stable mode we simply take the view volume bounding sphere, but we calculate it
|
||||
// in view space, so that it's perfectly stable.
|
||||
mat4f const viewFromClip = inverse(camera.cullingProjection);
|
||||
Corners const wsFrustumVertices = computeFrustumCorners(viewFromClip, csNearFar);
|
||||
wsViewVolumeBoundingSphere = computeBoundingSphere(wsFrustumVertices.vertices, 8);
|
||||
|
||||
auto getViewVolumeBoundingSphere = [&]() {
|
||||
if (shadowFar > 0) {
|
||||
float4 const wsViewVolumeBoundingSphere = { camera.getPosition(), shadowFar };
|
||||
return wsViewVolumeBoundingSphere;
|
||||
} else {
|
||||
mat4f const viewFromClip = inverse(camera.cullingProjection);
|
||||
Corners const wsFrustumVertices = computeFrustumCorners(viewFromClip, csNearFar);
|
||||
float4 const wsViewVolumeBoundingSphere =
|
||||
computeBoundingSphere(wsFrustumVertices.vertices, 8);
|
||||
return wsViewVolumeBoundingSphere;
|
||||
}
|
||||
};
|
||||
if (shadowReceiverVolumeBoundingSphere.w < wsViewVolumeBoundingSphere.w) {
|
||||
// When using the shadowReceiver volume, we don't have to use its enclosing sphere
|
||||
// because (we assume) the scene volume doesn't change. Seen from the light it only
|
||||
// changes when the light moves or rotates, and it is acceptable in that case to have
|
||||
// non "stable" shadows (the shadow will never be stable when the light moves).
|
||||
//
|
||||
// On the other hand, when using the view volume, we must use a sphere because otherwise
|
||||
// its projection's bounds in light space change with the camera, leading to unstable
|
||||
// shadows with camera movement.
|
||||
|
||||
float4 const wsViewVolumeBoundingSphere = getViewVolumeBoundingSphere();
|
||||
s = 1.0f / wsViewVolumeBoundingSphere.w;
|
||||
o = mat4f::project(LMpMv * camera.model, wsViewVolumeBoundingSphere.xyz).xy;
|
||||
o = -s * o;
|
||||
wsViewVolumeBoundingSphere.w = 0;
|
||||
}
|
||||
|
||||
if (wsViewVolumeBoundingSphere.w > 0) {
|
||||
s = 1.0f / wsViewVolumeBoundingSphere.w;
|
||||
o = mat4f::project(LMpMv * camera.model, wsViewVolumeBoundingSphere.xyz).xy;
|
||||
} else {
|
||||
// TODO: another options is the sphere around the intersections of receiver & casters
|
||||
// FIXME: this is not stable with the global rotation because wsShadowReceiversVolume
|
||||
// is not stable with it.
|
||||
Aabb const bounds = compute2DBounds(LMpMv,
|
||||
wsShadowReceiversVolume.getCorners().data(),
|
||||
wsShadowReceiversVolume.getCorners().size());
|
||||
assert_invariant(bounds.min.x < bounds.max.x);
|
||||
assert_invariant(bounds.min.y < bounds.max.y);
|
||||
|
||||
s = 2.0f / float2(bounds.max.xy - bounds.min.xy);
|
||||
o = float2(bounds.max.xy + bounds.min.xy) * 0.5f;
|
||||
|
||||
// Quantize the scale in world-space units. This value can be very small because
|
||||
// if it wasn't for floating-point imprecision, the scale would be a constant.
|
||||
double2 const quantizer = 0.0625;
|
||||
s = 1.0 / (ceil(1.0 / (s * quantizer)) * quantizer);
|
||||
}
|
||||
} else {
|
||||
Aabb const bounds = compute2DBounds(WLMp, lsShadowVolume.data(), vertexCount);
|
||||
assert_invariant(bounds.min.x < bounds.max.x);
|
||||
@@ -620,11 +643,29 @@ math::float4 ShadowMap::computeFocusParams(
|
||||
|
||||
s = 2.0f / float2(bounds.max.xy - bounds.min.xy);
|
||||
o = float2(bounds.max.xy + bounds.min.xy) * 0.5f;
|
||||
o = -s * o;
|
||||
|
||||
// TODO: we could quantize `s` here to give some stability when lispsm is disabled,
|
||||
// however, the quantization paramater should probably be user settable.
|
||||
}
|
||||
return { s, o };
|
||||
|
||||
// adjust offset for scale
|
||||
o = -s * o;
|
||||
|
||||
if (stable) {
|
||||
snapLightFrustum(s, o, LMpMv, wsShadowReceiversVolume.center(), shadowDimension);
|
||||
}
|
||||
|
||||
const mat4f F(mat4f::row_major_init {
|
||||
s.x, 0.0f, 0.0f, o.x,
|
||||
0.0f, s.y, 0.0f, o.y,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f,
|
||||
});
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
|
||||
// Apply these remapping in double to maintain a high precision for the depth axis
|
||||
ShadowMap::TextureCoordsMapping ShadowMap::getTextureCoordsMapping(ShadowMapInfo const& info,
|
||||
backend::Viewport const& viewport) noexcept {
|
||||
@@ -638,8 +679,6 @@ ShadowMap::TextureCoordsMapping ShadowMap::getTextureCoordsMapping(ShadowMapInfo
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
}};
|
||||
|
||||
constexpr mat4f MtInverse = inverse(Mt);
|
||||
|
||||
// apply the viewport transform
|
||||
const float2 o = float2{ viewport.left, viewport.bottom } / float(info.atlasDimension);
|
||||
const float2 s = float2{ viewport.width, viewport.height } / float(info.atlasDimension);
|
||||
@@ -661,7 +700,7 @@ ShadowMap::TextureCoordsMapping ShadowMap::getTextureCoordsMapping(ShadowMapInfo
|
||||
}} : mat4f{};
|
||||
|
||||
// Compute shadow-map texture access and viewport transform
|
||||
return { Mf * (Mv * Mt), MtInverse * (Mv * Mt) };
|
||||
return { Mf * (Mv * Mt), inverse(Mt) * (Mv * Mt) };
|
||||
}
|
||||
|
||||
mat4f ShadowMap::computeVsmLightSpaceMatrix(const mat4f& lightSpacePcf,
|
||||
@@ -802,8 +841,8 @@ ShadowMap::Corners ShadowMap::computeFrustumCorners(
|
||||
|
||||
Aabb ShadowMap::computeLightFrustumBounds(mat4f const& lightView,
|
||||
Aabb const& wsShadowReceiversVolume, Aabb const& wsShadowCastersVolume,
|
||||
ShadowMap::SceneInfo const& sceneInfo,
|
||||
bool stable, bool focusShadowCasters, bool farUsesShadowCasters) noexcept {
|
||||
ShadowMap::SceneInfo const& sceneInfo, bool stable, bool focusShadowCasters,
|
||||
bool farUsesShadowCasters) noexcept {
|
||||
Aabb lsLightFrustumBounds{};
|
||||
|
||||
float const receiversFar = sceneInfo.lsReceiversNearFar[1];
|
||||
@@ -834,13 +873,13 @@ Aabb ShadowMap::computeLightFrustumBounds(mat4f const& lightView,
|
||||
}
|
||||
|
||||
void ShadowMap::snapLightFrustum(float2& s, float2& o,
|
||||
double2 lsRef, int2 resolution) noexcept {
|
||||
mat4f const& Mv, double3 wsSnapCoords, int2 resolution) noexcept {
|
||||
|
||||
auto proj2 = [](mat4 m, double2 v) -> double2 {
|
||||
double2 p;
|
||||
p.x = dot(double2{ m[0].x, m[1].x }, v) + m[3].x;
|
||||
p.y = dot(double2{ m[0].y, m[1].y }, v) + m[3].y;
|
||||
return p;
|
||||
auto proj = [](mat4 m, double3 v) -> double3 {
|
||||
// for directional light p.w == 1, exactly
|
||||
auto p = m * v;
|
||||
assert_invariant(p.w == 1.0);
|
||||
return p.xyz;
|
||||
};
|
||||
|
||||
auto fract = [](auto v) {
|
||||
@@ -857,13 +896,13 @@ void ShadowMap::snapLightFrustum(float2& s, float2& o,
|
||||
});
|
||||
|
||||
// The (resolution * 0.5) comes from Mv having a NDC in the range -1,1 (so a range of 2).
|
||||
// Another (resolution * 0.5) is there to snap on even texels, which helps with debugging
|
||||
|
||||
// focused light-space
|
||||
mat4 const FMv{ F * Mv };
|
||||
|
||||
// This offsets the texture coordinates, so it has a fixed offset w.r.t the world
|
||||
// F * Mv * ref
|
||||
|
||||
double2 const lsFocusedOrigin = proj2(F, lsRef);
|
||||
double2 const d = fract(lsFocusedOrigin * (resolution * 0.25)) / (resolution * 0.25);
|
||||
double2 const lsOrigin = proj(FMv, wsSnapCoords).xy;
|
||||
double2 const d = (fract(lsOrigin * resolution * 0.5) * 2.0) / resolution;
|
||||
|
||||
// adjust offset
|
||||
o -= d;
|
||||
|
||||
@@ -122,8 +122,8 @@ public:
|
||||
uint8_t visibleLayers;
|
||||
};
|
||||
|
||||
static math::mat4f getDirectionalLightViewMatrix(math::float3 direction, math::float3 up,
|
||||
math::float3 position = {}) noexcept;
|
||||
static math::mat4f getDirectionalLightViewMatrix(
|
||||
math::float3 direction, math::float3 position = {}) noexcept;
|
||||
|
||||
static math::mat4f getPointLightViewMatrix(backend::TextureCubemapFace face,
|
||||
math::float3 position) noexcept;
|
||||
@@ -246,15 +246,16 @@ private:
|
||||
|
||||
static inline math::mat4f computeLightRotation(math::float3 const& lsDirection) noexcept;
|
||||
|
||||
static inline math::float4 computeFocusParams(
|
||||
math::mat4f const& LMpMv,
|
||||
math::mat4f const& WLMp,
|
||||
static inline math::mat4f computeFocusMatrix(
|
||||
const math::mat4f& LMpMv,
|
||||
const math::mat4f& WLMp,
|
||||
Aabb const& wsShadowReceiversVolume,
|
||||
FrustumBoxIntersection const& lsShadowVolume, size_t vertexCount,
|
||||
filament::CameraInfo const& camera, math::float2 const& csNearFar,
|
||||
float shadowFar, bool stable) noexcept;
|
||||
uint16_t shadowDimension, bool stable) noexcept;
|
||||
|
||||
static inline void snapLightFrustum(math::float2& s, math::float2& o,
|
||||
math::double2 lsRef, math::int2 resolution) noexcept;
|
||||
math::mat4f const& Mv, math::double3 wsSnapCoords, math::int2 resolution) noexcept;
|
||||
|
||||
static inline Aabb computeLightFrustumBounds(const math::mat4f& lightView,
|
||||
Aabb const& wsShadowReceiversVolume, Aabb const& wsShadowCastersVolume,
|
||||
|
||||
@@ -527,8 +527,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
// We compute the directional light's model matrix using the origin's as the light position.
|
||||
// The choice of the light's origin initially doesn't matter for a directional light.
|
||||
// This will be adjusted later because of how we compute the depth metric for VSM.
|
||||
const mat4f MvAtOrigin = ShadowMap::getDirectionalLightViewMatrix(direction,
|
||||
normalize(cameraInfo.worldTransform[0].xyz));
|
||||
const mat4f MvAtOrigin = ShadowMap::getDirectionalLightViewMatrix(direction);
|
||||
|
||||
// Compute scene-dependent values shared across all cascades
|
||||
ShadowMap::updateSceneInfoDirectional(MvAtOrigin, *scene, sceneInfo);
|
||||
@@ -696,7 +695,7 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
|
||||
const auto outerConeAngle = lcm.getSpotLightOuterCone(li);
|
||||
|
||||
// compute shadow map frustum for culling
|
||||
const mat4f Mv = ShadowMap::getDirectionalLightViewMatrix(direction, { 0, 1, 0 }, position);
|
||||
const mat4f Mv = ShadowMap::getDirectionalLightViewMatrix(direction, position);
|
||||
const mat4f Mp = mat4f::perspective(outerConeAngle * f::RAD_TO_DEG * 2.0f, 1.0f, 0.01f, radius);
|
||||
const mat4f MpMv = math::highPrecisionMultiply(Mp, Mv);
|
||||
const Frustum frustum(MpMv);
|
||||
|
||||
@@ -22,6 +22,30 @@ namespace filament {
|
||||
|
||||
using namespace math;
|
||||
|
||||
bool TransformManager::hasComponent(Entity e) const noexcept {
|
||||
return downcast(this)->hasComponent(e);
|
||||
}
|
||||
|
||||
size_t TransformManager::getComponentCount() const noexcept {
|
||||
return downcast(this)->getComponentCount();
|
||||
}
|
||||
|
||||
bool TransformManager::empty() const noexcept {
|
||||
return downcast(this)->empty();
|
||||
}
|
||||
|
||||
utils::Entity TransformManager::getEntity(TransformManager::Instance i) const noexcept {
|
||||
return downcast(this)->getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* TransformManager::getEntities() const noexcept {
|
||||
return downcast(this)->getEntities();
|
||||
}
|
||||
|
||||
TransformManager::Instance TransformManager::getInstance(Entity e) const noexcept {
|
||||
return downcast(this)->getInstance(e);
|
||||
}
|
||||
|
||||
void TransformManager::create(Entity entity, Instance parent, const mat4f& worldTransform) {
|
||||
downcast(this)->create(entity, parent, worldTransform);
|
||||
}
|
||||
@@ -38,14 +62,6 @@ void TransformManager::destroy(Entity e) noexcept {
|
||||
downcast(this)->destroy(e);
|
||||
}
|
||||
|
||||
bool TransformManager::hasComponent(Entity e) const noexcept {
|
||||
return downcast(this)->hasComponent(e);
|
||||
}
|
||||
|
||||
TransformManager::Instance TransformManager::getInstance(Entity e) const noexcept {
|
||||
return downcast(this)->getInstance(e);
|
||||
}
|
||||
|
||||
void TransformManager::setTransform(Instance ci, const mat4f& model) noexcept {
|
||||
downcast(this)->setTransform(ci, model);
|
||||
}
|
||||
@@ -58,7 +74,7 @@ const mat4f& TransformManager::getTransform(Instance ci) const noexcept {
|
||||
return downcast(this)->getTransform(ci);
|
||||
}
|
||||
|
||||
const mat4 TransformManager::getTransformAccurate(Instance ci) const noexcept {
|
||||
mat4 TransformManager::getTransformAccurate(Instance ci) const noexcept {
|
||||
return downcast(this)->getTransformAccurate(ci);
|
||||
}
|
||||
|
||||
@@ -66,7 +82,7 @@ const mat4f& TransformManager::getWorldTransform(Instance ci) const noexcept {
|
||||
return downcast(this)->getWorldTransform(ci);
|
||||
}
|
||||
|
||||
const mat4 TransformManager::getWorldTransformAccurate(Instance ci) const noexcept {
|
||||
mat4 TransformManager::getWorldTransformAccurate(Instance ci) const noexcept {
|
||||
return downcast(this)->getWorldTransformAccurate(ci);
|
||||
}
|
||||
|
||||
@@ -110,7 +126,7 @@ void TransformManager::setAccurateTranslationsEnabled(bool enable) noexcept {
|
||||
}
|
||||
|
||||
bool TransformManager::isAccurateTranslationsEnabled() const noexcept {
|
||||
return downcast(this)->isAccurateTranslationsEnabled();;
|
||||
return downcast(this)->isAccurateTranslationsEnabled();
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -23,70 +23,82 @@
|
||||
#include <utils/Log.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <math/mat4.h>
|
||||
|
||||
using namespace utils;
|
||||
using namespace filament::math;
|
||||
|
||||
namespace filament {
|
||||
|
||||
FCameraManager::FCameraManager(FEngine& engine) noexcept
|
||||
: mEngine(engine) {
|
||||
FCameraManager::FCameraManager(FEngine&) noexcept {
|
||||
}
|
||||
|
||||
FCameraManager::~FCameraManager() noexcept {
|
||||
}
|
||||
FCameraManager::~FCameraManager() noexcept = default;
|
||||
|
||||
void FCameraManager::terminate() noexcept {
|
||||
void FCameraManager::terminate(FEngine& engine) noexcept {
|
||||
auto& manager = mManager;
|
||||
if (!manager.empty()) {
|
||||
#ifndef NDEBUG
|
||||
slog.d << "cleaning up " << manager.getComponentCount()
|
||||
<< " leaked Camera components" << io::endl;
|
||||
#endif
|
||||
while (!manager.empty()) {
|
||||
Instance const ci = manager.end() - 1;
|
||||
destroy(manager.getEntity(ci));
|
||||
utils::Slice<Entity> const entities{ manager.getEntities(), manager.getComponentCount() };
|
||||
for (Entity const e : entities) {
|
||||
destroy(engine, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FCameraManager::gc(utils::EntityManager& em) noexcept {
|
||||
void FCameraManager::gc(FEngine& engine, utils::EntityManager& em) noexcept {
|
||||
auto& manager = mManager;
|
||||
manager.gc(em, 4, [this](Entity e) {
|
||||
destroy(e);
|
||||
manager.gc(em, [this, &engine](Entity e) {
|
||||
destroy(engine, e);
|
||||
});
|
||||
}
|
||||
|
||||
FCamera* FCameraManager::create(Entity entity) {
|
||||
FEngine& engine = mEngine;
|
||||
FCamera* FCameraManager::create(FEngine& engine, Entity entity) {
|
||||
auto& manager = mManager;
|
||||
|
||||
// if this entity already has Camera component, destroy it.
|
||||
if (UTILS_UNLIKELY(manager.hasComponent(entity))) {
|
||||
destroy(entity);
|
||||
destroy(engine, entity);
|
||||
}
|
||||
|
||||
// add the Camera component to the entity
|
||||
Instance const i = manager.addComponent(entity);
|
||||
|
||||
FCamera* camera = engine.getHeapAllocator().make<FCamera>(engine, entity);
|
||||
// For historical reasons, FCamera must not move. So the CameraManager stores a pointer.
|
||||
FCamera* const camera = engine.getHeapAllocator().make<FCamera>(engine, entity);
|
||||
manager.elementAt<CAMERA>(i) = camera;
|
||||
manager.elementAt<OWNS_TRANSFORM_COMPONENT>(i) = false;
|
||||
|
||||
// Make sure we have a transform component
|
||||
FTransformManager& transformManager = engine.getTransformManager();
|
||||
if (!transformManager.hasComponent(entity)) {
|
||||
transformManager.create(entity);
|
||||
FTransformManager& tcm = engine.getTransformManager();
|
||||
if (!tcm.hasComponent(entity)) {
|
||||
tcm.create(entity);
|
||||
manager.elementAt<OWNS_TRANSFORM_COMPONENT>(i) = true;
|
||||
}
|
||||
return camera;
|
||||
}
|
||||
|
||||
void FCameraManager::destroy(Entity e) noexcept {
|
||||
void FCameraManager::destroy(FEngine& engine, Entity e) noexcept {
|
||||
auto& manager = mManager;
|
||||
Instance const i = manager.getInstance(e);
|
||||
if (i) {
|
||||
FCamera* camera = manager.elementAt<CAMERA>(i);
|
||||
assert_invariant(camera);
|
||||
camera->terminate(mEngine);
|
||||
mEngine.getHeapAllocator().destroy(camera);
|
||||
manager.removeComponent(e);
|
||||
if (Instance const i = manager.getInstance(e) ; i) {
|
||||
// destroy the FCamera object
|
||||
bool const ownsTransformComponent = manager.elementAt<OWNS_TRANSFORM_COMPONENT>(i);
|
||||
|
||||
{ // scope for camera -- it's invalid after this scope.
|
||||
FCamera* const camera = manager.elementAt<CAMERA>(i);
|
||||
assert_invariant(camera);
|
||||
camera->terminate(engine);
|
||||
engine.getHeapAllocator().destroy(camera);
|
||||
|
||||
// Remove the camera component
|
||||
manager.removeComponent(e);
|
||||
}
|
||||
|
||||
// if we added the transform component, remove it.
|
||||
if (ownsTransformComponent) {
|
||||
engine.getTransformManager().destroy(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,9 +44,9 @@ public:
|
||||
~FCameraManager() noexcept;
|
||||
|
||||
// free-up all resources
|
||||
void terminate() noexcept;
|
||||
void terminate(FEngine& engine) noexcept;
|
||||
|
||||
void gc(utils::EntityManager& em) noexcept;
|
||||
void gc(FEngine& engine, utils::EntityManager& em) noexcept;
|
||||
|
||||
/*
|
||||
* Component Manager APIs
|
||||
@@ -57,32 +57,47 @@ public:
|
||||
}
|
||||
|
||||
Instance getInstance(utils::Entity e) const noexcept {
|
||||
return Instance(mManager.getInstance(e));
|
||||
return { mManager.getInstance(e) };
|
||||
}
|
||||
|
||||
size_t getComponentCount() const noexcept {
|
||||
return mManager.getComponentCount();
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return mManager.empty();
|
||||
}
|
||||
|
||||
utils::Entity getEntity(Instance i) const noexcept {
|
||||
return mManager.getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return mManager.getEntities();
|
||||
}
|
||||
|
||||
FCamera* getCamera(Instance i) noexcept {
|
||||
return mManager.elementAt<CAMERA>(i);
|
||||
}
|
||||
|
||||
FCamera* create(utils::Entity entity);
|
||||
FCamera* create(FEngine& engine, utils::Entity entity);
|
||||
|
||||
void destroy(utils::Entity e) noexcept;
|
||||
void destroy(FEngine& engine, utils::Entity e) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
CAMERA
|
||||
CAMERA,
|
||||
OWNS_TRANSFORM_COMPONENT
|
||||
};
|
||||
|
||||
using Base = utils::SingleInstanceComponentManager<FCamera *>;
|
||||
using Base = utils::SingleInstanceComponentManager<FCamera*, bool>;
|
||||
|
||||
struct CameraManagerImpl : public Base {
|
||||
using Base::gc;
|
||||
using Base::swap;
|
||||
using Base::hasComponent;
|
||||
} mManager;
|
||||
|
||||
FEngine& mEngine;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -227,7 +227,9 @@ void FLightManager::terminate() noexcept {
|
||||
}
|
||||
}
|
||||
void FLightManager::gc(utils::EntityManager& em) noexcept {
|
||||
mManager.gc(em);
|
||||
mManager.gc(em, [this](Entity e) {
|
||||
destroy(e);
|
||||
});
|
||||
}
|
||||
|
||||
void FLightManager::setShadowOptions(Instance i, ShadowOptions const& options) noexcept {
|
||||
|
||||
@@ -46,20 +46,32 @@ public:
|
||||
|
||||
void gc(utils::EntityManager& em) noexcept;
|
||||
|
||||
size_t getComponentCount() const noexcept {
|
||||
return mManager.getComponentCount();
|
||||
}
|
||||
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return mManager.getEntities();
|
||||
}
|
||||
/*
|
||||
* Component Manager APIs
|
||||
*/
|
||||
|
||||
bool hasComponent(utils::Entity e) const noexcept {
|
||||
return mManager.hasComponent(e);
|
||||
}
|
||||
|
||||
Instance getInstance(utils::Entity e) const noexcept {
|
||||
return mManager.getInstance(e);
|
||||
return { mManager.getInstance(e) };
|
||||
}
|
||||
|
||||
size_t getComponentCount() const noexcept {
|
||||
return mManager.getComponentCount();
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return mManager.empty();
|
||||
}
|
||||
|
||||
utils::Entity getEntity(Instance i) const noexcept {
|
||||
return mManager.getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return mManager.getEntities();
|
||||
}
|
||||
|
||||
void create(const FLightManager::Builder& builder, utils::Entity entity);
|
||||
|
||||
@@ -678,7 +678,9 @@ void FRenderableManager::terminate() noexcept {
|
||||
}
|
||||
|
||||
void FRenderableManager::gc(utils::EntityManager& em) noexcept {
|
||||
mManager.gc(em);
|
||||
mManager.gc(em, [this](Entity e) {
|
||||
destroy(e);
|
||||
});
|
||||
}
|
||||
|
||||
// This is basically a Renderable's destructor.
|
||||
|
||||
@@ -92,7 +92,23 @@ public:
|
||||
}
|
||||
|
||||
Instance getInstance(utils::Entity e) const noexcept {
|
||||
return mManager.getInstance(e);
|
||||
return { mManager.getInstance(e) };
|
||||
}
|
||||
|
||||
size_t getComponentCount() const noexcept {
|
||||
return mManager.getComponentCount();
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return mManager.empty();
|
||||
}
|
||||
|
||||
utils::Entity getEntity(Instance i) const noexcept {
|
||||
return mManager.getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return mManager.getEntities();
|
||||
}
|
||||
|
||||
void create(const RenderableManager::Builder& builder, utils::Entity entity);
|
||||
@@ -176,10 +192,6 @@ public:
|
||||
static_assert(sizeof(InstancesInfo) == 16);
|
||||
inline InstancesInfo getInstancesInfo(Instance instance) const noexcept;
|
||||
|
||||
utils::Entity getEntity(Instance instance) const noexcept {
|
||||
return mManager.getEntity(instance);
|
||||
}
|
||||
|
||||
inline size_t getLevelCount(Instance) const noexcept { return 1u; }
|
||||
size_t getPrimitiveCount(Instance instance, uint8_t level) const noexcept;
|
||||
void setMaterialInstanceAt(Instance instance, uint8_t level,
|
||||
|
||||
@@ -471,8 +471,7 @@ void FTransformManager::validateNode(UTILS_UNUSED_IN_RELEASE Instance i) noexcep
|
||||
}
|
||||
|
||||
void FTransformManager::gc(utils::EntityManager& em) noexcept {
|
||||
auto& manager = mManager;
|
||||
manager.gc(em, 4, [this](Entity e) {
|
||||
mManager.gc(em, [this](Entity e) {
|
||||
destroy(e);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,7 +50,23 @@ public:
|
||||
}
|
||||
|
||||
Instance getInstance(utils::Entity e) const noexcept {
|
||||
return Instance(mManager.getInstance(e));
|
||||
return { mManager.getInstance(e) };
|
||||
}
|
||||
|
||||
size_t getComponentCount() const noexcept {
|
||||
return mManager.getComponentCount();
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return mManager.empty();
|
||||
}
|
||||
|
||||
utils::Entity getEntity(Instance i) const noexcept {
|
||||
return mManager.getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return mManager.getEntities();
|
||||
}
|
||||
|
||||
void setAccurateTranslationsEnabled(bool enable) noexcept;
|
||||
@@ -103,7 +119,7 @@ public:
|
||||
|
||||
math::mat4 getTransformAccurate(Instance ci) const noexcept {
|
||||
math::mat4f const& local = mManager[ci].local;
|
||||
math::float3 localTranslationLo = mManager[ci].localTranslationLo;
|
||||
math::float3 const localTranslationLo = mManager[ci].localTranslationLo;
|
||||
math::mat4 r(local);
|
||||
r[3].xyz += localTranslationLo;
|
||||
return r;
|
||||
@@ -111,7 +127,7 @@ public:
|
||||
|
||||
math::mat4 getWorldTransformAccurate(Instance ci) const noexcept {
|
||||
math::mat4f const& world = mManager[ci].world;
|
||||
math::float3 worldTranslationLo = mManager[ci].worldTranslationLo;
|
||||
math::float3 const worldTranslationLo = mManager[ci].worldTranslationLo;
|
||||
math::mat4 r(world);
|
||||
r[3].xyz += worldTranslationLo;
|
||||
return r;
|
||||
|
||||
@@ -266,8 +266,8 @@ CameraInfo::CameraInfo(FCamera const& camera) noexcept {
|
||||
d = std::max(zn, camera.getFocusDistance());
|
||||
}
|
||||
|
||||
CameraInfo::CameraInfo(FCamera const& camera, math::mat4 const& inWorldTransform) noexcept {
|
||||
const mat4 modelMatrix{ inWorldTransform * camera.getModelMatrix() };
|
||||
CameraInfo::CameraInfo(FCamera const& camera, const math::mat4& worldOriginCamera) noexcept {
|
||||
const mat4 modelMatrix{ worldOriginCamera * camera.getModelMatrix() };
|
||||
for (uint8_t i = 0; i < CONFIG_STEREOSCOPIC_EYES; i++) {
|
||||
eyeProjection[i] = mat4f{ camera.getProjectionMatrix(i) };
|
||||
eyeFromView[i] = mat4f{ camera.getEyeFromViewMatrix(i) };
|
||||
@@ -275,7 +275,7 @@ CameraInfo::CameraInfo(FCamera const& camera, math::mat4 const& inWorldTransform
|
||||
cullingProjection = mat4f{ camera.getCullingProjectionMatrix() };
|
||||
model = mat4f{ modelMatrix };
|
||||
view = mat4f{ inverse(modelMatrix) };
|
||||
worldTransform = inWorldTransform;
|
||||
worldOrigin = worldOriginCamera;
|
||||
zn = (float)camera.getNear();
|
||||
zf = (float)camera.getCullingFar();
|
||||
ev100 = Exposure::ev100(camera);
|
||||
|
||||
@@ -223,7 +223,7 @@ private:
|
||||
struct CameraInfo {
|
||||
CameraInfo() noexcept {}
|
||||
explicit CameraInfo(FCamera const& camera) noexcept;
|
||||
CameraInfo(FCamera const& camera, math::mat4 const& inWorldTransform) noexcept;
|
||||
CameraInfo(FCamera const& camera, const math::mat4& worldOriginCamera) noexcept;
|
||||
|
||||
union {
|
||||
// projection matrix for drawing (infinite zfar)
|
||||
@@ -239,7 +239,7 @@ struct CameraInfo {
|
||||
math::mat4f model; // camera model matrix
|
||||
math::mat4f view; // camera view matrix (inverse(model))
|
||||
math::mat4f eyeFromView[CONFIG_STEREOSCOPIC_EYES]; // eye view matrix (only for stereoscopic)
|
||||
math::mat4 worldTransform; // world transform (already applied
|
||||
math::mat4 worldOrigin; // world origin transform (already applied
|
||||
// to model and view)
|
||||
math::float4 clipTransform{1, 1, 0, 0}; // clip-space transform, only for VERTEX_DOMAIN_DEVICE
|
||||
float zn{}; // distance (positive) to the near plane
|
||||
@@ -250,7 +250,7 @@ struct CameraInfo {
|
||||
float d{}; // focus distance [m]
|
||||
math::float3 const& getPosition() const noexcept { return model[3].xyz; }
|
||||
math::float3 getForwardVector() const noexcept { return normalize(-model[2].xyz); }
|
||||
math::mat4 getUserViewMatrix() const noexcept { return view * worldTransform; }
|
||||
math::mat4 getUserViewMatrix() const noexcept { return view * worldOrigin; }
|
||||
};
|
||||
|
||||
FILAMENT_DOWNCAST(Camera)
|
||||
|
||||
@@ -424,7 +424,7 @@ void FEngine::shutdown() {
|
||||
mDFG.terminate(*this); // free-up the DFG
|
||||
mRenderableManager.terminate(); // free-up all renderables
|
||||
mLightManager.terminate(); // free-up all lights
|
||||
mCameraManager.terminate(); // free-up all cameras
|
||||
mCameraManager.terminate(*this); // free-up all cameras
|
||||
|
||||
driver.destroyRenderPrimitive(mFullScreenTriangleRph);
|
||||
destroy(mFullScreenTriangleIb);
|
||||
@@ -537,7 +537,7 @@ void FEngine::gc() {
|
||||
mRenderableManager.gc(em);
|
||||
mLightManager.gc(em);
|
||||
mTransformManager.gc(em);
|
||||
mCameraManager.gc(em);
|
||||
mCameraManager.gc(*this, em);
|
||||
}
|
||||
|
||||
void FEngine::flush() {
|
||||
@@ -828,7 +828,7 @@ FSwapChain* FEngine::createSwapChain(uint32_t width, uint32_t height, uint64_t f
|
||||
|
||||
|
||||
FCamera* FEngine::createCamera(Entity entity) noexcept {
|
||||
return mCameraManager.create(entity);
|
||||
return mCameraManager.create(*this, entity);
|
||||
}
|
||||
|
||||
FCamera* FEngine::getCameraComponent(Entity entity) noexcept {
|
||||
@@ -837,7 +837,7 @@ FCamera* FEngine::getCameraComponent(Entity entity) noexcept {
|
||||
}
|
||||
|
||||
void FEngine::destroyCameraComponent(utils::Entity entity) noexcept {
|
||||
mCameraManager.destroy(entity);
|
||||
mCameraManager.destroy(*this, entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -1053,7 +1053,7 @@ void FEngine::destroy(Entity e) {
|
||||
mRenderableManager.destroy(e);
|
||||
mLightManager.destroy(e);
|
||||
mTransformManager.destroy(e);
|
||||
mCameraManager.destroy(e);
|
||||
mCameraManager.destroy(*this, e);
|
||||
}
|
||||
|
||||
bool FEngine::isValid(const FBufferObject* p) {
|
||||
|
||||
@@ -487,7 +487,7 @@ private:
|
||||
ResourceList<FRenderTarget> mRenderTargets{ "RenderTarget" };
|
||||
|
||||
// the fence list is accessed from multiple threads
|
||||
utils::SpinLock mFenceListLock;
|
||||
utils::Mutex mFenceListLock;
|
||||
ResourceList<FFence> mFences{"Fence"};
|
||||
|
||||
mutable uint32_t mMaterialId = 0;
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
#include <utils/Range.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <math/quat.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace filament::backend;
|
||||
@@ -54,7 +52,7 @@ FScene::~FScene() noexcept = default;
|
||||
|
||||
void FScene::prepare(utils::JobSystem& js,
|
||||
LinearAllocatorArena& allocator,
|
||||
mat4 const& worldTransform,
|
||||
const mat4& worldOriginTransform,
|
||||
bool shadowReceiversAreCasters) noexcept {
|
||||
// TODO: can we skip this in most cases? Since we rely on indices staying the same,
|
||||
// we could only skip, if nothing changed in the RCM.
|
||||
@@ -170,7 +168,7 @@ void FScene::prepare(utils::JobSystem& js,
|
||||
* Fill the SoA with the JobSystem
|
||||
*/
|
||||
|
||||
auto renderableWork = [first = renderableInstances.data(), &rcm, &tcm, &worldTransform,
|
||||
auto renderableWork = [first = renderableInstances.data(), &rcm, &tcm, &worldOriginTransform,
|
||||
&sceneData, shadowReceiversAreCasters](auto* p, auto c) {
|
||||
SYSTRACE_NAME("renderableWork");
|
||||
|
||||
@@ -178,12 +176,12 @@ void FScene::prepare(utils::JobSystem& js,
|
||||
auto [ri, ti] = p[i];
|
||||
|
||||
// this is where we go from double to float for our transforms
|
||||
const mat4f shaderWorldTransform{
|
||||
worldTransform * tcm.getWorldTransformAccurate(ti) };
|
||||
const bool reversedWindingOrder = det(shaderWorldTransform.upperLeft()) < 0;
|
||||
const mat4f worldTransform{
|
||||
worldOriginTransform * tcm.getWorldTransformAccurate(ti) };
|
||||
const bool reversedWindingOrder = det(worldTransform.upperLeft()) < 0;
|
||||
|
||||
// compute the world AABB so we can perform culling
|
||||
const Box worldAABB = rigidTransform(rcm.getAABB(ri), shaderWorldTransform);
|
||||
const Box worldAABB = rigidTransform(rcm.getAABB(ri), worldTransform);
|
||||
|
||||
auto visibility = rcm.getVisibility(ri);
|
||||
visibility.reversedWindingOrder = reversedWindingOrder;
|
||||
@@ -201,7 +199,7 @@ void FScene::prepare(utils::JobSystem& js,
|
||||
assert_invariant(index < sceneData.size());
|
||||
|
||||
sceneData.elementAt<RENDERABLE_INSTANCE>(index) = ri;
|
||||
sceneData.elementAt<WORLD_TRANSFORM>(index) = shaderWorldTransform;
|
||||
sceneData.elementAt<WORLD_TRANSFORM>(index) = worldTransform;
|
||||
sceneData.elementAt<VISIBILITY_STATE>(index) = visibility;
|
||||
sceneData.elementAt<SKINNING_BUFFER>(index) = rcm.getSkinningBufferInfo(ri);
|
||||
sceneData.elementAt<MORPHING_BUFFER>(index) = rcm.getMorphingBufferInfo(ri);
|
||||
@@ -218,20 +216,19 @@ void FScene::prepare(utils::JobSystem& js,
|
||||
}
|
||||
};
|
||||
|
||||
auto lightWork = [first = lightInstances.data(), &lcm, &tcm, &worldTransform,
|
||||
auto lightWork = [first = lightInstances.data(), &lcm, &tcm, &worldOriginTransform,
|
||||
&lightData](auto* p, auto c) {
|
||||
SYSTRACE_NAME("lightWork");
|
||||
for (size_t i = 0; i < c; i++) {
|
||||
auto [li, ti] = p[i];
|
||||
// this is where we go from double to float for our transforms
|
||||
mat4f const shaderWorldTransform{
|
||||
worldTransform * tcm.getWorldTransformAccurate(ti) };
|
||||
float4 const position = shaderWorldTransform * float4{ lcm.getLocalPosition(li), 1 };
|
||||
const mat4f worldTransform{ worldOriginTransform * tcm.getWorldTransformAccurate(ti) };
|
||||
const float4 position = worldTransform * float4{ lcm.getLocalPosition(li), 1 };
|
||||
float3 d = 0;
|
||||
if (!lcm.isPointLight(li) || lcm.isIESLight(li)) {
|
||||
d = lcm.getLocalDirection(li);
|
||||
// using mat3f::getTransformForNormals handles non-uniform scaling
|
||||
d = normalize(mat3f::getTransformForNormals(shaderWorldTransform.upperLeft()) * d);
|
||||
d = normalize(mat3f::getTransformForNormals(worldTransform.upperLeft()) * d);
|
||||
}
|
||||
size_t const index = DIRECTIONAL_LIGHTS_COUNT + std::distance(first, p) + i;
|
||||
assert_invariant(index < lightData.size());
|
||||
@@ -264,43 +261,14 @@ void FScene::prepare(utils::JobSystem& js,
|
||||
*/
|
||||
|
||||
if (auto [li, ti] = directionalLightInstances ; li) {
|
||||
// in the code below, we only transform directions, so the translation of the
|
||||
// world transform is irrelevant, and we don't need to use getWorldTransformAccurate()
|
||||
|
||||
FLightManager::ShadowParams const params = lcm.getShadowParams(li);
|
||||
float3 const localDirection = lcm.getLocalDirection(li);
|
||||
float3 const shadowLocalDirection = params.options.transform * localDirection;
|
||||
mat3 const worldDirectionTransform = tcm.getWorldTransformAccurate(ti).upperLeft();
|
||||
mat3 const shaderWorldTransform = worldTransform.upperLeft() * worldDirectionTransform;
|
||||
|
||||
// using mat3::getTransformForNormals handles non-uniform scaling
|
||||
// note: in the common case of the rigid-body transform, getTransformForNormals() returns
|
||||
// identity.
|
||||
mat3 const worlTransformNormals = mat3::getTransformForNormals(shaderWorldTransform);
|
||||
double3 const d = worlTransformNormals * localDirection;
|
||||
double3 const s = worlTransformNormals * shadowLocalDirection;
|
||||
|
||||
// We compute the reference point for snapping shadowmaps without applying the
|
||||
// rotation of `worldOriginTransform` on both sides, so that we don't have any instability
|
||||
// due to the limited precision of the "light space" matrix (even at double precision).
|
||||
|
||||
// getMv() Returns the world-to-lightspace transformation. See ShadowMap.cpp.
|
||||
auto getMv = [](double3 direction) -> mat3 {
|
||||
// We use the x-axis as the "up" reference so that the math is stable when the light
|
||||
// is pointing down, which is a common case for lights. See ShadowMap.cpp.
|
||||
return transpose(mat3::lookTo(direction, double3{ 1, 0, 0 }));
|
||||
};
|
||||
double3 const worldDirection =
|
||||
mat3::getTransformForNormals(worldDirectionTransform) * shadowLocalDirection;
|
||||
double3 const worldOrigin = transpose(worldTransform.upperLeft()) * worldTransform[3].xyz;
|
||||
mat3 const Mv = getMv(worldDirection);
|
||||
double2 const lsReferencePoint = (Mv * worldOrigin).xy;
|
||||
|
||||
const mat4f worldTransform{
|
||||
worldOriginTransform * tcm.getWorldTransformAccurate(ti) };
|
||||
// using mat3f::getTransformForNormals handles non-uniform scaling
|
||||
float3 d = lcm.getLocalDirection(li);
|
||||
d = normalize(mat3f::getTransformForNormals(worldTransform.upperLeft()) * d);
|
||||
constexpr float inf = std::numeric_limits<float>::infinity();
|
||||
lightData.elementAt<POSITION_RADIUS>(0) = float4{ 0, 0, 0, inf };
|
||||
lightData.elementAt<DIRECTION>(0) = normalize(d);
|
||||
lightData.elementAt<SHADOW_DIRECTION>(0) = normalize(s);
|
||||
lightData.elementAt<SHADOW_REF>(0) = lsReferencePoint;
|
||||
lightData.elementAt<DIRECTION>(0) = d;
|
||||
lightData.elementAt<LIGHT_INSTANCE>(0) = li;
|
||||
} else {
|
||||
lightData.elementAt<LIGHT_INSTANCE>(0) = 0;
|
||||
|
||||
@@ -55,7 +55,7 @@ class FSkybox;
|
||||
class FScene : public Scene {
|
||||
public:
|
||||
/*
|
||||
* Filaments-scope Public API
|
||||
* Filament-scope Public API
|
||||
*/
|
||||
|
||||
FSkybox* getSkybox() const noexcept { return mSkybox; }
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
void terminate(FEngine& engine);
|
||||
|
||||
void prepare(utils::JobSystem& js, LinearAllocatorArena& allocator,
|
||||
math::mat4 const& worldTransform, bool shadowReceiversAreCasters) noexcept;
|
||||
math::mat4 const& worldOriginTransform, bool shadowReceiversAreCasters) noexcept;
|
||||
|
||||
void prepareVisibleRenderables(utils::Range<uint32_t> visibleRenderables) noexcept;
|
||||
|
||||
@@ -162,8 +162,6 @@ public:
|
||||
enum {
|
||||
POSITION_RADIUS,
|
||||
DIRECTION,
|
||||
SHADOW_DIRECTION,
|
||||
SHADOW_REF,
|
||||
LIGHT_INSTANCE,
|
||||
VISIBILITY,
|
||||
SCREEN_SPACE_Z_RANGE,
|
||||
@@ -173,8 +171,6 @@ public:
|
||||
using LightSoa = utils::StructureOfArrays<
|
||||
math::float4,
|
||||
math::float3,
|
||||
math::float3,
|
||||
math::double2,
|
||||
FLightManager::Instance,
|
||||
Culler::result_type,
|
||||
math::float2,
|
||||
@@ -197,6 +193,7 @@ private:
|
||||
void addEntities(const utils::Entity* entities, size_t count);
|
||||
void remove(utils::Entity entity);
|
||||
void removeEntities(const utils::Entity* entities, size_t count);
|
||||
size_t getEntityCount() const noexcept { return mEntities.size(); }
|
||||
size_t getRenderableCount() const noexcept;
|
||||
size_t getLightCount() const noexcept;
|
||||
bool hasEntity(utils::Entity entity) const noexcept;
|
||||
|
||||
@@ -397,8 +397,8 @@ CameraInfo FView::computeCameraInfo(FEngine& engine) const noexcept {
|
||||
* The "world origin" is also used to keep the origin close to the camera position to
|
||||
* improve fp precision in the shader for large scenes.
|
||||
*/
|
||||
double3 translation;
|
||||
mat3 rotation;
|
||||
mat4 translation;
|
||||
mat4 rotation;
|
||||
|
||||
/*
|
||||
* Calculate all camera parameters needed to render this View for this frame.
|
||||
@@ -409,18 +409,16 @@ CameraInfo FView::computeCameraInfo(FEngine& engine) const noexcept {
|
||||
// view-space, which improves floating point precision in the shader by staying around
|
||||
// zero, where fp precision is highest. This also ensures that when the camera is placed
|
||||
// very far from the origin, objects are still rendered and lit properly.
|
||||
translation = -camera->getPosition();
|
||||
translation = mat4::translation( -camera->getPosition() );
|
||||
}
|
||||
|
||||
FIndirectLight const* const ibl = scene->getIndirectLight();
|
||||
if (ibl) {
|
||||
// the IBL transformation must be a rigid transform
|
||||
rotation = mat3{ transpose(scene->getIndirectLight()->getRotation()) };
|
||||
// it is important to orthogonalize the matrix when converting it to doubles, because
|
||||
// as float, it only has about a 1e-8 precision on the size of the basis vectors
|
||||
rotation = orthogonalize(rotation);
|
||||
rotation = mat4{ transpose(scene->getIndirectLight()->getRotation()) };
|
||||
}
|
||||
return { *camera, mat4{ rotation } * mat4::translation(translation) };
|
||||
|
||||
return { *camera, rotation * translation };
|
||||
}
|
||||
|
||||
void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena,
|
||||
@@ -448,7 +446,7 @@ void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena,
|
||||
// intent of the code, which is that we should only depend on CameraInfo here.
|
||||
// This is an extremely uncommon case.
|
||||
const mat4 projection = mCullingCamera->getCullingProjectionMatrix();
|
||||
const mat4 view = inverse(cameraInfo.worldTransform * mCullingCamera->getModelMatrix());
|
||||
const mat4 view = inverse(cameraInfo.worldOrigin * mCullingCamera->getModelMatrix());
|
||||
return Frustum{ mat4f{ projection * view }};
|
||||
}
|
||||
};
|
||||
@@ -461,9 +459,7 @@ void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena,
|
||||
* Gather all information needed to render this scene. Apply the world origin to all
|
||||
* objects in the scene.
|
||||
*/
|
||||
scene->prepare(js, arena.getAllocator(),
|
||||
cameraInfo.worldTransform,
|
||||
hasVSM());
|
||||
scene->prepare(js, arena.getAllocator(), cameraInfo.worldOrigin, hasVSM());
|
||||
|
||||
/*
|
||||
* Light culling: runs in parallel with Renderable culling (below)
|
||||
|
||||
@@ -702,8 +702,8 @@ TEST(FilamentTest, FroxelData) {
|
||||
LightManager::Instance instance = engine->getLightManager().getInstance(e);
|
||||
|
||||
FScene::LightSoa lights;
|
||||
lights.push_back({}, {}, {}, {}, {}, {}, {}, {}); // first one is always skipped
|
||||
lights.push_back(float4{ 0, 0, -5, 1 }, {}, {}, {}, instance, 1, {}, {});
|
||||
lights.push_back({}, {}, {}, {}, {}, {}); // first one is always skipped
|
||||
lights.push_back(float4{ 0, 0, -5, 1 }, {}, instance, 1, {}, {});
|
||||
|
||||
{
|
||||
froxelData.froxelizeLights(*engine, {}, lights);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.45.0"
|
||||
spec.version = "1.45.1"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.45.0/filament-v1.45.0-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.45.1/filament-v1.45.1-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -57,13 +57,15 @@ public:
|
||||
}
|
||||
|
||||
void destroy(utils::Entity e) noexcept {
|
||||
if (Instance ci = mManager.getInstance(e); ci) {
|
||||
if (Instance const ci = mManager.getInstance(e); ci) {
|
||||
mManager.removeComponent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void gc(utils::EntityManager& em) noexcept {
|
||||
mManager.gc(em);
|
||||
mManager.gc(em, [this](Entity e) {
|
||||
destroy(e);
|
||||
});
|
||||
}
|
||||
|
||||
void setMorphTargetNames(Instance ci, utils::FixedCapacityVector<CString> names) noexcept {
|
||||
|
||||
@@ -70,13 +70,15 @@ public:
|
||||
}
|
||||
|
||||
void destroy(utils::Entity e) noexcept {
|
||||
if (Instance ci = mManager.getInstance(e); ci) {
|
||||
if (Instance const ci = mManager.getInstance(e); ci) {
|
||||
mManager.removeComponent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void gc(utils::EntityManager& em) noexcept {
|
||||
mManager.gc(em);
|
||||
mManager.gc(em, [this](Entity e) {
|
||||
destroy(e);
|
||||
});
|
||||
}
|
||||
|
||||
void setTranslation(Instance ci, const float3& translation) noexcept {
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
/* compound assignment products by a scalar
|
||||
*/
|
||||
template<typename U>
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
constexpr QUATERNION<T>& operator*=(U v) {
|
||||
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
|
||||
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
constexpr QUATERNION<T>& operator/=(U v) {
|
||||
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
|
||||
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
|
||||
@@ -125,25 +125,25 @@ public:
|
||||
* q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w);
|
||||
*
|
||||
*/
|
||||
template<typename U>
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
friend inline constexpr
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(QUATERNION<T> q, U scalar) {
|
||||
// don't pass q by reference because we need a copy anyway
|
||||
return q *= scalar;
|
||||
return QUATERNION<arithmetic_result_t<T, U>>(q *= scalar);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
friend inline constexpr
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(T scalar, QUATERNION<U> q) {
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(U scalar, QUATERNION<T> q) {
|
||||
// don't pass q by reference because we need a copy anyway
|
||||
return q *= scalar;
|
||||
return QUATERNION<arithmetic_result_t<T, U>>(q *= scalar);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
friend inline constexpr
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator/(QUATERNION<T> q, U scalar) {
|
||||
// don't pass q by reference because we need a copy anyway
|
||||
return q /= scalar;
|
||||
return QUATERNION<arithmetic_result_t<T, U>>(q /= scalar);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -289,14 +289,6 @@ public:
|
||||
return matrix::cof(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a matrix representing the pose of a virtual camera looking towards -Z in its
|
||||
* local Y-up coordinate system. "up" defines where the Y axis of the camera's local coordinate
|
||||
* system is.
|
||||
*/
|
||||
template<typename A, typename B>
|
||||
static TMat33 lookTo(const TVec3<A>& direction, const TVec3<B>& up) noexcept;
|
||||
|
||||
/**
|
||||
* Packs the tangent frame represented by the specified matrix into a quaternion.
|
||||
* Reflection is preserved by encoding it as the sign of the w component in the
|
||||
@@ -414,29 +406,6 @@ constexpr TMat33<T>::TMat33(const TQuaternion<U>& q) noexcept : m_value{} {
|
||||
m_value[2] = col_type(xz + yw, yz - xw, 1 - xx - yy); // NOLINT
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T dot_tolerance() noexcept;
|
||||
|
||||
template<>
|
||||
constexpr float dot_tolerance<float>() noexcept { return 0.999f; }
|
||||
|
||||
template<>
|
||||
constexpr double dot_tolerance<double>() noexcept { return 0.9999; }
|
||||
|
||||
template<typename T>
|
||||
template<typename A, typename B>
|
||||
TMat33<T> TMat33<T>::lookTo(const TVec3<A>& direction, const TVec3<B>& up) noexcept {
|
||||
auto const z_axis = direction;
|
||||
auto norm_up = up;
|
||||
if (std::abs(dot(z_axis, norm_up)) > dot_tolerance< arithmetic_result_t<A, B> >()) {
|
||||
// Fix up vector if we're degenerate (looking straight up, basically)
|
||||
norm_up = { norm_up.z, norm_up.x, norm_up.y };
|
||||
}
|
||||
auto const x_axis = normalize(cross(z_axis, norm_up));
|
||||
auto const y_axis = cross(x_axis, z_axis);
|
||||
return { x_axis, y_axis, -z_axis };
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename T>
|
||||
constexpr TQuaternion<T> TMat33<T>::packTangentFrame(const TMat33<T>& m, size_t storageSize) noexcept {
|
||||
|
||||
@@ -285,9 +285,6 @@ public:
|
||||
template<typename A, typename B, typename C>
|
||||
static TMat44 lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up) noexcept;
|
||||
|
||||
template<typename A, typename B, typename C>
|
||||
static TMat44 lookTo(const TVec3<A>& direction, const TVec3<B>& position, const TVec3<C>& up) noexcept;
|
||||
|
||||
template<typename A>
|
||||
static constexpr TVec3<A> project(const TMat44& projectionMatrix, TVec3<A> vertice) noexcept{
|
||||
TVec4<A> r = projectionMatrix * TVec4<A>{ vertice, 1 };
|
||||
@@ -520,19 +517,19 @@ template<typename T>
|
||||
template<typename A, typename B, typename C>
|
||||
TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center,
|
||||
const TVec3<C>& up) noexcept {
|
||||
return lookTo(normalize(center - eye), eye, normalize(up));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename A, typename B, typename C>
|
||||
TMat44<T> TMat44<T>::lookTo(const TVec3<A>& direction, const TVec3<B>& position,
|
||||
const TVec3<C>& up) noexcept {
|
||||
auto r = TMat33<T>::lookTo(direction, up);
|
||||
return TMat44<T>{
|
||||
TVec4<T>{ r[0], 0 },
|
||||
TVec4<T>{ r[1], 0 },
|
||||
TVec4<T>{ r[2], 0 },
|
||||
TVec4<T>{ position, 1 } };
|
||||
TVec3<T> z_axis(normalize(center - eye));
|
||||
TVec3<T> norm_up(normalize(up));
|
||||
if (std::abs(dot(z_axis, norm_up)) > T(0.999)) {
|
||||
// Fix up vector if we're degenerate (looking straight up, basically)
|
||||
norm_up = { norm_up.z, norm_up.x, norm_up.y };
|
||||
}
|
||||
TVec3<T> x_axis(normalize(cross(z_axis, norm_up)));
|
||||
TVec3<T> y_axis(cross(x_axis, z_axis));
|
||||
return TMat44<T>(
|
||||
TVec4<T>(x_axis, 0),
|
||||
TVec4<T>(y_axis, 0),
|
||||
TVec4<T>(-z_axis, 0),
|
||||
TVec4<T>(eye, 1));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
@@ -32,71 +32,6 @@ class MatTest : public testing::Test {
|
||||
protected:
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// A macro to help with vector comparisons within floating point range.
|
||||
#define EXPECT_VEC_EQ(VEC1, VEC2) \
|
||||
do { \
|
||||
const decltype(VEC1) v1 = VEC1; \
|
||||
const decltype(VEC2) v2 = VEC2; \
|
||||
if (std::is_same<TypeParam,float>::value) { \
|
||||
for (int i = 0; i < v1.size(); ++i) { \
|
||||
EXPECT_FLOAT_EQ(v1[i], v2[i]); \
|
||||
} \
|
||||
} else if (std::is_same<TypeParam,double>::value) { \
|
||||
for (int i = 0; i < v1.size(); ++i) { \
|
||||
EXPECT_DOUBLE_EQ(v1[i], v2[i]); \
|
||||
} \
|
||||
} else { \
|
||||
for (int i = 0; i < v1.size(); ++i) { \
|
||||
EXPECT_EQ(v1[i], v2[i]); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// A macro to help with vector comparisons within a range.
|
||||
#define EXPECT_VEC_NEAR(VEC1, VEC2, eps) \
|
||||
do { \
|
||||
const decltype(VEC1) v1 = VEC1; \
|
||||
const decltype(VEC2) v2 = VEC2; \
|
||||
for (int i = 0; i < v1.size(); ++i) { \
|
||||
EXPECT_NEAR(v1[i], v2[i], eps); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// A macro to help with type comparisons within floating point range.
|
||||
#define ASSERT_TYPE_EQ(T1, T2) \
|
||||
do { \
|
||||
const decltype(T1) t1 = T1; \
|
||||
const decltype(T2) t2 = T2; \
|
||||
if (std::is_same<TypeParam,float>::value) { \
|
||||
ASSERT_FLOAT_EQ(t1, t2); \
|
||||
} else if (std::is_same<TypeParam,double>::value) { \
|
||||
ASSERT_DOUBLE_EQ(t1, t2); \
|
||||
} else { \
|
||||
ASSERT_EQ(t1, t2); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
|
||||
TEST_F(MatTest, LargeFloatRotationsWithOrthogonalization) {
|
||||
double3 const t = { 2304097.1410110965, -4688442.9915525438, -3639452.5611694567 };
|
||||
mat4 const T = mat4::translation(t);
|
||||
for (float d = 0; d < 90; d = d + 1.0) {
|
||||
mat3f const R = mat3f::rotation(d * f::DEG_TO_RAD, float3{ 0, 1, 0 });
|
||||
mat3 RR = orthogonalize(mat3{ R });
|
||||
ASSERT_NEAR(dot(RR[0], RR[0]), 1.0, 1e-12);
|
||||
ASSERT_NEAR(dot(RR[1], RR[1]), 1.0, 1e-12);
|
||||
ASSERT_NEAR(dot(RR[2], RR[2]), 1.0, 1e-12);
|
||||
mat4 M = mat4{ RR } * T;
|
||||
double3 const t2 = transpose(M.upperLeft()) * M[3].xyz;
|
||||
EXPECT_VEC_NEAR(t, t2, 0.0001); // 0.1mm
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MatTest, ConstexprMat2) {
|
||||
constexpr float a = F_PI;
|
||||
constexpr mat2f M;
|
||||
@@ -617,6 +552,53 @@ TYPED_TEST(MatTestT, Inverse2) {
|
||||
TEST_MATRIX_INVERSE(m4, 20.0 * std::numeric_limits<TypeParam>::epsilon());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// A macro to help with vector comparisons within floating point range.
|
||||
#define EXPECT_VEC_EQ(VEC1, VEC2) \
|
||||
do { \
|
||||
const decltype(VEC1) v1 = VEC1; \
|
||||
const decltype(VEC2) v2 = VEC2; \
|
||||
if (std::is_same<TypeParam,float>::value) { \
|
||||
for (int i = 0; i < v1.size(); ++i) { \
|
||||
EXPECT_FLOAT_EQ(v1[i], v2[i]); \
|
||||
} \
|
||||
} else if (std::is_same<TypeParam,double>::value) { \
|
||||
for (int i = 0; i < v1.size(); ++i) { \
|
||||
EXPECT_DOUBLE_EQ(v1[i], v2[i]); \
|
||||
} \
|
||||
} else { \
|
||||
for (int i = 0; i < v1.size(); ++i) { \
|
||||
EXPECT_EQ(v1[i], v2[i]); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// A macro to help with vector comparisons within a range.
|
||||
#define EXPECT_VEC_NEAR(VEC1, VEC2, eps) \
|
||||
do { \
|
||||
const decltype(VEC1) v1 = VEC1; \
|
||||
const decltype(VEC2) v2 = VEC2; \
|
||||
for (int i = 0; i < v1.size(); ++i) { \
|
||||
EXPECT_NEAR(v1[i], v2[i], eps); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// A macro to help with type comparisons within floating point range.
|
||||
#define ASSERT_TYPE_EQ(T1, T2) \
|
||||
do { \
|
||||
const decltype(T1) t1 = T1; \
|
||||
const decltype(T2) t2 = T2; \
|
||||
if (std::is_same<TypeParam,float>::value) { \
|
||||
ASSERT_FLOAT_EQ(t1, t2); \
|
||||
} else if (std::is_same<TypeParam,double>::value) { \
|
||||
ASSERT_DOUBLE_EQ(t1, t2); \
|
||||
} else { \
|
||||
ASSERT_EQ(t1, t2); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
TYPED_TEST(MatTestT, NormalsNegativeScale) {
|
||||
typedef filament::math::details::TMat33<TypeParam> M33T;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <math.h>
|
||||
#include <random>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -324,3 +325,103 @@ TEST_F(QuatTest, NaN) {
|
||||
EXPECT_NEAR(qs[2], 0.5, 0.1);
|
||||
EXPECT_NEAR(qs[3], 0.5, 0.1);
|
||||
}
|
||||
|
||||
TEST_F(QuatTest, Conversions) {
|
||||
quat qd;
|
||||
quatf qf;
|
||||
float3 vf;
|
||||
double3 vd;
|
||||
double d = 0.0;
|
||||
float f = 0.0f;
|
||||
|
||||
static_assert(std::is_same<details::arithmetic_result_t<float, float>, float>::value);
|
||||
static_assert(std::is_same<details::arithmetic_result_t<float, double>, double>::value);
|
||||
static_assert(std::is_same<details::arithmetic_result_t<double, float>, double>::value);
|
||||
static_assert(std::is_same<details::arithmetic_result_t<double, double>, double>::value);
|
||||
|
||||
{
|
||||
auto r1 = qd * d;
|
||||
auto r2 = qd * f;
|
||||
auto r3 = qf * d;
|
||||
auto r4 = qf * f;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = qd / d;
|
||||
auto r2 = qd / f;
|
||||
auto r3 = qf / d;
|
||||
auto r4 = qf / f;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = d * qd;
|
||||
auto r2 = f * qd;
|
||||
auto r3 = d * qf;
|
||||
auto r4 = f * qf;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = qd * vd;
|
||||
auto r2 = qf * vd;
|
||||
auto r3 = qd * vf;
|
||||
auto r4 = qf * vf;
|
||||
static_assert(std::is_same<decltype(r1), double3>::value);
|
||||
static_assert(std::is_same<decltype(r2), double3>::value);
|
||||
static_assert(std::is_same<decltype(r3), double3>::value);
|
||||
static_assert(std::is_same<decltype(r4), float3>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = qd * qd;
|
||||
auto r2 = qf * qd;
|
||||
auto r3 = qd * qf;
|
||||
auto r4 = qf * qf;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = dot(qd, qd);
|
||||
auto r2 = dot(qf, qd);
|
||||
auto r3 = dot(qd, qf);
|
||||
auto r4 = dot(qf, qf);
|
||||
static_assert(std::is_same<decltype(r1), double>::value);
|
||||
static_assert(std::is_same<decltype(r2), double>::value);
|
||||
static_assert(std::is_same<decltype(r3), double>::value);
|
||||
static_assert(std::is_same<decltype(r4), float>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = cross(qd, qd);
|
||||
auto r2 = cross(qf, qd);
|
||||
auto r3 = cross(qd, qf);
|
||||
auto r4 = cross(qf, qf);
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename L, typename R, typename = void>
|
||||
struct has_divide_assign : std::false_type {};
|
||||
|
||||
template <typename L, typename R>
|
||||
struct has_divide_assign<L, R,
|
||||
decltype(std::declval<L&>() /= std::declval<R>(), void())> : std::true_type {};
|
||||
|
||||
// Static assertions to validate the availability of the /= operator for specific type
|
||||
// combinations. The first static_assert checks that the quat does not have a /= operator with Foo.
|
||||
// This ensures that quat does not provide an inappropriate overload that could be erroneously
|
||||
// selected.
|
||||
struct Foo {};
|
||||
static_assert(!has_divide_assign<quat, Foo>::value);
|
||||
static_assert(has_divide_assign<quat, float>::value);
|
||||
|
||||
@@ -44,23 +44,25 @@ public:
|
||||
public:
|
||||
virtual void onEntitiesDestroyed(size_t n, Entity const* entities) noexcept = 0;
|
||||
protected:
|
||||
~Listener() noexcept;
|
||||
virtual ~Listener() noexcept;
|
||||
};
|
||||
|
||||
|
||||
// maximum number of entities that can exist at the same time
|
||||
static size_t getMaxEntityCount() noexcept {
|
||||
// because index 0 is reserved, we only have 2^GENERATION_SHIFT - 1 valid indices
|
||||
return RAW_INDEX_COUNT - 1;
|
||||
}
|
||||
|
||||
// create n entities. Thread safe.
|
||||
// number of active Entities
|
||||
size_t getEntityCount() const noexcept;
|
||||
|
||||
// Create n entities. Thread safe.
|
||||
void create(size_t n, Entity* entities);
|
||||
|
||||
// destroys n entities. Thread safe.
|
||||
void destroy(size_t n, Entity* entities) noexcept;
|
||||
|
||||
// create a new Entity. Thread safe.
|
||||
// Create a new Entity. Thread safe.
|
||||
// Return Entity.isNull() if the entity cannot be allocated.
|
||||
Entity create() {
|
||||
Entity e;
|
||||
@@ -68,20 +70,20 @@ public:
|
||||
return e;
|
||||
}
|
||||
|
||||
// destroys an Entity. Thread safe.
|
||||
// Destroys an Entity. Thread safe.
|
||||
void destroy(Entity e) noexcept {
|
||||
destroy(1, &e);
|
||||
}
|
||||
|
||||
// return whether the given Entity has been destroyed (false) or not (true).
|
||||
// Return whether the given Entity has been destroyed (false) or not (true).
|
||||
// Thread safe.
|
||||
bool isAlive(Entity e) const noexcept {
|
||||
assert(getIndex(e) < RAW_INDEX_COUNT);
|
||||
return (!e.isNull()) && (getGeneration(e) == mGens[getIndex(e)]);
|
||||
}
|
||||
|
||||
// registers a listener to be called when an entity is destroyed. thread safe.
|
||||
// if the listener is already register, this method has no effect.
|
||||
// Registers a listener to be called when an entity is destroyed. Thread safe.
|
||||
// If the listener is already registered, this method has no effect.
|
||||
void registerListener(Listener* l) noexcept;
|
||||
|
||||
// unregisters a listener.
|
||||
@@ -94,6 +96,7 @@ public:
|
||||
uint8_t getGenerationForIndex(size_t index) const noexcept {
|
||||
return mGens[index];
|
||||
}
|
||||
|
||||
// singleton, can't be copied
|
||||
EntityManager(const EntityManager& rhs) = delete;
|
||||
EntityManager& operator=(const EntityManager& rhs) = delete;
|
||||
|
||||
@@ -48,7 +48,7 @@ class EntityManager;
|
||||
* printf("%s\n", names->getName(names->getInstance(myEntity));
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
class UTILS_PUBLIC NameComponentManager : public SingleInstanceComponentManager<utils::CString> {
|
||||
class UTILS_PUBLIC NameComponentManager : private SingleInstanceComponentManager<utils::CString> {
|
||||
public:
|
||||
using Instance = EntityInstance<NameComponentManager>;
|
||||
|
||||
@@ -75,15 +75,6 @@ public:
|
||||
return { SingleInstanceComponentManager::getInstance(e) };
|
||||
}
|
||||
|
||||
/*! \cond PRIVATE */
|
||||
// these are implemented in SingleInstanceComponentManager<>, but we need to
|
||||
// reimplement them in each manager, to ensure they are generated in an implementation file
|
||||
// for backward binary compatibility reasons.
|
||||
size_t getComponentCount() const noexcept;
|
||||
Entity const* getEntities() const noexcept;
|
||||
void gc(const EntityManager& em, size_t ratio = 4) noexcept;
|
||||
/*! \endcond */
|
||||
|
||||
/**
|
||||
* Adds a name component to the given entity if it doesn't already exist.
|
||||
*/
|
||||
@@ -105,6 +96,12 @@ public:
|
||||
* @return pointer to the copy that was made during setName()
|
||||
*/
|
||||
const char* getName(Instance instance) const noexcept;
|
||||
|
||||
void gc(EntityManager& em) noexcept {
|
||||
SingleInstanceComponentManager<utils::CString>::gc(em, [this](Entity e) {
|
||||
removeComponent(e);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
return pos != map.end() ? pos->second : 0;
|
||||
}
|
||||
|
||||
// returns the number of components (i.e. size of each arrays)
|
||||
// Returns the number of components (i.e. size of each array)
|
||||
size_t getComponentCount() const noexcept {
|
||||
// The array as an extra dummy component at index 0, so the visible count is 1 less.
|
||||
return mData.size() - 1;
|
||||
@@ -108,11 +108,8 @@ public:
|
||||
return getComponentCount() == 0;
|
||||
}
|
||||
|
||||
// returns a pointer to the Entity array. This is basically the list
|
||||
// of entities this component manager handles.
|
||||
// The pointer becomes invalid when adding or removing a component.
|
||||
Entity const* getEntities() const noexcept {
|
||||
return begin<ENTITY_INDEX>();
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return data<ENTITY_INDEX>() + 1;
|
||||
}
|
||||
|
||||
Entity getEntity(Instance i) const noexcept {
|
||||
@@ -128,14 +125,6 @@ public:
|
||||
// This invalidates all pointers components.
|
||||
inline Instance removeComponent(Entity e);
|
||||
|
||||
// trigger one round of garbage collection. this is intended to be called on a regular
|
||||
// basis. This gc gives up after it cannot randomly free 'ratio' component in a row.
|
||||
void gc(const EntityManager& em, size_t ratio = 4) noexcept {
|
||||
gc(em, ratio, [this](Entity e) {
|
||||
removeComponent(e);
|
||||
});
|
||||
}
|
||||
|
||||
// return the first instance
|
||||
Instance begin() const noexcept { return 1u; }
|
||||
|
||||
@@ -234,24 +223,33 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
template<typename REMOVE>
|
||||
void gc(const EntityManager& em,
|
||||
REMOVE&& removeComponent) noexcept {
|
||||
gc(em, 4, std::forward<REMOVE>(removeComponent));
|
||||
}
|
||||
|
||||
template<typename REMOVE>
|
||||
void gc(const EntityManager& em, size_t ratio,
|
||||
REMOVE removeComponent) noexcept {
|
||||
Entity const* entities = getEntities();
|
||||
REMOVE&& removeComponent) noexcept {
|
||||
Entity const* const pEntities = begin<ENTITY_INDEX>();
|
||||
size_t count = getComponentCount();
|
||||
size_t aliveInARow = 0;
|
||||
default_random_engine& rng = mRng;
|
||||
UTILS_NOUNROLL
|
||||
while (count && aliveInARow < ratio) {
|
||||
assert_invariant(count == getComponentCount());
|
||||
// note: using the modulo favorizes lower number
|
||||
size_t i = rng() % count;
|
||||
if (UTILS_LIKELY(em.isAlive(entities[i]))) {
|
||||
size_t const i = rng() % count;
|
||||
Entity const entity = pEntities[i];
|
||||
assert_invariant(entity);
|
||||
if (UTILS_LIKELY(em.isAlive(entity))) {
|
||||
++aliveInARow;
|
||||
continue;
|
||||
}
|
||||
removeComponent(entity);
|
||||
aliveInARow = 0;
|
||||
count--;
|
||||
removeComponent(entities[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
namespace utils {
|
||||
|
||||
EntityManager::Listener::~Listener() noexcept = default;
|
||||
|
||||
EntityManager::EntityManager()
|
||||
: mGens(new uint8_t[RAW_INDEX_COUNT]) {
|
||||
// initialize all the generations to 0
|
||||
@@ -32,8 +34,6 @@ EntityManager::~EntityManager() {
|
||||
delete [] mGens;
|
||||
}
|
||||
|
||||
EntityManager::Listener::~Listener() noexcept = default;
|
||||
|
||||
EntityManager& EntityManager::get() noexcept {
|
||||
// note: we leak the EntityManager because it's more important that it survives everything else
|
||||
// the leak is really not a problem because the process is terminating anyway.
|
||||
@@ -57,6 +57,10 @@ void EntityManager::unregisterListener(EntityManager::Listener* l) noexcept {
|
||||
static_cast<EntityManagerImpl *>(this)->unregisterListener(l);
|
||||
}
|
||||
|
||||
size_t EntityManager::getEntityCount() const noexcept {
|
||||
return static_cast<EntityManagerImpl const *>(this)->getEntityCount();
|
||||
}
|
||||
|
||||
#if FILAMENT_UTILS_TRACK_ENTITIES
|
||||
std::vector<Entity> EntityManager::getActiveEntities() const {
|
||||
return static_cast<EntityManagerImpl const *>(this)->getActiveEntities();
|
||||
|
||||
@@ -48,6 +48,16 @@ public:
|
||||
using EntityManager::create;
|
||||
using EntityManager::destroy;
|
||||
|
||||
UTILS_NOINLINE
|
||||
size_t getEntityCount() const noexcept {
|
||||
std::lock_guard<Mutex> const lock(mFreeListLock);
|
||||
if (mCurrentIndex < RAW_INDEX_COUNT) {
|
||||
return (mCurrentIndex - 1) - mFreeList.size();
|
||||
} else {
|
||||
return getMaxEntityCount() - mFreeList.size();
|
||||
}
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
void create(size_t n, Entity* entities) {
|
||||
Entity::Type index{};
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace utils {
|
||||
|
||||
static constexpr size_t NAME = 0;
|
||||
|
||||
NameComponentManager::NameComponentManager(EntityManager& em) {
|
||||
NameComponentManager::NameComponentManager(EntityManager&) {
|
||||
}
|
||||
|
||||
NameComponentManager::~NameComponentManager() = default;
|
||||
@@ -36,14 +36,6 @@ const char* NameComponentManager::getName(Instance instance) const noexcept {
|
||||
return elementAt<NAME>(instance).c_str();
|
||||
}
|
||||
|
||||
size_t NameComponentManager::getComponentCount() const noexcept {
|
||||
return SingleInstanceComponentManager::getComponentCount();
|
||||
}
|
||||
|
||||
Entity const* NameComponentManager::getEntities() const noexcept {
|
||||
return SingleInstanceComponentManager::getEntities();
|
||||
}
|
||||
|
||||
void NameComponentManager::addComponent(Entity e) {
|
||||
SingleInstanceComponentManager::addComponent(e);
|
||||
}
|
||||
@@ -52,8 +44,4 @@ void NameComponentManager::removeComponent(Entity e) {
|
||||
SingleInstanceComponentManager::removeComponent(e);
|
||||
}
|
||||
|
||||
void NameComponentManager::gc(const EntityManager& em, size_t ratio) noexcept {
|
||||
SingleInstanceComponentManager::gc(em, ratio);
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
@@ -612,8 +612,10 @@ void applySettings(Engine* engine, const LightSettings& settings, IndirectLight*
|
||||
}
|
||||
for (size_t i = 0; i < sceneLightCount; i++) {
|
||||
auto const li = lm->getInstance(sceneLights[i]);
|
||||
lm->setShadowCaster(li, settings.enableShadows);
|
||||
lm->setShadowOptions(li, settings.shadowOptions);
|
||||
if (li) {
|
||||
lm->setShadowCaster(li, settings.enableShadows);
|
||||
lm->setShadowOptions(li, settings.shadowOptions);
|
||||
}
|
||||
}
|
||||
view->setSoftShadowOptions(settings.softShadowOptions);
|
||||
}
|
||||
|
||||
@@ -1045,7 +1045,7 @@ void ViewerGui::updateUserInterface() {
|
||||
|
||||
std::vector<std::string> names;
|
||||
names.reserve(cameraCount + 1);
|
||||
names.push_back("Free camera");
|
||||
names.emplace_back("Free camera");
|
||||
int c = 0;
|
||||
for (size_t i = 0; i < cameraCount; i++) {
|
||||
const char* n = mAsset->getName(cameras[i]);
|
||||
@@ -1060,8 +1060,8 @@ void ViewerGui::updateUserInterface() {
|
||||
|
||||
std::vector<const char*> cstrings;
|
||||
cstrings.reserve(names.size());
|
||||
for (size_t i = 0; i < names.size(); i++) {
|
||||
cstrings.push_back(names[i].c_str());
|
||||
for (const auto & name : names) {
|
||||
cstrings.push_back(name.c_str());
|
||||
}
|
||||
|
||||
ImGui::ListBox("Cameras", &mCurrentCamera, cstrings.data(), cstrings.size());
|
||||
@@ -1083,8 +1083,16 @@ void ViewerGui::updateUserInterface() {
|
||||
// At this point, all View settings have been modified,
|
||||
// so we can now push them into the Filament View.
|
||||
applySettings(mEngine, mSettings.view, mView);
|
||||
|
||||
auto lights = utils::FixedCapacityVector<utils::Entity>::with_capacity(mScene->getEntityCount());
|
||||
mScene->forEach([&](utils::Entity entity) {
|
||||
if (lm.hasComponent(entity)) {
|
||||
lights.push_back(entity);
|
||||
}
|
||||
});
|
||||
|
||||
applySettings(mEngine, mSettings.lighting, mIndirectLight, mSunlight,
|
||||
lm.getEntities(), lm.getComponentCount(), &lm, mScene, mView);
|
||||
lights.data(), lights.size(), &lm, mScene, mView);
|
||||
|
||||
// TODO(prideout): add support for hierarchy, animation and variant selection in remote mode. To
|
||||
// support these features, we will need to send a message (list of strings) from DebugServer to
|
||||
|
||||
@@ -101,7 +101,7 @@ struct App {
|
||||
|
||||
bool actualSize = false;
|
||||
bool originIsFarAway = false;
|
||||
float originDistance = 1.0f;
|
||||
float originDistance = 6378137; // Earth's radius in [m]
|
||||
|
||||
struct Scene {
|
||||
Entity groundPlane;
|
||||
@@ -762,7 +762,7 @@ int main(int argc, char** argv) {
|
||||
ImGui::Checkbox("Camera at origin",
|
||||
debug.getPropertyAddress<bool>("d.view.camera_at_origin"));
|
||||
ImGui::Checkbox("Far Origin", &app.originIsFarAway);
|
||||
ImGui::SliderFloat("Origin", &app.originDistance, 0, 1);
|
||||
ImGui::SliderFloat("Origin", &app.originDistance, 0, 10000000);
|
||||
ImGui::Checkbox("Far uses shadow casters",
|
||||
debug.getPropertyAddress<bool>("d.shadowmap.far_uses_shadowcasters"));
|
||||
ImGui::Checkbox("Focus shadow casters",
|
||||
@@ -981,12 +981,7 @@ int main(int argc, char** argv) {
|
||||
tcm.setParent(tcm.getInstance(camera.getEntity()), root);
|
||||
tcm.setParent(tcm.getInstance(app.asset->getRoot()), root);
|
||||
tcm.setParent(tcm.getInstance(view->getFogEntity()), root);
|
||||
|
||||
// these values represent a point somewhere on Earth's surface
|
||||
float const d = app.originIsFarAway ? app.originDistance : 0.0f;
|
||||
// tcm.setTransform(root, mat4::translation(double3{ 67.0, -6366759.0, -21552.0 } * d));
|
||||
tcm.setTransform(root, mat4::translation(
|
||||
double3{ 2304097.1410110965, -4688442.9915525438, -3639452.5611694567 } * d));
|
||||
tcm.setTransform(root, mat4f::translation(float3{ app.originIsFarAway ? app.originDistance : 0.0f }));
|
||||
|
||||
// Check if color grading has changed.
|
||||
ColorGradingSettings const& options = app.viewer->getSettings().view.colorGrading;
|
||||
|
||||
@@ -688,6 +688,7 @@ class_<Scene>("Scene")
|
||||
.function("getSkybox", &Scene::getSkybox, allow_raw_pointers())
|
||||
.function("setIndirectLight", &Scene::setIndirectLight, allow_raw_pointers())
|
||||
.function("getIndirectLight", &Scene::getIndirectLight, allow_raw_pointers())
|
||||
.function("getEntityCount", &Scene::getEntityCount)
|
||||
.function("getRenderableCount", &Scene::getRenderableCount)
|
||||
.function("getLightCount", &Scene::getLightCount);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.45.0",
|
||||
"version": "1.45.1",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user