You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-05-14 20:20:06 +00:00
Compare commits
211 Commits
3.2.0
...
5.0.0-prev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b068238e0a | ||
|
|
42fb0ecf23 | ||
|
|
79635e81d7 | ||
|
|
f388eb45ec | ||
|
|
f08809772a | ||
|
|
f96604ffc9 | ||
|
|
beac3b8048 | ||
|
|
a00bcd8a35 | ||
|
|
1f72048ef5 | ||
|
|
65f7555482 | ||
|
|
433f828ad9 | ||
|
|
1b8f0aac4a | ||
|
|
70271ae5e9 | ||
|
|
c3540a056c | ||
|
|
0cf4ae88c5 | ||
|
|
e579f524ba | ||
|
|
23dd7b5987 | ||
|
|
f476898b46 | ||
|
|
4e91b6f69b | ||
|
|
1bf669e09f | ||
|
|
54be6bf588 | ||
|
|
72f5f9441b | ||
|
|
acebfb27f6 | ||
|
|
a3e725fd5a | ||
|
|
e0c8f6ade8 | ||
|
|
612015f7cf | ||
|
|
09c2c95f3b | ||
|
|
3454273095 | ||
|
|
e82b35466b | ||
|
|
50ba446cff | ||
|
|
d4ffadf599 | ||
|
|
4a940d8e31 | ||
|
|
6d8dee0b06 | ||
|
|
67b384a1fe | ||
|
|
990baacdf9 | ||
|
|
f73a6777c4 | ||
|
|
65da5d35f5 | ||
|
|
25a9cdb400 | ||
|
|
c6b2950a75 | ||
|
|
841e449f78 | ||
|
|
9d04e41cde | ||
|
|
f1e672470c | ||
|
|
9d1b6a81ee | ||
|
|
e32077fb0d | ||
|
|
293dc43db7 | ||
|
|
2b5166dcd9 | ||
|
|
ee780c4996 | ||
|
|
e840631fb3 | ||
|
|
a5fdfce554 | ||
|
|
8028b2a770 | ||
|
|
b45dc77312 | ||
|
|
5dab4f21c7 | ||
|
|
f17ecafae7 | ||
|
|
5892df1ce1 | ||
|
|
f0fb205212 | ||
|
|
70e917107d | ||
|
|
eaae94ce00 | ||
|
|
7430c39f52 | ||
|
|
5fc44b82bc | ||
|
|
128990acc6 | ||
|
|
4790db6b93 | ||
|
|
32b93d3eeb | ||
|
|
86de8b6e03 | ||
|
|
b80c3e6c9f | ||
|
|
6a1fef4150 | ||
|
|
3184ba94ae | ||
|
|
6126af9f37 | ||
|
|
c6b816c312 | ||
|
|
5d5eb34590 | ||
|
|
5c3232faf3 | ||
|
|
ac58475539 | ||
|
|
5607dc4eed | ||
|
|
4e4b9eb2a7 | ||
|
|
3fac6e4773 | ||
|
|
45c56bbd85 | ||
|
|
2b8d3b1385 | ||
|
|
c710787b5b | ||
|
|
107f901fe3 | ||
|
|
447996ce0f | ||
|
|
73f6dad0f3 | ||
|
|
3c11209f17 | ||
|
|
3f2f12d2cf | ||
|
|
b9643b98ff | ||
|
|
b36a1571b3 | ||
|
|
c42f8c8ab0 | ||
|
|
9b2e5c1d10 | ||
|
|
821f08ff5c | ||
|
|
28d8698597 | ||
|
|
db28f171f7 | ||
|
|
410304125f | ||
|
|
67eff61073 | ||
|
|
4851a1880e | ||
|
|
2fe0bde422 | ||
|
|
c2119c171a | ||
|
|
3df190382a | ||
|
|
35325c8899 | ||
|
|
903f702d7b | ||
|
|
e93051603e | ||
|
|
e4998365c9 | ||
|
|
68d9925a16 | ||
|
|
392ab6dd76 | ||
|
|
f75fcce0da | ||
|
|
fb31db47f2 | ||
|
|
425aad0cba | ||
|
|
8b4ca1add5 | ||
|
|
b308b26833 | ||
|
|
e67e9482e2 | ||
|
|
723a04d0cf | ||
|
|
52f2ef1f24 | ||
|
|
e92b514624 | ||
|
|
a4bcf93022 | ||
|
|
a499f0c046 | ||
|
|
447c83dbbc | ||
|
|
bdeeabbbe1 | ||
|
|
5e6da2e158 | ||
|
|
f60d6dfe60 | ||
|
|
c795d24003 | ||
|
|
9e2dbe7758 | ||
|
|
4edcef1bbf | ||
|
|
a11d2d01ce | ||
|
|
550d0c43be | ||
|
|
c1538a8399 | ||
|
|
f97e6195e6 | ||
|
|
7eb41124db | ||
|
|
65c60000c2 | ||
|
|
fa2f867bca | ||
|
|
b2b2b0f767 | ||
|
|
fb7f308f09 | ||
|
|
8034228713 | ||
|
|
f526671826 | ||
|
|
81dacb1efe | ||
|
|
48d1994f5f | ||
|
|
f9901a0255 | ||
|
|
3b0f6985f6 | ||
|
|
1879ac8c53 | ||
|
|
e651039032 | ||
|
|
1d5c87463a | ||
|
|
cd8e0372b6 | ||
|
|
e1715afbab | ||
|
|
2f51bff791 | ||
|
|
59221d5821 | ||
|
|
4fe9a3200d | ||
|
|
8c959b257c | ||
|
|
6c50cf85f3 | ||
|
|
52ae87f301 | ||
|
|
845365ee27 | ||
|
|
8e1b4eb086 | ||
|
|
97ea668294 | ||
|
|
6b11e7c588 | ||
|
|
d9e7eb9732 | ||
|
|
386170cbf6 | ||
|
|
37d0c4b711 | ||
|
|
4fa43eda4b | ||
|
|
9afeebf672 | ||
|
|
d8e96e69a6 | ||
|
|
01459b06b8 | ||
|
|
7b21c500ef | ||
|
|
aa0d56f9fa | ||
|
|
c6644a2132 | ||
|
|
b76bf5a5ad | ||
|
|
69bde2cf3d | ||
|
|
a10042d989 | ||
|
|
dd2d185e4a | ||
|
|
e817e8d3c7 | ||
|
|
aaac2b71a3 | ||
|
|
11c3a7b374 | ||
|
|
ccc09e6aca | ||
|
|
5a8f1263ef | ||
|
|
b6b2c72b19 | ||
|
|
0fd5d7affe | ||
|
|
2e4d80bc1c | ||
|
|
6b87db7ac7 | ||
|
|
61760d940c | ||
|
|
f43d4c38ea | ||
|
|
ccb8386672 | ||
|
|
e15319a46e | ||
|
|
e352d153ce | ||
|
|
4f9bbf57bc | ||
|
|
0b9d80da93 | ||
|
|
24d32d8441 | ||
|
|
476c4027ff | ||
|
|
12c748a8cd | ||
|
|
0259ad2464 | ||
|
|
5f3ead2086 | ||
|
|
e3f42d747a | ||
|
|
b93e0e4701 | ||
|
|
9f9e04724d | ||
|
|
5981af6c0a | ||
|
|
f38240f527 | ||
|
|
d775e805fb | ||
|
|
d9eb91c120 | ||
|
|
13223b2d74 | ||
|
|
d5ce78ae5a | ||
|
|
3bb5241275 | ||
|
|
41e895a2db | ||
|
|
17ce81eb0e | ||
|
|
ba3b80db7a | ||
|
|
2a1f3345ba | ||
|
|
c0aa89bd6f | ||
|
|
501aa7b7f1 | ||
|
|
9313489552 | ||
|
|
63b36a45b9 | ||
|
|
087dbe99b9 | ||
|
|
d11cd0a06d | ||
|
|
429ff2dd09 | ||
|
|
3f16943ccd | ||
|
|
4b4aebff8c | ||
|
|
46a7dddd11 | ||
|
|
2ec81da048 | ||
|
|
08c4aba8ab | ||
|
|
44889c8a33 |
1
.coffee.internal.sed
Normal file
1
.coffee.internal.sed
Normal file
@@ -0,0 +1 @@
|
||||
s/Coffee.Internal/Coffee.UIParticleInternal/g
|
||||
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -26,9 +26,9 @@ A clear and concise description of what you expected to happen.
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Environment (please complete the following information):**
|
||||
- Version [e.g. 1.0.0]
|
||||
- Version [e.g. 4.0.0]
|
||||
- Platform: [e.g. Editor(Windows/Mac), Standalone(Windows/Mac), iOS, Android, WebGL]
|
||||
- Unity version: [e.g. 2018.2.8f1]
|
||||
- Unity version: [e.g. 2022.3.0f1]
|
||||
- Build options: [e.g. IL2CPP, .Net 4.x, LWRP]
|
||||
|
||||
**Additional context**
|
||||
|
||||
9
.github/pull_request_template.md
vendored
Normal file
9
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: Pull Request
|
||||
about: Create a pull request
|
||||
title: ''
|
||||
assignees: mob-sakai
|
||||
|
||||
---
|
||||
|
||||
**NOTE: Create a pull request to merge into `develop` branch**
|
||||
23
.github/workflows/release.yml
vendored
23
.github/workflows/release.yml
vendored
@@ -1,23 +0,0 @@
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- preview
|
||||
- master
|
||||
- v*.x
|
||||
tags-ignore:
|
||||
- "**"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(github.event.head_commit.message, '[skip ci]') && ! contains(github.event.head_commit.message, '[ci skip]')"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- run: |
|
||||
npm i --no-save https://gist.github.com/mob-sakai/c90044338361af97a7e8c8a78425bdb3
|
||||
npx semantic-release -e @mob-sakai/semantic-release-upm
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
100
.github/workflows/unity-test.yml
vendored
100
.github/workflows/unity-test.yml
vendored
@@ -1,100 +0,0 @@
|
||||
name: unity-test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
tags:
|
||||
- "!*"
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
unity-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
unity:
|
||||
[
|
||||
"2018.3.14f1",
|
||||
"2018.4.25f1",
|
||||
"2019.1.14f1",
|
||||
"2019.2.11f1",
|
||||
"2019.3.15f1",
|
||||
"2019.4.8f1",
|
||||
"2020.1.5f1",
|
||||
]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
# Use Unity image from https://hub.docker.com/r/gableroux/unity3d/tags
|
||||
image: gableroux/unity3d:${{ matrix.unity }}
|
||||
|
||||
steps:
|
||||
# Activate Unity Editor
|
||||
- name: Activate Unity Editor
|
||||
id: activation
|
||||
run: |
|
||||
apt-get update > /dev/null
|
||||
apt-get install software-properties-common -y > /dev/null
|
||||
apt-add-repository ppa:git-core/ppa -y > /dev/null
|
||||
apt-get update > /dev/null
|
||||
apt-get install git -y > /dev/null
|
||||
git clone https://gist.github.com/135c940b45ec4e385861c8711777db7f.git .ulfs
|
||||
chmod 755 .ulfs/activate.sh && .ulfs/activate.sh ${{ matrix.unity }}
|
||||
|
||||
# (On failed activation) Upload unity activation file
|
||||
- name: Upload unity activation file
|
||||
uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: Unity_v${{ matrix.unity }}.alf
|
||||
path: ./*.alf
|
||||
|
||||
# Checkout sandbox project
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: "sandbox"
|
||||
submodules: "true"
|
||||
|
||||
# Update package submodule
|
||||
- name: "Update package submodule"
|
||||
working-directory: Packages/dev
|
||||
run: git checkout ${{ github.head_ref }}
|
||||
|
||||
# Install codecoverage package
|
||||
- name: "Install codecoverage package"
|
||||
if: always() && steps.activation.conclusion == 'success'
|
||||
run: |
|
||||
[ -n "`echo ${{ matrix.unity }} | grep -e '\(2017.\|2018.\|2019.1.\|2019.2.\)'`" ] && exit 0
|
||||
npm i -g openupm-cli
|
||||
openupm add com.unity.testtools.codecoverage
|
||||
|
||||
# Run playmode tests
|
||||
- name: "Run playmode tests"
|
||||
if: always() && steps.activation.conclusion == 'success'
|
||||
run: |
|
||||
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
||||
/opt/Unity/Editor/Unity -batchmode -nographics -silent-crashes -logFile -projectPath . \
|
||||
-runTests -testPlatform playmode -enableCodeCoverage
|
||||
|
||||
# Run editmode tests
|
||||
- name: "Run editmode tests"
|
||||
if: always() && steps.activation.conclusion == 'success'
|
||||
run: |
|
||||
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
||||
/opt/Unity/Editor/Unity -batchmode -nographics -silent-crashes -logFile -projectPath . \
|
||||
-runTests -testPlatform editmode -enableCodeCoverage
|
||||
|
||||
# Setup testspace
|
||||
- uses: testspace-com/setup-testspace@v1
|
||||
if: always() && steps.activation.conclusion == 'success'
|
||||
with:
|
||||
domain: ${{ github.repository_owner }}
|
||||
|
||||
# Push test results
|
||||
- name: Push test results
|
||||
if: always() && steps.activation.conclusion == 'success'
|
||||
run: testspace "[${{ matrix.unity }}]TestResults-*.xml" "[Code Coverage]CodeCoverage/**/TestCoverageResults_*.xml"
|
||||
23
.releaserc.json
Normal file
23
.releaserc.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"branches": [
|
||||
"release",
|
||||
"release-4.x",
|
||||
{
|
||||
"name": "release-preview",
|
||||
"prerelease": "preview"
|
||||
}
|
||||
],
|
||||
"plugins": [
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
"@semantic-release/changelog",
|
||||
[
|
||||
"@semantic-release/npm",
|
||||
{
|
||||
"npmPublish": false
|
||||
}
|
||||
],
|
||||
"@semantic-release/git",
|
||||
"@semantic-release/github"
|
||||
]
|
||||
}
|
||||
435
CHANGELOG.md
435
CHANGELOG.md
@@ -1,3 +1,438 @@
|
||||
# [5.0.0-preview.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v5.0.0-preview.2...v5.0.0-preview.3) (2024-06-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* generated baking-camera object remains in the prefab or scene ([fd66928](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/fd66928efe584aeb4f6347b9a9dca97d9512eb88))
|
||||
|
||||
# [5.0.0-preview.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v5.0.0-preview.1...v5.0.0-preview.2) (2024-06-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 'Resource ID out of range in GetResource' error in overlay rendering mode ([ff78b6f](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ff78b6fe32ceed8ddad50e63dcb7a202eab95266)), closes [#308](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/308)
|
||||
* `UIParticle.transform.localScale` does not scale particles ([491ee7b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/491ee7b0c3e528e1e577ae5ff2588d7c3bd8ecdb)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
||||
* despite not using the size module, particles become smaller based on their z position ([c96ddf2](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c96ddf293e855f7ebccaaaf3b112092955545e61)), closes [#316](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/316)
|
||||
* the ParticleSystem's localPosition drifts at certain scales due to floating-point precision issues ([a9c2b19](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a9c2b19edf00e1c86c928ef23405906952ede852)), closes [#299](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/299) [#312](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/312)
|
||||
* UIParticle is scaled by canvas size even when `AutoScalingMode.None` and `ScalingMode.Local` ([63b24d8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/63b24d8a8b478b3165733ece3eec524e88b28855)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
||||
* UIParticle is scaled incorrectly with nested canvases ([c95d8c6](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c95d8c6b1774396ff252d13121ad32a3cab0fe5c)), closes [#313](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/313)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* remove overlay window (editor) ([fc3fbdd](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/fc3fbdd230595ad3471875ec6fec384a3dad0d17))
|
||||
* reset previous position on start play for world space simulation ([e741584](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e7415845074143abae23e3ae7eedc767a01d020d)), closes [#303](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/303)
|
||||
* restore `Transform.localScale` when setting `autoScalingMode` to something other than `Transform` ([dfb94f4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/dfb94f4badfb3035a4374579c53293460b4fd946))
|
||||
|
||||
# [5.0.0-preview.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.6...v5.0.0-preview.1) (2024-05-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add project settings for UIParticle ([b6e6185](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b6e6185c521fef0f118f61cfdfdac07b87555c01))
|
||||
* change the default value of `UIParticle.scale` from `10` to `1` ([1b3c0f9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1b3c0f92dcc6a1974d1ea074821e5264200e9711)), closes [#310](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/310)
|
||||
* UIParticle no longer inherits from MaskableGraphic ([b6d921b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b6d921b3e47f749b5028d22b0e89b6eb3a1af7de))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* Some members inherited from MaskableGraphic will no longer be available.
|
||||
|
||||
## [4.6.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.5...v4.6.6) (2024-05-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix release workflow ([30b0076](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/30b00762f6da166c043587798b1552f27b4cc604))
|
||||
|
||||
## [4.6.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.4...v4.6.5) (2024-05-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update workflows (for preview and v4) ([3eab097](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3eab0979b9b85919b804442ab05735b7120eade5))
|
||||
|
||||
## [4.6.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.3...v4.6.4) (2024-05-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* assertion failed on expression: 'ps->array_size()' ([1b5c359](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1b5c359058289895caf5f245fe09abb643bc38eb)), closes [#278](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/278)
|
||||
* lost Material.mainTexture when using AnimatableProperties ([ea04352](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ea043524c0b00f67cba26a1f9ea537ee4a56d6ff)), closes [#311](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/311)
|
||||
* remove unnecessary code ([c37c014](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c37c01486499773e3d7e8296c95bb4c3fae94abb))
|
||||
|
||||
## [4.6.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.2...v4.6.3) (2024-04-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* if only Trail Material is used, it will not be displayed ([2eff411](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2eff411bd97eb4e6947d29a02b85b414bfdaee3a)), closes [#294](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/294)
|
||||
* if the UIParticle parents do not have Canvas, an exception is thrown in OnEnable ([e82c833](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e82c833d04b819f103984931ba29a3616ef50908)), closes [#300](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/300)
|
||||
* particle size too small due to auto scaling ([2ec3748](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2ec374833614d64406e7c3207ca5fe234a749dcb)), closes [#295](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/295)
|
||||
|
||||
## [4.6.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.1...v4.6.2) (2024-02-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix compile error in Unity 2021.1 or older ([fcae60b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/fcae60bf29079bac07463bd3a86f8644151d72ba))
|
||||
* fix demos ([ad20d12](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ad20d128a2ad033d9f30b98f0a0dab6091f5aa19))
|
||||
* fix warning ([7fd4a8e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/7fd4a8e343ce587dffa9db5ff186061b3ebb38a6))
|
||||
|
||||
## [4.6.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.0...v4.6.1) (2024-01-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* unintended scaling occurs when `AutoScalingMode=UIParticle` and `ScalingMode=Local` ([1627de1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1627de10eb1e742a015603ae9939071665a5bd89)), closes [#292](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/292)
|
||||
|
||||
# [4.6.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.5.2...v4.6.0) (2024-01-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix abnormal mesh bounds error ([772bf50](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/772bf50d168982bd401c30e58172e0a60fbafe46)), closes [#213](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/213)
|
||||
* fix warning ([93d3919](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/93d3919b6fb6ac186b3e99f8baaef9a044f583f2))
|
||||
* fix warning ([8a78ec1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8a78ec13ad2aad9138a22b67c332871e064a38cc))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* "[generated]" GameObjects on the hierarchy is disturbing ([7c42421](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/7c4242150b591daf64390588afa27efa27368af3)), closes [#288](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/288)
|
||||
* add explicit dependencies ([9a0187a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9a0187a72a35d378ff7be965bfcb7475f423fe0f))
|
||||
* add icon ([0c1022c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0c1022c6224394713f62b41e5e4ef0c289610ae1))
|
||||
* remove samples ([f53a7fa](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f53a7faed3ee73ac22d745a778284e818624b510))
|
||||
|
||||
# [4.6.0-preview.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.5.2...v4.6.0-preview.1) (2024-01-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix abnormal mesh bounds error ([772bf50](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/772bf50d168982bd401c30e58172e0a60fbafe46)), closes [#213](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/213)
|
||||
* fix warning ([93d3919](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/93d3919b6fb6ac186b3e99f8baaef9a044f583f2))
|
||||
* fix warning ([8a78ec1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8a78ec13ad2aad9138a22b67c332871e064a38cc))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* "[generated]" GameObjects on the hierarchy is disturbing ([7c42421](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/7c4242150b591daf64390588afa27efa27368af3)), closes [#288](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/288)
|
||||
* add explicit dependencies ([9a0187a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9a0187a72a35d378ff7be965bfcb7475f423fe0f))
|
||||
* add icon ([0c1022c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0c1022c6224394713f62b41e5e4ef0c289610ae1))
|
||||
* remove samples ([f53a7fa](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f53a7faed3ee73ac22d745a778284e818624b510))
|
||||
|
||||
## [4.5.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.5.1...4.5.2) (2024-01-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (editor) sometimes crashes when entering play mode ([b80c3e6](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b80c3e6c9fdd2a8fb72ff233edb85df2e3dbba3d))
|
||||
|
||||
## [4.5.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.5.0...4.5.1) (2023-12-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix material for mesh sharing group ([6126af9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/6126af9f376dd4c100a1b9d19d9499bdef7d5566))
|
||||
* the changes made to the material used by the ParticleSystem are not immediately reflected ([3184ba9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3184ba94ae08264223c0c71443ad70acc1a1ccb2)), closes [#280](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/280)
|
||||
|
||||
# [4.5.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.4.0...4.5.0) (2023-12-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* incorrect rendering of world-space simulated particles while animating scale ([ac58475](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ac584755393d87bda2e80d9653370b7e4c68912f)), closes [#285](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/285)
|
||||
* remove obsolete warning ([5d5eb34](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5d5eb34590b7cefb0e4ac26c0441e104176ce522))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Automatically generated objects are no longer editable (NotEditable). ([5607dc4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5607dc4eed0c086b4651941953df6c7d535712e0))
|
||||
* support IMeshModifier ([5c3232f](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/5c3232faf3d2cfad1e3e1a9349b8346c7982a608)), closes [#282](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/282)
|
||||
|
||||
# [4.4.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.3.0...4.4.0) (2023-11-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* support 'Active Apply Color Space' for linear color space ([45c56bb](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/45c56bbd850202365751ea019baf5131b2eb9fbe))
|
||||
|
||||
# [4.3.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.2.2...4.3.0) (2023-11-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* added 'autoScalingMode (None, Transform.localScale, UIParticle.scale)' instead of 'autoScaling' ([107f901](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/107f901fe3232223322681edc4bf908642474298))
|
||||
* reset transform.localScale on upgrading v3.x to v4.x ([c710787](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c710787b5ba496cf73e7eb43458bb3958139baa9)), closes [#277](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/277)
|
||||
|
||||
## [4.2.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.2.1...4.2.2) (2023-10-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* il2cpp code stripping bug ([73f6dad](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/73f6dad0f33641a76ddd05ffc6812ced3f8a276d)), closes [#269](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/269)
|
||||
|
||||
## [4.2.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.2.0...4.2.1) (2023-08-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* autoScaling and PositionMode may be locked ([3f2f12d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3f2f12d2cf7541118c02830ec9fdea8183357487))
|
||||
|
||||
# [4.2.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.7...4.2.0) (2023-08-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* assertion 'ps->array_size()' in UpdateMesh() when using trails of type ribbon ([f75fcce](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f75fcce0dae0bc166bd01d36a150aded1fd721f3)), closes [#241](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/241)
|
||||
* built-in shaders are no longer supported ([c2119c1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c2119c171a1262431eac7fea6bf3125db2bcaaca)), closes [#233](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/233) [#257](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/257)
|
||||
* crash occurs when too many vertices are rendered ([723a04d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/723a04d0cfd156715a3c92b6d6bd75fdc1862c28))
|
||||
* error: SerializedObject target has been destroyed ([e930516](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e93051603e121732c92bcd89ded48087c2b0d7fb)), closes [#267](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/267)
|
||||
* excessive particle emitted on move ParticleSystem for local space simulation and emission over distance ([2fe0bde](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2fe0bde422f9769dfedaf6b053ea07f773646679)), closes [#265](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/265)
|
||||
* fix typos ([52f2ef1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/52f2ef1f2471a2e1c29fca96255c04b222d9c848))
|
||||
* generated GameObject will be named '[generated] *' ([9b2e5c1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9b2e5c1d1024e091de6d18a4578cd18b43563e48))
|
||||
* inactive ParticleSystems are removed from the list on refresh ([4851a18](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/4851a1880eef9f385dd9db644ea7e544f95da4fc))
|
||||
* mesh sharing not working ([8b4ca1a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8b4ca1add5c409601e840253e1c0dbcdbf536da8)), closes [#236](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/236)
|
||||
* nullptr exceptions when using nested UIParticle components in hierarchy ([e67e948](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e67e9482e2cb840b16e2cfe76e04f7423fcbd3a3)), closes [#246](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/246)
|
||||
* nullReferenceException after copy-n-paste ([425aad0](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/425aad0cbab475635c72bee84ecbf3f2acedccc2)), closes [#258](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/258)
|
||||
* remove unnecessary per-frame allocation. ([e92b514](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e92b514624cc362e53ddeae5ade20fa732f94c7c))
|
||||
* scaling ParticleSystem puts prewarmed particles in wrong location ([fb31db4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/fb31db47f2debb3aadbdc4d1b88d0efd9c4ad7bd)), closes [#235](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/235)
|
||||
* sub-emitters option is not work in editor playing ([b308b26](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b308b2683372662bb834b6f6d23ea3435a68d1b3)), closes [#231](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/231)
|
||||
* the camera under UIParticle will be assigned as _orthoCamera ([c42f8c8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c42f8c8ab0ff033689349a81e02a4808e071a8a2))
|
||||
* UIParticleAttractor attracts the particles at wrong position when in RelativeMode ([68d9925](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/68d9925a16237df3c7b07b4781172cbd03425421)), closes [#262](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/262)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 'AbsoluteMode' option is renamed to 'PositionMode' ([67eff61](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/67eff610736344ba0122163ff5ee63b25c43f555))
|
||||
* 'AutoScaling' option will be imported from 'IgnoreCanvasScale' (for v3.x) ([4103041](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/410304125f3f25f3f543c7bc01dcc661eab00609))
|
||||
* add 'AutoScaling' option for UIParticle ([35325c8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/35325c88996fa6aea19a6dd1395c05884e1f84ae))
|
||||
* add 'UpdateMode' option for UIParticleAttractor ([903f702](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/903f702d7be38228841a5a693e3afdceb4a59d9f)), closes [#250](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/250)
|
||||
* add particle system getter and setter for attractor ([a4bcf93](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a4bcf93022d2729f3d2a74a2cac4f52e68641b18)), closes [#253](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/253)
|
||||
* add public properties for UIParticleAttractor ([392ab6d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/392ab6dd76c36e815320d3a50744d19faa631260)), closes [#253](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/253)
|
||||
* add Start/StopEmission API for UIParticle ([e499836](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e4998365c9825fa385e0a317768ce073a1f15b48)), closes [#240](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/240)
|
||||
|
||||
## [4.1.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.6...4.1.7) (2022-08-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* the annoying empty black scene overlay box shown even when nothing is selected ([bdeeabb](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/bdeeabbbe140b0ba80fac7ac477874c2467d3a16))
|
||||
|
||||
## [4.1.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.5...4.1.6) (2022-08-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix abnormal mesh bounds error ([f60d6df](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f60d6dfe6030ac89527a4265e414e9a0a20d56db)), closes [#213](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/213) [#218](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/218)
|
||||
|
||||
## [4.1.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.4...4.1.5) (2022-08-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix culling for RectMask2D ([9e2dbe7](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9e2dbe7758eb28a4f6a7c11113d9169847880f96)), closes [#220](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/220)
|
||||
|
||||
## [4.1.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.3...4.1.4) (2022-07-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add `Enabled` toggle in overlay window ([f97e619](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/f97e6195e62b5acfa8f3e97bfe3bc4a7dcadf38a))
|
||||
* if `m_Particles` contains null, an error will occur ([550d0c4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/550d0c43be35cd07e390ffd5749557c89fee0332)), closes [#214](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/214)
|
||||
* ParticleSystem reordering and refreshing in inspector does not work for prefab asset ([7eb4112](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/7eb41124db06ea794db76788b35ce82a0af2c402))
|
||||
* refresh button does not works in prefab edit mode ([c1538a8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c1538a83998608a30dc90944b05f8b75e165cf05)), closes [#214](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/214)
|
||||
* when `UIParticlrRenderer` destroy manually, an error will occur ([a11d2d0](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a11d2d01ce5f67e3f430bcb0bfdee1ad9abf7cfe))
|
||||
|
||||
## [4.1.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.2...4.1.3) (2022-06-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* error on drag prefab to scene ([fa2f867](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/fa2f867bcaff437bb9420da1abcef970cdb09ade)), closes [#211](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/211)
|
||||
|
||||
## [4.1.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.1...4.1.2) (2022-06-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* error on editor ([8034228](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/80342287137c07d58a7492875a401d80cb134073)), closes [#210](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/210)
|
||||
* incorrect position of world space trail particles ([fb7f308](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/fb7f308f092db8a1512383857b80110cd626ecf9)), closes [#209](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/209)
|
||||
|
||||
## [4.1.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.1.0...4.1.1) (2022-06-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add absolute mode toggle to overlay window ([48d1994](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/48d1994f5f8751b707b6ef7695b552df731bece9))
|
||||
|
||||
# [4.1.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.0.1...4.1.0) (2022-06-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add relative/absolute particle position mode ([1879ac8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1879ac8c538778e386e68cfc989a6f4f974043ca)), closes [#205](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/205)
|
||||
|
||||
## [4.0.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/4.0.0...4.0.1) (2022-06-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* overlays do not exist in Unity 2019.2-2021.1 ([cd8e037](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/cd8e0372b63bb6feaaf053518013a641bc7e65ac)), closes [#207](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/207) [#208](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/208)
|
||||
|
||||
# [4.0.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.12...4.0.0) (2022-06-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* correct world space particle position when changing screen size ([c6644a2](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c6644a213263375c7a35b5082ef4b71cc58964e6))
|
||||
* keep properly canvas batches ([d8e96e6](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/d8e96e69a62dff7a451eaed32c7a814e7e62dbb9))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adaptive scaling for UI ([aa0d56f](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/aa0d56f9faa05e9679d4b476bcf135eafb1b8af9))
|
||||
* add overlay window for UIParticle ([7b21c50](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/7b21c500ef78103b605fdca71051d2357b09602f))
|
||||
* add particle attractor component ([386170c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/386170cbf68ebf59d4510fe0a45cf83925ec9ba4))
|
||||
* display warning in inspector if using 'TEXCOORD*.zw' components as custom vertex stream ([59221d5](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/59221d58217a440b77d504e6428bf99f10246260))
|
||||
* mesh sharing group ([9afeebf](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9afeebf67212cdf4d3ac9e9a3b78a7ced5c7ecfe))
|
||||
* random mesh sharing group ([4fa43ed](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/4fa43eda4bc70c9c827c4fad9d5ae1327bfbc322))
|
||||
* support 8+ materials ([b76bf5a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b76bf5a5ad378c3c4b16bcf08d21337757557101)), closes [#122](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/122) [#152](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/152) [#186](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/186)
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* If you update to v4, you may be required to adjust your UIParticle.scale.
|
||||
|
||||
# [4.0.0-preview.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.12...4.0.0-preview.1) (2022-06-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* correct world space particle position when changing screen size ([c6644a2](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c6644a213263375c7a35b5082ef4b71cc58964e6))
|
||||
* keep properly canvas batches ([d8e96e6](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/d8e96e69a62dff7a451eaed32c7a814e7e62dbb9))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adaptive scaling for UI ([aa0d56f](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/aa0d56f9faa05e9679d4b476bcf135eafb1b8af9))
|
||||
* add overlay window for UIParticle ([7b21c50](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/7b21c500ef78103b605fdca71051d2357b09602f))
|
||||
* add particle attractor component ([386170c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/386170cbf68ebf59d4510fe0a45cf83925ec9ba4))
|
||||
* mesh sharing group ([9afeebf](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9afeebf67212cdf4d3ac9e9a3b78a7ced5c7ecfe))
|
||||
* random mesh sharing group ([4fa43ed](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/4fa43eda4bc70c9c827c4fad9d5ae1327bfbc322))
|
||||
* support 8+ materials ([b76bf5a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b76bf5a5ad378c3c4b16bcf08d21337757557101)), closes [#122](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/122) [#152](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/152) [#186](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/186)
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* If you update to v4, you may be required to adjust your UIParticle.scale.
|
||||
|
||||
## [3.3.12](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.11...3.3.12) (2022-06-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* always display materials in inspector ([a10042d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/a10042d989dea18ff010bdbe970aa434e2bdf117))
|
||||
* UNITY_UI_ALPHACLIP in UIAdditive shader is not working ([e817e8d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e817e8d3c75188f3243243855b135bd840699199))
|
||||
|
||||
## [3.3.11](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.10...3.3.11) (2022-06-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* sorting by layer does not work properly ([ccc09e6](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ccc09e6aca2fa3d7bc887e6c733e66706e40ae0f))
|
||||
* when using linear color space, the particle colors are not output correctly ([11c3a7b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/11c3a7b37415d78e1b8ba3988a6e043c9f1861e0)), closes [#203](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/203)
|
||||
|
||||
## [3.3.10](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.9...3.3.10) (2022-02-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* annoying warning for [ExecuteInEditMode] ([b6b2c72](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b6b2c72b198566e2880a22831c937eff7e9eff28)), closes [#180](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/180)
|
||||
* PrefabStageUtility class is not experimental after 2021.2 ([0fd5d7a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0fd5d7affe707fa9e92abd6e192bf400dfb1a80a))
|
||||
|
||||
## [3.3.9](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.8...3.3.9) (2021-08-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix for warning CS0618 ([61760d9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/61760d940cdd4baacaa196ac1631a0a1a40b7204))
|
||||
|
||||
## [3.3.8](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.7...3.3.8) (2021-06-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* improve performance ([e352d15](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e352d153cef8c1efb2792e35010d7eed1e31a040))
|
||||
|
||||
## [3.3.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.6...3.3.7) (2021-06-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Refresh() will be called multiple times in the same frame, due to external assets ([0b9d80d](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0b9d80da939580c72ca1471081d7a034edc985d4))
|
||||
|
||||
## [3.3.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.5...3.3.6) (2021-05-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* In rare cases, the generated camera (for baking) will not be deactivated ([12c748a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/12c748a8cd4adfd2dc5f085cec77050431f261a4))
|
||||
* remove from "Add Component" menu ([476c402](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/476c4027ff5f70fb9b4c026dd5fc59bf5a876227))
|
||||
|
||||
## [3.3.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.4...3.3.5) (2021-02-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix cached position for pre-warmed particles ([e3f42d7](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e3f42d747a7fd973b5813cc72a9444943a6c3ad0))
|
||||
* ParticleSystem creates particles in wrong position during pre-warm ([b93e0e4](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/b93e0e4701c7011176eeec5c109dda7f4ea632e0)), closes [#147](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/147)
|
||||
|
||||
## [3.3.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.3...3.3.4) (2021-02-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Multiselecting sets all scales to the same value ([13223b2](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/13223b2d747609cf88b424ad590bda7f857b387d))
|
||||
* support sub emitter with 'PlayOnAwake' ([d5ce78a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/d5ce78ae5acf2740ba7fdc6cde9f197c4e165484))
|
||||
* The maximum material count is 8 ([3bb5241](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/3bb52412751360409747192150188ae904f2c3d3))
|
||||
|
||||
## [3.3.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.2...3.3.3) (2021-02-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* particle trails draw in wrong transform ([17ce81e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/17ce81eb0eccb103c21fa553183df97429cf5c6f)), closes [#145](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/145)
|
||||
|
||||
## [3.3.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.1...3.3.2) (2021-02-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* _cachedPosition defaults to localPosition ([c0aa89b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c0aa89bd6f7847723a4702b6ca70fa202e8a8304)), closes [#121](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/121)
|
||||
* submeshes can't over 8 ([2a1f334](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2a1f3345bacdecf38e8890781a181a1392224e35)), closes [#122](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/122)
|
||||
|
||||
## [3.3.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.3.0...3.3.1) (2021-02-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ignore material check and transform check ([d11cd0a](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/d11cd0a06d76a32b2a119387bddc34c703b9b497)), closes [#119](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/119)
|
||||
* the trail is incorrect in SimulationSpace.Local ([9313489](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/9313489552b30f2e2b0b42a641f5e0502995b03d))
|
||||
|
||||
# [3.3.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.2.0...3.3.0) (2020-11-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* the particles may disappear unintentionally ([2ec81da](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2ec81da04877d63593dd863133b6da149dcd79e6)), closes [#117](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/117)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ignore rendering of particle systems that do not have a SharedMaterial and TrailMaterial ([08c4aba](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/08c4aba8ab9b5a041d4350a72dae62d25530afca)), closes [#118](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/118)
|
||||
* show/hide materials in inspector ([4b4aebf](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/4b4aebff8cdaff9acc696a1094e170e65631135f))
|
||||
* shrink rendering by material ([46a7ddd](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/46a7dddd11c3e030192cd998ae1a79441f5e5c14)), closes [#113](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/113)
|
||||
|
||||
# [3.2.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/3.1.1...3.2.0) (2020-11-15)
|
||||
|
||||
|
||||
|
||||
@@ -81,4 +81,4 @@ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcem
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
|
||||
https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
|
||||
|
||||
@@ -19,11 +19,24 @@ When fixing a bug it is fine to submit a pull request right away.
|
||||
|
||||
Steps to be performed to submit a pull request:
|
||||
|
||||
1. Fork the repository and create your branch from `develop`.
|
||||
2. If you have fixed a bug or added code that should be tested, add tests.
|
||||
3. Click `Window > Generals > Test Runner` to test
|
||||
4. Commit with a massage based on [Angular Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153).
|
||||
5. Fill out the description, link any related issues and submit your pull request.
|
||||
1. Fork the repository.
|
||||
2. Clone the repository.
|
||||
3. Checkout `develop` branch.
|
||||
4. Develop the package.
|
||||
5. Test the package with the test runner (`Window > Generals > Test Runner`).
|
||||
6. Commit with a message based
|
||||
on [Angular Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) as follows:
|
||||
|
||||
- `fix:` fix a bug
|
||||
- `feat:` new feature
|
||||
- `docs:` changes only in documentation
|
||||
- `style:` changes only in formatting, white-space, etc
|
||||
- `refactor:` changes only in code structure (extract method, rename variable, move method, etc)
|
||||
- `perf:` changes only in code performance
|
||||
- `test:` add or update tests
|
||||
- `chore:` changes to the build process or auxiliary tools and libraries such as documentation generation
|
||||
|
||||
7. Create a pull request on GitHub. Fill out the description, link any related issues and submit your pull request.
|
||||
|
||||
#### License
|
||||
|
||||
|
||||
143
Editor/AnimatablePropertyEditor.cs
Normal file
143
Editor/AnimatablePropertyEditor.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
internal static class AnimatablePropertyEditor
|
||||
{
|
||||
private static readonly GUIContent s_ContentNothing = new GUIContent("Nothing");
|
||||
private static readonly List<string> s_ActiveNames = new List<string>();
|
||||
private static readonly StringBuilder s_Sb = new StringBuilder();
|
||||
private static readonly HashSet<string> s_Names = new HashSet<string>();
|
||||
|
||||
private static string CollectActiveNames(SerializedProperty sp, List<string> result)
|
||||
{
|
||||
result.Clear();
|
||||
for (var i = 0; i < sp.arraySize; i++)
|
||||
{
|
||||
var spName = sp.GetArrayElementAtIndex(i).FindPropertyRelative("m_Name");
|
||||
if (spName == null) continue;
|
||||
|
||||
result.Add(spName.stringValue);
|
||||
}
|
||||
|
||||
s_Sb.Length = 0;
|
||||
if (result.Count == 0)
|
||||
{
|
||||
s_Sb.Append("Nothing");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Aggregate(s_Sb, (a, b) => s_Sb.AppendFormat("{0}, ", b));
|
||||
s_Sb.Length -= 2;
|
||||
}
|
||||
|
||||
return s_Sb.ToString();
|
||||
}
|
||||
|
||||
public static void Draw(SerializedProperty sp, Material[] mats)
|
||||
{
|
||||
bool isClicked;
|
||||
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
var pos = EditorGUILayout.GetControlRect(true);
|
||||
var label = new GUIContent(sp.displayName, sp.tooltip);
|
||||
var rect = EditorGUI.PrefixLabel(pos, label);
|
||||
var text = sp.hasMultipleDifferentValues
|
||||
? "-"
|
||||
: CollectActiveNames(sp, s_ActiveNames);
|
||||
isClicked = GUI.Button(rect, text, EditorStyles.popup);
|
||||
}
|
||||
|
||||
if (!isClicked) return;
|
||||
|
||||
var gm = new GenericMenu();
|
||||
gm.AddItem(s_ContentNothing, s_ActiveNames.Count == 0, () =>
|
||||
{
|
||||
sp.ClearArray();
|
||||
sp.serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
|
||||
if (!sp.hasMultipleDifferentValues)
|
||||
{
|
||||
for (var i = 0; i < sp.arraySize; i++)
|
||||
{
|
||||
var p = sp.GetArrayElementAtIndex(i);
|
||||
var name = p.FindPropertyRelative("m_Name").stringValue;
|
||||
var type = (AnimatableProperty.ShaderPropertyType)p.FindPropertyRelative("m_Type").intValue;
|
||||
AddMenu(gm, sp, new ShaderProperty(name, type), false);
|
||||
}
|
||||
}
|
||||
|
||||
s_Names.Clear();
|
||||
for (var j = 0; j < mats.Length; j++)
|
||||
{
|
||||
var mat = mats[j];
|
||||
if (!mat || !mat.shader) continue;
|
||||
|
||||
for (var i = 0; i < ShaderUtil.GetPropertyCount(mat.shader); i++)
|
||||
{
|
||||
var name = ShaderUtil.GetPropertyName(mat.shader, i);
|
||||
var type = (AnimatableProperty.ShaderPropertyType)ShaderUtil.GetPropertyType(mat.shader, i);
|
||||
if (s_Names.Contains(name)) continue;
|
||||
s_Names.Add(name);
|
||||
|
||||
AddMenu(gm, sp, new ShaderProperty(name, type), true);
|
||||
|
||||
if (type != AnimatableProperty.ShaderPropertyType.Texture) continue;
|
||||
|
||||
AddMenu(gm, sp, new ShaderProperty($"{name}_ST"), true);
|
||||
AddMenu(gm, sp, new ShaderProperty($"{name}_HDR"), true);
|
||||
AddMenu(gm, sp, new ShaderProperty($"{name}_TexelSize"), true);
|
||||
}
|
||||
}
|
||||
|
||||
gm.ShowAsContext();
|
||||
}
|
||||
|
||||
private static void AddMenu(GenericMenu menu, SerializedProperty sp, ShaderProperty prop, bool add)
|
||||
{
|
||||
if (add && s_ActiveNames.Contains(prop.name)) return;
|
||||
|
||||
var label = new GUIContent($"{prop.name} ({prop.type})");
|
||||
menu.AddItem(label, s_ActiveNames.Contains(prop.name), () =>
|
||||
{
|
||||
var index = s_ActiveNames.IndexOf(prop.name);
|
||||
if (0 <= index)
|
||||
{
|
||||
sp.DeleteArrayElementAtIndex(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
sp.InsertArrayElementAtIndex(sp.arraySize);
|
||||
var p = sp.GetArrayElementAtIndex(sp.arraySize - 1);
|
||||
p.FindPropertyRelative("m_Name").stringValue = prop.name;
|
||||
p.FindPropertyRelative("m_Type").intValue = (int)prop.type;
|
||||
}
|
||||
|
||||
sp.serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
}
|
||||
|
||||
private struct ShaderProperty
|
||||
{
|
||||
public readonly string name;
|
||||
public readonly AnimatableProperty.ShaderPropertyType type;
|
||||
|
||||
public ShaderProperty(string name)
|
||||
{
|
||||
this.name = name;
|
||||
type = AnimatableProperty.ShaderPropertyType.Vector;
|
||||
}
|
||||
|
||||
public ShaderProperty(string name, AnimatableProperty.ShaderPropertyType type)
|
||||
{
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15e5409f0334e479e91e672ae14567d3
|
||||
guid: 3e440931f761e4e888510a4e6045287a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
478
Editor/UIParticleEditor.cs
Normal file
478
Editor/UIParticleEditor.cs
Normal file
@@ -0,0 +1,478 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
using UnityEditor.Overlays;
|
||||
#else
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Coffee.UIParticleInternal;
|
||||
using Object = UnityEngine.Object;
|
||||
#endif
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
using UnityEditor.SceneManagement;
|
||||
|
||||
#elif UNITY_2018_3_OR_NEWER
|
||||
using UnityEditor.Experimental.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
[CustomEditor(typeof(UIParticle))]
|
||||
[CanEditMultipleObjects]
|
||||
internal class UIParticleEditor : Editor
|
||||
{
|
||||
//################################
|
||||
// Constant or Static Members.
|
||||
//################################
|
||||
private static readonly GUIContent s_ContentRenderingOrder = new GUIContent("Rendering Order");
|
||||
private static readonly GUIContent s_ContentRefresh = new GUIContent("Refresh");
|
||||
private static readonly GUIContent s_ContentFix = new GUIContent("Fix");
|
||||
private static readonly GUIContent s_ContentMaterial = new GUIContent("Material");
|
||||
private static readonly GUIContent s_ContentTrailMaterial = new GUIContent("Trail Material");
|
||||
private static readonly GUIContent s_Content3D = new GUIContent("3D");
|
||||
private static readonly GUIContent s_ContentRandom = new GUIContent("Random");
|
||||
private static readonly GUIContent s_ContentScale = new GUIContent("Scale");
|
||||
private static bool s_XYZMode;
|
||||
|
||||
private SerializedProperty _maskable;
|
||||
private SerializedProperty _scale3D;
|
||||
private SerializedProperty _animatableProperties;
|
||||
private SerializedProperty _meshSharing;
|
||||
private SerializedProperty _groupId;
|
||||
private SerializedProperty _groupMaxId;
|
||||
private SerializedProperty _positionMode;
|
||||
private SerializedProperty _autoScalingMode;
|
||||
private ReorderableList _ro;
|
||||
private bool _showMax;
|
||||
|
||||
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
||||
#if UNITY_2018 || UNITY_2019
|
||||
private static readonly List<ParticleSystemVertexStream> s_Streams = new List<ParticleSystemVertexStream>();
|
||||
#endif
|
||||
private static readonly List<string> s_MaskablePropertyNames = new List<string>
|
||||
{
|
||||
"_Stencil",
|
||||
"_StencilComp",
|
||||
"_StencilOp",
|
||||
"_StencilWriteMask",
|
||||
"_StencilReadMask",
|
||||
"_ColorMask"
|
||||
};
|
||||
|
||||
//################################
|
||||
// Public/Protected Members.
|
||||
//################################
|
||||
/// <summary>
|
||||
/// This function is called when the object becomes enabled and active.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_maskable = serializedObject.FindProperty("m_Maskable");
|
||||
_scale3D = serializedObject.FindProperty("m_Scale3D");
|
||||
_animatableProperties = serializedObject.FindProperty("m_AnimatableProperties");
|
||||
_meshSharing = serializedObject.FindProperty("m_MeshSharing");
|
||||
_groupId = serializedObject.FindProperty("m_GroupId");
|
||||
_groupMaxId = serializedObject.FindProperty("m_GroupMaxId");
|
||||
_positionMode = serializedObject.FindProperty("m_PositionMode");
|
||||
_autoScalingMode = serializedObject.FindProperty("m_AutoScalingMode");
|
||||
|
||||
var sp = serializedObject.FindProperty("m_Particles");
|
||||
_ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true)
|
||||
{
|
||||
elementHeight = EditorGUIUtility.singleLineHeight * 3 + 4,
|
||||
elementHeightCallback = _ => 3 * (EditorGUIUtility.singleLineHeight + 2),
|
||||
drawElementCallback = (rect, index, _, __) =>
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(sp.hasMultipleDifferentValues);
|
||||
rect.y += 1;
|
||||
rect.height = EditorGUIUtility.singleLineHeight;
|
||||
var p = sp.GetArrayElementAtIndex(index);
|
||||
EditorGUI.ObjectField(rect, p, GUIContent.none);
|
||||
rect.x += 15;
|
||||
rect.width -= 15;
|
||||
var ps = p.objectReferenceValue as ParticleSystem;
|
||||
var materials = ps
|
||||
? new SerializedObject(ps.GetComponent<ParticleSystemRenderer>()).FindProperty("m_Materials")
|
||||
: null;
|
||||
rect.y += rect.height + 1;
|
||||
MaterialField(rect, s_ContentMaterial, materials, 0);
|
||||
rect.y += rect.height + 1;
|
||||
MaterialField(rect, s_ContentTrailMaterial, materials, 1);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
if (materials != null && materials.serializedObject.hasModifiedProperties)
|
||||
{
|
||||
materials.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
},
|
||||
drawHeaderCallback = rect =>
|
||||
{
|
||||
#if !UNITY_2019_3_OR_NEWER
|
||||
rect.y -= 1;
|
||||
#endif
|
||||
var pos = new Rect(rect.x, rect.y, 150, rect.height);
|
||||
EditorGUI.LabelField(pos, s_ContentRenderingOrder);
|
||||
|
||||
pos = new Rect(rect.width - 35, rect.y, 60, rect.height);
|
||||
if (GUI.Button(pos, s_ContentRefresh, EditorStyles.miniButton))
|
||||
{
|
||||
foreach (var uip in targets.OfType<UIParticle>())
|
||||
{
|
||||
uip.RefreshParticles();
|
||||
EditorUtility.SetDirty(uip);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// On select UIParticle, refresh particles.
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
foreach (var uip in targets.OfType<UIParticle>())
|
||||
{
|
||||
if (PrefabUtility.GetPrefabAssetType(uip) != PrefabAssetType.NotAPrefab) continue;
|
||||
uip.RefreshParticles(uip.particles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void MaterialField(Rect rect, GUIContent label, SerializedProperty sp, int index)
|
||||
{
|
||||
if (sp == null || sp.arraySize <= index)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
EditorGUI.ObjectField(rect, label, null, typeof(Material), true);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUI.PropertyField(rect, sp.GetArrayElementAtIndex(index), label);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement this function to make a custom inspector.
|
||||
/// </summary>
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var current = target as UIParticle;
|
||||
if (!current) return;
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
// Maskable
|
||||
EditorGUILayout.PropertyField(_maskable);
|
||||
|
||||
// Scale
|
||||
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
||||
s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
// AnimatableProperties
|
||||
var mats = current.particles
|
||||
.Where(x => x)
|
||||
.Select(x => x.GetComponent<ParticleSystemRenderer>().sharedMaterial)
|
||||
.Where(x => x)
|
||||
.ToArray();
|
||||
|
||||
AnimatablePropertyEditor.Draw(_animatableProperties, mats);
|
||||
|
||||
// Mesh sharing
|
||||
EditorGUI.BeginChangeCheck();
|
||||
_showMax = DrawMeshSharing(_meshSharing, _groupId, _groupMaxId, _showMax);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
foreach (var uip in targets.OfType<UIParticle>())
|
||||
{
|
||||
uip.ResetGroupId();
|
||||
}
|
||||
}
|
||||
|
||||
// Position Mode
|
||||
EditorGUILayout.PropertyField(_positionMode);
|
||||
|
||||
// Auto Scaling
|
||||
DrawAutoScaling(_autoScalingMode, targets.OfType<UIParticle>());
|
||||
|
||||
// Target ParticleSystems.
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.BeginDisabledGroup(targets.OfType<UIParticle>().Any(x => !x.canvas));
|
||||
_ro.DoLayoutList();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
foreach (var uip in targets.OfType<UIParticle>())
|
||||
{
|
||||
uip.RefreshParticles(uip.particles);
|
||||
}
|
||||
}
|
||||
|
||||
// Non-UI built-in shader is not supported.
|
||||
foreach (var mat in current.materials)
|
||||
{
|
||||
if (!mat || !mat.shader) continue;
|
||||
var shader = mat.shader;
|
||||
if (IsBuiltInObject(shader) && !shader.name.StartsWith("UI/"))
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
$"Built-in shader '{shader.name}' in '{mat.name}' is not supported.\n" +
|
||||
"Use UI shaders instead.",
|
||||
MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
// Does the shader support UI masks?
|
||||
if (current.maskable && current.GetComponentInParent<Mask>(false))
|
||||
{
|
||||
foreach (var mat in current.materials)
|
||||
{
|
||||
if (!mat || !mat.shader) continue;
|
||||
var shader = mat.shader;
|
||||
if (s_Shaders.Contains(shader)) continue;
|
||||
s_Shaders.Add(shader);
|
||||
foreach (var propName in s_MaskablePropertyNames)
|
||||
{
|
||||
if (mat.HasProperty(propName)) continue;
|
||||
|
||||
EditorGUILayout.HelpBox(
|
||||
$"Shader '{shader.name}' doesn't have '{propName}' property." +
|
||||
"\nThis graphic cannot be masked.",
|
||||
MessageType.Warning);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_Shaders.Clear();
|
||||
|
||||
// UIParticle for trail should be removed.
|
||||
var label = "This UIParticle component should be removed. The UIParticle for trails is no longer needed.";
|
||||
#pragma warning disable CS0612
|
||||
if (FixButton(current.m_IsTrail, label))
|
||||
#pragma warning restore CS0612
|
||||
{
|
||||
DestroyUIParticle(current);
|
||||
}
|
||||
|
||||
#if UNITY_2018 || UNITY_2019
|
||||
// (2018, 2019) Check to use 'TEXCOORD*.zw' components as custom vertex stream.
|
||||
var allPsRenderers = targets.OfType<UIParticle>()
|
||||
.SelectMany(x => x.particles)
|
||||
.Where(x => x)
|
||||
.Select(x => x.GetComponent<ParticleSystemRenderer>())
|
||||
.ToArray();
|
||||
if (0 < allPsRenderers.Length)
|
||||
{
|
||||
// Check to use 'TEXCOORD*.zw' components as custom vertex stream.
|
||||
foreach (var psr in allPsRenderers)
|
||||
{
|
||||
if (!new SerializedObject(psr).FindProperty("m_UseCustomVertexStreams").boolValue) continue;
|
||||
if (psr.activeVertexStreamsCount == 0) continue;
|
||||
psr.GetActiveVertexStreams(s_Streams);
|
||||
|
||||
if (2 < s_Streams.Select(GetUsedComponentCount).Sum())
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
$"ParticleSystem '{psr.name}' uses 'TEXCOORD*.zw' components as custom vertex stream.\n" +
|
||||
"UIParticle does not support it (See README.md).",
|
||||
MessageType.Warning);
|
||||
}
|
||||
|
||||
s_Streams.Clear();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool IsBuiltInObject(Object obj)
|
||||
{
|
||||
return AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out var guid, out long _)
|
||||
&& Regex.IsMatch(guid, "^0{16}.0{15}$", RegexOptions.Compiled);
|
||||
}
|
||||
|
||||
#if UNITY_2018 || UNITY_2019
|
||||
private static int GetUsedComponentCount(ParticleSystemVertexStream s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case ParticleSystemVertexStream.Position:
|
||||
case ParticleSystemVertexStream.Normal:
|
||||
case ParticleSystemVertexStream.Tangent:
|
||||
case ParticleSystemVertexStream.Color:
|
||||
return 0;
|
||||
case ParticleSystemVertexStream.UV:
|
||||
case ParticleSystemVertexStream.UV2:
|
||||
case ParticleSystemVertexStream.UV3:
|
||||
case ParticleSystemVertexStream.UV4:
|
||||
case ParticleSystemVertexStream.SizeXY:
|
||||
case ParticleSystemVertexStream.StableRandomXY:
|
||||
case ParticleSystemVertexStream.VaryingRandomXY:
|
||||
case ParticleSystemVertexStream.Custom1XY:
|
||||
case ParticleSystemVertexStream.Custom2XY:
|
||||
case ParticleSystemVertexStream.NoiseSumXY:
|
||||
case ParticleSystemVertexStream.NoiseImpulseXY:
|
||||
return 2;
|
||||
case ParticleSystemVertexStream.AnimBlend:
|
||||
case ParticleSystemVertexStream.AnimFrame:
|
||||
case ParticleSystemVertexStream.VertexID:
|
||||
case ParticleSystemVertexStream.SizeX:
|
||||
case ParticleSystemVertexStream.Rotation:
|
||||
case ParticleSystemVertexStream.RotationSpeed:
|
||||
case ParticleSystemVertexStream.Velocity:
|
||||
case ParticleSystemVertexStream.Speed:
|
||||
case ParticleSystemVertexStream.AgePercent:
|
||||
case ParticleSystemVertexStream.InvStartLifetime:
|
||||
case ParticleSystemVertexStream.StableRandomX:
|
||||
case ParticleSystemVertexStream.VaryingRandomX:
|
||||
case ParticleSystemVertexStream.Custom1X:
|
||||
case ParticleSystemVertexStream.Custom2X:
|
||||
case ParticleSystemVertexStream.NoiseSumX:
|
||||
case ParticleSystemVertexStream.NoiseImpulseX:
|
||||
return 1;
|
||||
case ParticleSystemVertexStream.Center:
|
||||
case ParticleSystemVertexStream.SizeXYZ:
|
||||
case ParticleSystemVertexStream.Rotation3D:
|
||||
case ParticleSystemVertexStream.RotationSpeed3D:
|
||||
case ParticleSystemVertexStream.StableRandomXYZ:
|
||||
case ParticleSystemVertexStream.VaryingRandomXYZ:
|
||||
case ParticleSystemVertexStream.Custom1XYZ:
|
||||
case ParticleSystemVertexStream.Custom2XYZ:
|
||||
case ParticleSystemVertexStream.NoiseSumXYZ:
|
||||
case ParticleSystemVertexStream.NoiseImpulseXYZ:
|
||||
return 3;
|
||||
case ParticleSystemVertexStream.StableRandomXYZW:
|
||||
case ParticleSystemVertexStream.VaryingRandomXYZW:
|
||||
case ParticleSystemVertexStream.Custom1XYZW:
|
||||
case ParticleSystemVertexStream.Custom2XYZW:
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 3;
|
||||
}
|
||||
#endif
|
||||
|
||||
private static bool DrawMeshSharing(SerializedProperty spMeshSharing, SerializedProperty spGroupId,
|
||||
SerializedProperty spGroupMaxId, bool showMax)
|
||||
{
|
||||
showMax |= spGroupId.intValue != spGroupMaxId.intValue ||
|
||||
spGroupId.hasMultipleDifferentValues ||
|
||||
spGroupMaxId.hasMultipleDifferentValues;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(spMeshSharing);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
showMax = GUILayout.Toggle(showMax, s_ContentRandom, EditorStyles.miniButton, GUILayout.Width(60));
|
||||
if (EditorGUI.EndChangeCheck() && !showMax)
|
||||
{
|
||||
spGroupMaxId.intValue = spGroupId.intValue;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUI.BeginDisabledGroup(spMeshSharing.intValue == 0);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(spGroupId);
|
||||
if (showMax)
|
||||
{
|
||||
EditorGUILayout.PropertyField(spGroupMaxId);
|
||||
}
|
||||
else if (spMeshSharing.intValue == 1 || spMeshSharing.intValue == 4)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
var obj = UIParticleUpdater.GetPrimary(spGroupId.intValue);
|
||||
EditorGUILayout.ObjectField("Primary", obj, typeof(UIParticle), false);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
return showMax;
|
||||
}
|
||||
|
||||
private static void DrawAutoScaling(SerializedProperty prop, IEnumerable<UIParticle> uiParticles)
|
||||
{
|
||||
EditorGUILayout.PropertyField(prop);
|
||||
}
|
||||
|
||||
private void DestroyUIParticle(UIParticle p, bool ignoreCurrent = false)
|
||||
{
|
||||
if (!p || (ignoreCurrent && target == p)) return;
|
||||
|
||||
DestroyImmediate(p);
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
var stage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
if (stage != null && stage.scene.isLoaded)
|
||||
{
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
var prefabAssetPath = stage.assetPath;
|
||||
#else
|
||||
var prefabAssetPath = stage.prefabAssetPath;
|
||||
#endif
|
||||
PrefabUtility.SaveAsPrefabAsset(stage.prefabContentsRoot, prefabAssetPath);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static bool FixButton(bool show, string text)
|
||||
{
|
||||
if (!show) return false;
|
||||
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(true)))
|
||||
{
|
||||
EditorGUILayout.HelpBox(text, MessageType.Warning, true);
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
{
|
||||
return GUILayout.Button(s_ContentFix, GUILayout.Width(30));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool DrawFloatOrVector3Field(SerializedProperty sp, bool showXyz)
|
||||
{
|
||||
var x = sp.FindPropertyRelative("x");
|
||||
var y = sp.FindPropertyRelative("y");
|
||||
var z = sp.FindPropertyRelative("z");
|
||||
|
||||
showXyz |= !Mathf.Approximately(x.floatValue, y.floatValue) ||
|
||||
!Mathf.Approximately(y.floatValue, z.floatValue) ||
|
||||
y.hasMultipleDifferentValues ||
|
||||
z.hasMultipleDifferentValues;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (showXyz)
|
||||
{
|
||||
EditorGUILayout.PropertyField(sp);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.PropertyField(x, s_ContentScale);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
y.floatValue = z.floatValue = x.floatValue;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
showXyz = GUILayout.Toggle(showXyz, s_Content3D, EditorStyles.miniButton, GUILayout.Width(30));
|
||||
if (EditorGUI.EndChangeCheck() && !showXyz)
|
||||
{
|
||||
z.floatValue = y.floatValue = x.floatValue;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
return showXyz;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,10 +34,10 @@ namespace Coffee.UIExtensions
|
||||
ps.transform.SetParent(uiParticle.transform, false);
|
||||
ps.transform.localPosition = Vector3.zero;
|
||||
|
||||
// Assign default material.
|
||||
// Assign default material (UIAdditive).
|
||||
var renderer = ps.GetComponent<ParticleSystemRenderer>();
|
||||
var defaultMat = AssetDatabase.GetBuiltinExtraResource<Material>("Default-Particle.mat");
|
||||
renderer.material = defaultMat ? defaultMat : renderer.material;
|
||||
var path = AssetDatabase.GUIDToAssetPath("9944483a3e009401ba5dcc42f14d5c63");
|
||||
renderer.material = AssetDatabase.LoadAssetAtPath<Material>(path);
|
||||
|
||||
// Refresh particles.
|
||||
uiParticle.RefreshParticles();
|
||||
@@ -1,6 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67b89587ad4f645e18aa12053a6cc9b7
|
||||
AssemblyDefinitionImporter:
|
||||
guid: 7a55e246f37df405bac88eac692e3a86
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
BIN
Icons/UIParticleIcon.png
Normal file
BIN
Icons/UIParticleIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 418 B |
127
Icons/UIParticleIcon.png.meta
Normal file
127
Icons/UIParticleIcon.png.meta
Normal file
@@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f0675613942149309588d556e33d990
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 64
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,7 +1,7 @@
|
||||
Copyright 2018 mob-sakai
|
||||
Copyright 2018-2024 mob-sakai
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
545
README.md
545
README.md
@@ -1,271 +1,494 @@
|
||||
Particle Effect For UGUI (UI Particle)
|
||||
===
|
||||
# <img alt="UIParticleIcon" src="https://github.com/mob-sakai/ParticleEffectForUGUI/assets/12690315/d76e105e-a840-4f61-a1f6-8cf311c0812d" width="26"/> Particle Effect For UGUI (UI Particle)
|
||||
|
||||
**:warning: NOTE: Do not use [the obsolete tags and branches](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/108) to reference the package. They will be removed in near future. :warning:**
|
||||
|
||||
This plugin provide a component to render particle effect for uGUI in Unity 2018.2 or later.
|
||||
The particle rendering is maskable and sortable, without Camera, RenderTexture or Canvas.
|
||||
This package provides a component to render particle effects for uGUI in Unity 2018.2 or later.
|
||||
The particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.
|
||||
|
||||
[](https://openupm.com/packages/com.coffee.ui-particle/)
|
||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/releases)
|
||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/releases) [](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/master/LICENSE.txt)
|
||||
[](http://makeapullrequest.com)
|
||||

|
||||

|
||||

|
||||

|
||||
[](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/main/LICENSE.txt)
|
||||

|
||||

|
||||
[](http://makeapullrequest.com)
|
||||
[](https://twitter.com/intent/follow?screen_name=mob_sakai)
|
||||
|
||||
<< [📝 Description](#-description) | [🎮 Demo](#-demo) | [⚙ Installation](#-installation) | [🚀 Usage](#-usage) | [🛠 Development Note](#-development-note) | [🤝 Contributing](#-contributing) >>
|
||||
|
||||
<< [Description](#Description) | [Demo](#demo) | [Installation](#installation) | [Usage](#usage) | [Development Note](#development-note) | [Change log](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/upm/CHANGELOG.md) >>
|
||||
<br><br>
|
||||
|
||||
|
||||
|
||||
<br><br><br><br>
|
||||
|
||||
## Description
|
||||
## 📝 Description
|
||||
|
||||

|
||||
|
||||
This plugin uses new APIs `MeshBake/MashTrailBake` (added with Unity 2018.2) to render particles by CanvasRenderer.
|
||||
You can mask and sort particles for uGUI without Camera, RenderTexture, Canvas.
|
||||
This package utilizes the new APIs `MeshBake/MashTrailBake` (introduced with Unity 2018.2) to render particles through
|
||||
CanvasRenderer.
|
||||
You can render, mask, and sort your ParticleSystems for UI without the necessity of an additional Camera, RenderTexture,
|
||||
or Canvas.
|
||||
|
||||
Compares this "Baking mesh" approach with the conventional approach:
|
||||
(This scene is included in the package.)
|
||||
### Features
|
||||
|
||||
|Approach|Good|Bad|Screenshot|
|
||||
|-|-|-|-|
|
||||
|Baking mesh<br>**\(UIParticle\)**|Rendered as is.<br>Maskable.<br>Sortable.<br>Less objects.|**Requires Unity 2018.2 or later.**<br>Requires UI shaders to use Mask.|<img src="https://user-images.githubusercontent.com/12690315/41765089-0302b9a2-763e-11e8-88b3-b6ffa306bbb0.gif" width="500px">|
|
||||
|Do nothing|Rendered as is.|**Looks like a glitch.**<br>Not maskable.<br>Not sortable.|<img src="https://user-images.githubusercontent.com/12690315/41765090-0329828a-763e-11e8-8d8a-f1d269ea3bc7.gif" width="500px">|
|
||||
|Convert particle to UIVertex<br>[\(UIParticleSystem\)](https://forum.unity.com/threads/free-script-particle-systems-in-ui-screen-space-overlay.406862/)|Maskable.<br>Sortable.<br>Less objects.|**Adjustment is difficult.**<br>Requires UI shaders.<br>Difficult to adjust scale.<br>Force hierarchy scalling.<br>Simulation results are incorrect.<br>Trail, rotation of transform, time scaling are not supported.<br>Generate heavy GC every frame.|<img src="https://user-images.githubusercontent.com/12690315/41765088-02deb9c6-763e-11e8-98d0-9e0c1766ef39.gif" width="500px">|
|
||||
|Use Canvas to sort|Rendered as is.<br>Sortable.|**You must to manage sorting orders.**<br>Not maskable.<br>More batches.|<img src="https://user-images.githubusercontent.com/12690315/41765087-02b866ea-763e-11e8-8c33-081c9ad852f8.gif" width="500px">|
|
||||
|Use RenderTexture|Maskable.<br>Sortable.|**Requires Camera and RenderTexture.**<br>Difficult to adjust position and size.<br>Quality depends on the RenderTexture's setting.|<img src="https://user-images.githubusercontent.com/12690315/41765085-0291b3e2-763e-11e8-827b-72e5ee9bc556.gif" width="500px">|
|
||||
* Easy to use: The package is ready to use out of the box.
|
||||
* Sort particle effects and other UI by sibling index.
|
||||
* No extra Camera, RenderTexture, or Canvas required.
|
||||
* Masking options for Mask or RectMask2D.
|
||||
* Support for the Trail module.
|
||||
* Support for CanvasGroup alpha.
|
||||
* No allocations needed to render particles.
|
||||
* Compatibility with overlay, camera space, and world space.
|
||||
* Support for Universal Render Pipeline (URP) and High Definition Render Pipeline (HDRP).
|
||||
* Support for disabling `Enter Play Mode Options > Reload Domain`.
|
||||
* Support for changing material property with AnimationClip (AnimatableProperty).
|
||||
![AnimatableProperty.gif][AnimatableProperty.gif]
|
||||
* [4.0.0+] Support for 8+ materials.
|
||||
* [4.0.0+] Correct world space particle position adjustment when changing window size for standalone platforms (Windows,
|
||||
MacOSX, and Linux).
|
||||
* [4.0.0+] Adaptive scaling for UI.
|
||||
* [4.0.0+] Mesh sharing group to improve performance.
|
||||
![MeshSharing.gif][MeshSharing.gif]
|
||||
* [4.0.0+] Particle attractor component.
|
||||
![ParticleAttractor.gif][ParticleAttractor.gif]
|
||||
* [4.1.0+] Relative/Absolute particle position mode.
|
||||
![AbsolutePosition.gif][AbsolutePosition.gif]
|
||||
|
||||
[AnimatableProperty.gif]: https://user-images.githubusercontent.com/12690315/53286323-2d94a980-37b0-11e9-8afb-c4a207805ff2.gif
|
||||
|
||||
#### Features
|
||||
[MeshSharing.gif]: https://user-images.githubusercontent.com/12690315/174311048-c882df81-6c34-4eba-b0aa-5645457692f1.gif
|
||||
|
||||
* Easy to use: the package is out-of-the-box
|
||||
* Sort particle effects with UI
|
||||
* No Camera, RenderTexture or Canvas are required
|
||||
* Masking with Mask or RectMask2D
|
||||
* Support Trail module
|
||||
* Change alpha with CanvasGroup
|
||||
* No heavy allocation every frame
|
||||
* Support overlay, camera space and world space
|
||||
* Support changing material property with AnimationClip (AnimatableProperty)
|
||||

|
||||
[ParticleAttractor.gif]: https://user-images.githubusercontent.com/12690315/174311027-462929a4-13f0-4ec4-86ea-9c832f2eecf1.gif
|
||||
|
||||
[AbsolutePosition.gif]: https://user-images.githubusercontent.com/12690315/175751579-5a2357e8-2ecf-4afd-83c8-66e9771bde39.gif
|
||||
|
||||
<br><br>
|
||||
|
||||
<br><br><br><br>
|
||||
## 🎮 Demo
|
||||
|
||||
## Demo
|
||||
* [WebGL Demo](https://mob-sakai.github.io/demos/UIParticle_Demo/index.html)
|
||||
|
||||
> 
|
||||
|
||||
* [WebGL Demo](https://mob-sakai.github.io/Demos/ParticleEffectForUGUI)
|
||||
* [WebGL Demo (Cartoon FX & War FX)](https://mob-sakai.github.io/Demos/ParticleEffectForUGUI_CFX)
|
||||
* [Cartoon FX Free][CFX] & [War FX][WFX] (by [Jean Moreno (JMO)][JMO]) with UIParticle
|
||||
* [Cartoon FX Free][CFX] & [War FX][WFX] (by [Jean Moreno (JMO)][JMO]) with UIParticle
|
||||
|
||||
> 
|
||||
|
||||
[CFX]: https://assetstore.unity.com/packages/vfx/particles/cartoon-fx-free-109565
|
||||
|
||||
[WFX]: https://assetstore.unity.com/packages/vfx/particles/war-fx-5669
|
||||
|
||||
[JMO]: https://assetstore.unity.com/publishers/1669
|
||||
|
||||

|
||||
|
||||
<br><br>
|
||||
|
||||
## ⚙ Installation
|
||||
|
||||
<br><br><br><br>
|
||||
_This package requires Unity 2018.3 or later._
|
||||
|
||||
## Installation
|
||||
#### Install via OpenUPM
|
||||
|
||||
### Requirement
|
||||
This package is available on [OpenUPM](https://openupm.com) package registry.
|
||||
This is the preferred method of installation, as you can easily receive updates as they're released.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
If you have [openupm-cli](https://github.com/openupm/openupm-cli) installed, then run the following command in your
|
||||
project's directory:
|
||||
|
||||
### Using OpenUPM
|
||||
|
||||
This package is available on [OpenUPM](https://openupm.com).
|
||||
You can install it via [openupm-cli](https://github.com/openupm/openupm-cli).
|
||||
```
|
||||
```sh
|
||||
openupm add com.coffee.ui-particle
|
||||
```
|
||||
|
||||
### Using Git
|
||||
#### Install via UPM (using Git URL)
|
||||
|
||||
Find the manifest.json file in the Packages folder of your project and add a line to `dependencies` field.
|
||||
Navigate to your project's Packages folder and open the `manifest.json` file. Then add this package somewhere in
|
||||
the `dependencies` block:
|
||||
|
||||
* Major version: 
|
||||
`"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git"`
|
||||
* Preview version: 
|
||||
`"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#preview"`
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To update the package, change suffix `#{version}` to the target version.
|
||||
|
||||
* e.g. `"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#3.0.0",`
|
||||
* e.g. `"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.6.0",`
|
||||
|
||||
Or, use [UpmGitExtension](https://github.com/mob-sakai/UpmGitExtension) to install and update the package.
|
||||
|
||||
### For Unity 2018.2
|
||||
<br><br>
|
||||
|
||||
Unity 2018.2 supports embedded packages.
|
||||
## ⚙ Upgrading from 3.x/4.x to 5.x
|
||||
|
||||
1. Download a source code zip file from [Releases](https://github.com/mob-sakai/ParticleEffectForUGUI/releases) page
|
||||
2. Extract it
|
||||
3. Import it under `Packages` directory in your Unity project
|
||||
### Breaking Changes
|
||||
|
||||
|
||||
|
||||
<br><br><br><br>
|
||||
|
||||
## How to play demo
|
||||
|
||||
### For Unity 2019.1 or later
|
||||
|
||||
1. Open `Package Manager` window
|
||||
2. Select `UI Particle` package in package list
|
||||
3. Click `Import Sample` button
|
||||

|
||||
4. The demo project is imported into `Assets/Samples/UI Particle/{version}/Demo`
|
||||
5. Open `UIParticle_Demo` scene and play it
|
||||
|
||||
### For Unity 2018.4 or earlier
|
||||
|
||||
1. Select `Assets/Samples/UI Particle Demo` from menu
|
||||
2. The demo project is imported into `Assets/Samples/UI Particle/{version}/Demo`
|
||||
3. Open `UIParticle_Demo` scene and play it
|
||||
|
||||
### About `Cartoon FX & War Fx Demo`
|
||||
|
||||
* It requires free assets ([Cartoon FX Free][CFX] & [War FX][WFX])
|
||||
* by [Jean Moreno (JMO)][JMO]
|
||||
|
||||
|
||||
|
||||
<br><br><br><br>
|
||||
|
||||
## Usage
|
||||
|
||||
### UIParticle component
|
||||
|
||||
`UIParticle` controls the ParticleSystems that is attached to its own game objects and child game objects.
|
||||
|
||||
| Properties | Screenshot |
|
||||
| -- | -- |
|
||||
| **Ignore Canvas Scale:** Ignore the scale of the root canvas. This prevents it from displaying small even in hierarchy scaling mode of ParticleSystem. <br>**Scale:** Scale the rendering. When the `3D` toggle is enabled, 3D scale (x,y,z) is supported. <br>**AnimatableProperties:** If you want update material properties (e.g. `_MainTex_ST`, `_Color`) in AnimationClip, use this to mark the changes. <br>**Rendering Order:** The ParticleSystems to be rendered. You can change the rendering order and the materials. | ![][inspector] |
|
||||
|
||||
[inspector]:https://user-images.githubusercontent.com/12690315/95017219-1cea2c00-0693-11eb-9490-c52b8d0fdbb6.png
|
||||
|
||||
NOTE: Press `Refresh` button to reconstruct rendering order based on children ParticleSystem's sorting order and z position.
|
||||
- The default value of `UIParticle.scale` has been changed from `10` to `1`.
|
||||
- `UIParticle` no longer inherits from `MaskableGraphic`.
|
||||
-
|
||||
|
||||
<br><br>
|
||||
|
||||
### Basically usage
|
||||
## 🚀 Usage
|
||||
|
||||
1. Select `Game Object/UI/ParticleSystem` to create UIParticle with a ParticleSystem.
|
||||

|
||||
2. Adjust the ParticleSystem as you like.
|
||||

|
||||
### UIParticle Component
|
||||
|
||||
`UIParticle` controls the ParticleSystems that are attached to its own game objects and child game objects.
|
||||
|
||||

|
||||
|
||||
- **Maskable**: Does this graphic allow masking.
|
||||
- **Scale**: Scale the rendering. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.
|
||||
- **Animatable Properties**: If you want to update material properties (e.g., `_MainTex_ST`, `_Color`) in AnimationClip,
|
||||
use this to mark the changes.
|
||||
- **Mesh Sharing**: Particle simulation results are shared within the same group. A large number of the same effects can
|
||||
be displayed with a small load. When the `Random` toggle is enabled, it will be grouped randomly.
|
||||
- **Position Mode**: Emission position mode.
|
||||
- **Absolute:** Emit from the world position of the `ParticleSystem`.
|
||||
- **Relative:** Emit from the scaled position of the `ParticleSystem`.
|
||||
- **Auto Scaling**: `Transform.lossyScale` (=world scale) will be set to `(1, 1, 1)` on update. It prevents the
|
||||
root-Canvas scale from affecting the hierarchy-scaled `ParticleSystem`.
|
||||
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
||||
|
||||
**NOTE:** Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
||||
and z-position.
|
||||
|
||||
<br><br>
|
||||
|
||||
### With your ParticleSystem prefab
|
||||
#### Basic Usage
|
||||
|
||||
1. Select `Game Object/UI/ParticleSystem (Empty)` to create UIParticle.
|
||||

|
||||
2. Drag & drop your ParticleSystem prefab on UIParticle.
|
||||

|
||||
1. Select `GameObject/UI/ParticleSystem` to create UIParticle with a ParticleSystem.
|
||||

|
||||
2. Adjust the ParticleSystem as you like.
|
||||

|
||||
|
||||
<br><br>
|
||||
<br>
|
||||
|
||||
### With `Mask` or `MaskRect2D` component
|
||||
#### With Your Existing ParticleSystem Prefab
|
||||
|
||||
If you want to mask particles, set a stencil supported shader (such as `UI/UIAdditive`) to material for ParticleSystem.
|
||||
1. Select `GameObject/UI/ParticleSystem (Empty)` to create UIParticle.
|
||||

|
||||
2. Drag and drop your ParticleSystem prefab onto UIParticle.
|
||||

|
||||
|
||||
<br>
|
||||
|
||||
#### With `Mask` or `RectMask2D` Component
|
||||
|
||||
If you want to mask particles, set a stencil-supported shader (such as `UI/UIAdditive`) to the material for
|
||||
ParticleSystem.
|
||||
If you use some custom shaders, see
|
||||
the [How to Make a Custom Shader to Support Mask/RectMask2D Component](#how-to-make-a-custom-shader-to-support-maskrectmask2d-component)
|
||||
section.
|
||||
|
||||

|
||||
|
||||
|
||||
<br><br>
|
||||
|
||||
### Script usage
|
||||
|
||||
```cs
|
||||
// Instant ParticleSystem prefab with UIParticle on runtime.
|
||||
// Instantiate ParticleSystem prefab with UIParticle on runtime.
|
||||
var go = GameObject.Instantiate(prefab);
|
||||
var uiParticle = go.AddComponent<UIParticle>();
|
||||
uiParticle.scale = 100;
|
||||
|
||||
// Play/Stop the controled ParticleSystems.
|
||||
// Control by ParticleSystem.
|
||||
particleSystem.Play();
|
||||
particleSystem.Emit(10);
|
||||
|
||||
// Control by UIParticle.
|
||||
uiParticle.Play();
|
||||
uiParticle.Stop();
|
||||
```
|
||||
|
||||
<br><br><br><br>
|
||||
<br><br>
|
||||
|
||||
## Development Note
|
||||
### UIParticleAttractor component
|
||||
|
||||
### Animatable material property
|
||||
`UIParticleAttractor` attracts particles generated by the specified ParticleSystem.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
Animation clips can change the material properties of the Renderer, such as ParticleSystemRenderer.
|
||||
It uses MaterialPropertyBlock so it does not create new material instances.
|
||||
Using material properties, you can change UV animation, scale and color etc.
|
||||
- **Particle System**: Attracts particles generated by the specified particle system.
|
||||
- **Destination Radius**: Once the particle is within the radius, the particle lifetime will become 0, and `OnAttracted`
|
||||
will be called.
|
||||
- **Delay Rate**: Delay to start attracting. It is a percentage of the particle's start lifetime.
|
||||
- **Max Speed**: Maximum speed of attracting. If this value is too small, attracting may not be completed by the end of
|
||||
the lifetime, and `OnAttracted` may not be called.
|
||||
- **Movement**: Attracting movement type. (`Linear`, `Smooth`, `Sphere`)
|
||||
- **Update Mode**: Update mode.
|
||||
- **Normal:** Update with scaled delta time.
|
||||
- **Unscaled Time:** Update with unscaled delta time.
|
||||
- **OnAttracted**: An event called when attracting is complete (per particle).
|
||||
|
||||
Well, there is a component called CanvasRenderer.
|
||||
It is used by all Graphic components for UI (Text, Image, Raw Image, etc.) including UIParticle.
|
||||
However, It is **NOT** a Renderer.
|
||||
Therefore, in UIParticle, changing ParticleSystemRenderer's MaterialPropertyBlock by animation clip is ignored.
|
||||
<br><br>
|
||||
|
||||
To prevent this, Use "Animatable Material Property".
|
||||
"Animatable Material Property" gets the necessary properties from ParticleSystemRenderer's MaterialPropertyBlock and sets them to the CanvasRenderer's material.
|
||||
## 🛠 Development Note
|
||||
|
||||
### Compares the Baking mesh approach with the conventional approach
|
||||
|
||||
- **Baking mesh approach (=UIParticle)**
|
||||

|
||||
- ✅ Rendered as is.
|
||||
- ✅ Maskable.
|
||||
- ✅ Sortable.
|
||||
- ✅ Less objects.
|
||||
|
||||
<br><br><br><br>
|
||||
- **Do nothing (=Plain ParticleSystem)**
|
||||

|
||||
- ✅ Rendered as is.
|
||||
- ❌ Looks like a glitch.
|
||||
- ❌ Not maskable.
|
||||
- ❌ Not sortable.
|
||||
|
||||
## Contributing
|
||||
- **Convert particle to UIVertex (=[UIParticleSystem][UIParticleSystem])**
|
||||

|
||||
- ✅ Maskable.
|
||||
- ✅ Sortable.
|
||||
- ❌ Adjustment is difficult.
|
||||
- ❌ Requires UI shaders.
|
||||
- ❌ Difficult to adjust scale.
|
||||
- ❌ Force hierarchy scalling.
|
||||
- ❌ Simulation results are incorrect.
|
||||
- ❌ Trail, rotation of transform, time scaling are not supported.
|
||||
- ❌ Generate heavy GC every frame.
|
||||
|
||||
- **Use Canvas to sort (Sorting By Canvas )**
|
||||

|
||||
- ✅ Rendered as is.
|
||||
- ✅ Sortable.
|
||||
- ❌ You must to manage sorting orders.
|
||||
- ❌ Not maskable.
|
||||
- ❌ More batches.
|
||||
- ❌ Requires Canvas.
|
||||
|
||||
- **Use RenderTexture**
|
||||

|
||||
- ✅ Maskable.
|
||||
- ✅ Sortable.
|
||||
- ❌ Requires Camera and RenderTexture.
|
||||
- ❌ Difficult to adjust position and size.
|
||||
- ❌ Quality depends on the RenderTexture's setting.
|
||||
|
||||
[UIParticleSystem]: https://forum.unity.com/threads/free-script-particle-systems-in-ui-screen-space-overlay.406862/
|
||||
|
||||
#### [Performance test results](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/193#issuecomment-1160028374)
|
||||
|
||||
| Approach | FPS on Editor | FPS on iPhone6 | FPS on Xperia XZ |
|
||||
|-----------------------------|---------------|----------------|------------------|
|
||||
| Particle System | 43 | 57 | 22 |
|
||||
| UIParticleSystem | 4 | 3 | 0 (unmeasurable) |
|
||||
| Sorting By Canvas | 43 | 44 | 18 |
|
||||
| UIParticle | 17 | 12 | 4 |
|
||||
| UIParticle with MeshSharing | 44 | 45 | 30 |
|
||||
|
||||
### 🔍 FAQ: Why Are My UIParticles Not Displayed Correctly?
|
||||
|
||||
If `ParticleSystem` alone displays particles correctly but `UIParticle` does not, please check the following points:
|
||||
|
||||
- [Shader Limitation](#shader-limitation)
|
||||
- `UIParticle` does not support all built-in shaders except for `UI/Default`.
|
||||
- Most cases can be solved by using `UI/Additive` or `UI/Default`.
|
||||
- Particles are not masked
|
||||
- `UIParticle` is maskable.
|
||||
- Set `Mask` or `RectMask2D` component properly.
|
||||
- [Use maskable/clipable shader](#how-to-make-a-custom-shader-to-support-maskrectmask2d-component) (such
|
||||
as `UI/Additive` or `UI/Default`)
|
||||
- Particles are too small
|
||||
- If particles are small enough, they will not appear on the screen.
|
||||
- Increase the `Scale` value.
|
||||
- If you don't want to change the apparent size depending on the resolution, try the `Auto Scaling` option.
|
||||
- Particles are too many
|
||||
- No more than 65535 vertices can be displayed (for mesh combination limitations).
|
||||
- Please set `Emission` module and `Max Particles` of ParticleSystem properly.
|
||||
- Particles are emitted off-screen.
|
||||
- When `Position Mode = Relative`, particles are emitted from the scaled position of the ParticleSystem, not from
|
||||
the screen point of the ParticleSystem.
|
||||
- Place the ParticleSystem in the proper position or try `Position Mode = Absolute`.
|
||||
- Attaching `UIParticle` to the same object as `ParticleSystem`
|
||||
- `Transform.localScale` will be overridden by the `Auto Scaling` option.
|
||||
- It is recommended to place `ParticleSystem` under `UIParticle`.
|
||||
- If `Transform.localScale` contains 0, rendering will be skipped.
|
||||
- Displayed particles are in the correct position but too large/too small
|
||||
- Adjust `ParticleSystem.renderer.Min/MaxParticleSize`.
|
||||
|
||||
<br>
|
||||
|
||||
### Shader Limitation
|
||||
|
||||
The use of UI shaders is recommended.
|
||||
|
||||
- If you need a simple Additive shader, use the `UI/Additive` shader instead.
|
||||
- If you need a simple alpha-blend shader, use the `UI/Default` shader instead.
|
||||
- If your custom shader does not work properly with UIParticle, consider creating a custom UI shader.
|
||||
|
||||
#### Built-in shaders are not supported
|
||||
|
||||
`UIParticle` does not support all built-in shaders except for `UI/Default`.
|
||||
If their use is detected, an error is displayed in the inspector.
|
||||
Use UI shaders instead.
|
||||
|
||||
#### (Unity 2018 or 2019) UV.zw components will be discarded
|
||||
|
||||
UIParticleRenderer renders the particles based on UIVertex.
|
||||
Therefore, only the xy components are available for each UV in the shader. (zw components will be discarded).
|
||||
So unfortunately, UIParticles will not work well with some shaders.
|
||||
|
||||
#### (Unity 2018 or 2019) Custom vertex streams
|
||||
|
||||
When using custom vertex streams, you can fill zw components with "unnecessary" data.
|
||||
Refer to [this issue](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/191) for more information.
|
||||
|
||||
<br>
|
||||
|
||||
### Overheads
|
||||
|
||||
UIParticle has some overheads, and the batching depends on uGUI.
|
||||
When improving performance, keep the following in mind:
|
||||
|
||||
- If you are displaying a large number of the same effect, consider the `Mesh Sharing` feature in
|
||||
the [UIParticle Component](#uiparticle-component).
|
||||
- If you don't like the uniform output, consider the `Random Group` feature.
|
||||

|
||||
- If you are using multiple materials, you will have more draw calls.
|
||||
- Consider a single material, atlasing the sprites, and using `Sprite` mode in the `Texture Sheet Animation` module
|
||||
in the ParticleSystem.
|
||||
|
||||
### How to Make a Custom Shader to Support Mask/RectMask2D Component
|
||||
|
||||
<details>
|
||||
<summary>Shader tips</summary>
|
||||
|
||||
```ShaderLab
|
||||
Shader "Your/Custom/Shader"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
// ...
|
||||
// #### required for Mask ####
|
||||
_StencilComp ("Stencil Comparison", Float) = 8
|
||||
_Stencil ("Stencil ID", Float) = 0
|
||||
_StencilOp ("Stencil Operation", Float) = 0
|
||||
_StencilWriteMask ("Stencil Write Mask", Float) = 255
|
||||
_StencilReadMask ("Stencil Read Mask", Float) = 255
|
||||
_ColorMask ("Color Mask", Float) = 15
|
||||
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
// #### required for Mask ####
|
||||
Stencil
|
||||
{
|
||||
Ref [_Stencil]
|
||||
Comp [_StencilComp]
|
||||
Pass [_StencilOp]
|
||||
ReadMask [_StencilReadMask]
|
||||
WriteMask [_StencilWriteMask]
|
||||
}
|
||||
ColorMask [_ColorMask]
|
||||
// ...
|
||||
|
||||
Pass
|
||||
{
|
||||
// ...
|
||||
// #### required for RectMask2D ####
|
||||
#include "UnityUI.cginc"
|
||||
#pragma multi_compile __ UNITY_UI_CLIP_RECT
|
||||
float4 _ClipRect;
|
||||
|
||||
// #### required for Mask ####
|
||||
#pragma multi_compile __ UNITY_UI_ALPHACLIP
|
||||
|
||||
struct appdata_t
|
||||
{
|
||||
// ...
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
// ...
|
||||
// #### required for RectMask2D ####
|
||||
float4 worldPosition : TEXCOORD1;
|
||||
};
|
||||
|
||||
v2f vert(appdata_t v)
|
||||
{
|
||||
v2f OUT;
|
||||
// ...
|
||||
// #### required for RectMask2D ####
|
||||
OUT.worldPosition = v.vertex;
|
||||
return OUT;
|
||||
}
|
||||
|
||||
fixed4 frag(v2f IN) : SV_Target
|
||||
{
|
||||
// ...
|
||||
// #### required for RectMask2D ####
|
||||
#ifdef UNITY_UI_CLIP_RECT
|
||||
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
|
||||
#endif
|
||||
|
||||
// #### required for Mask ####
|
||||
#ifdef UNITY_UI_ALPHACLIP
|
||||
clip (color.a - 0.001);
|
||||
#endif
|
||||
|
||||
return color;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<br><br>
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
### Issues
|
||||
|
||||
Issues are very valuable to this project.
|
||||
Issues are incredibly valuable to this project:
|
||||
|
||||
- Ideas are a valuable source of contributions others can make
|
||||
- Problems show where this project is lacking
|
||||
- With a question you show where contributors can improve the user experience
|
||||
- Ideas provide a valuable source of contributions that others can make.
|
||||
- Problems help identify areas where this project needs improvement.
|
||||
- Questions indicate where contributors can enhance the user experience.
|
||||
|
||||
### Pull Requests
|
||||
|
||||
Pull requests are, a great way to get your ideas into this repository.
|
||||
See [CONTRIBUTING.md](/../../blob/develop/CONTRIBUTING.md).
|
||||
Pull requests offer a fantastic way to contribute your ideas to this repository.
|
||||
Please refer to [CONTRIBUTING.md](https://github.com/mob-sakai/ParticleEffectForUGUI/blob/main/CONTRIBUTING.md)
|
||||
and [develop branch](https://github.com/mob-sakai/ParticleEffectForUGUI/tree/develop) for guidelines.
|
||||
|
||||
### Support
|
||||
|
||||
This is an open source project that I am developing in my spare time.
|
||||
If you like it, please support me.
|
||||
With your support, I can spend more time on development. :)
|
||||
This is an open-source project developed during my spare time.
|
||||
If you appreciate it, consider supporting me.
|
||||
Your support allows me to dedicate more time to development. 😊
|
||||
|
||||
[](https://www.patreon.com/join/mob_sakai?)
|
||||
[](https://www.patreon.com/join/2343451?)
|
||||
[](https://github.com/users/mob-sakai/sponsorship)
|
||||
|
||||
|
||||
|
||||
<br><br><br><br>
|
||||
<br><br>
|
||||
|
||||
## License
|
||||
|
||||
* MIT
|
||||
|
||||
|
||||
|
||||
## Author
|
||||
|
||||
*  [mob-sakai](https://github.com/mob-sakai) [](https://twitter.com/intent/follow?screen_name=mob_sakai) 
|
||||
|
||||
|
||||
|
||||
## See Also
|
||||
|
||||
* GitHub page : https://github.com/mob-sakai/ParticleEffectForUGUI
|
||||
* Releases : https://github.com/mob-sakai/ParticleEffectForUGUI/releases
|
||||
* Issue tracker : https://github.com/mob-sakai/ParticleEffectForUGUI/issues
|
||||
* Change log : https://github.com/mob-sakai/ParticleEffectForUGUI/blob/upm/CHANGELOG.md
|
||||
* Change log : https://github.com/mob-sakai/ParticleEffectForUGUI/blob/main/CHANGELOG.md
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
[System.Serializable]
|
||||
[Serializable]
|
||||
public class AnimatableProperty : ISerializationCallbackReceiver
|
||||
{
|
||||
public enum ShaderPropertyType
|
||||
@@ -11,16 +12,22 @@ namespace Coffee.UIExtensions
|
||||
Vector,
|
||||
Float,
|
||||
Range,
|
||||
Texture,
|
||||
Texture
|
||||
}
|
||||
|
||||
[SerializeField] string m_Name = "";
|
||||
[SerializeField] ShaderPropertyType m_Type = ShaderPropertyType.Vector;
|
||||
[SerializeField] private string m_Name = "";
|
||||
[SerializeField] private ShaderPropertyType m_Type = ShaderPropertyType.Vector;
|
||||
public int id { get; private set; }
|
||||
|
||||
public ShaderPropertyType type
|
||||
public ShaderPropertyType type => m_Type;
|
||||
|
||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||
{
|
||||
get { return m_Type; }
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||
{
|
||||
id = Shader.PropertyToID(m_Name);
|
||||
}
|
||||
|
||||
public void UpdateMaterialProperties(Material material, MaterialPropertyBlock mpb)
|
||||
@@ -31,35 +38,38 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
case ShaderPropertyType.Color:
|
||||
var color = mpb.GetColor(id);
|
||||
if (color != default(Color))
|
||||
if (color != default)
|
||||
{
|
||||
material.SetColor(id, color);
|
||||
}
|
||||
|
||||
break;
|
||||
case ShaderPropertyType.Vector:
|
||||
var vector = mpb.GetVector(id);
|
||||
if (vector != default(Vector4))
|
||||
if (vector != default)
|
||||
{
|
||||
material.SetVector(id, vector);
|
||||
}
|
||||
|
||||
break;
|
||||
case ShaderPropertyType.Float:
|
||||
case ShaderPropertyType.Range:
|
||||
var value = mpb.GetFloat(id);
|
||||
if (value != default(float))
|
||||
if (!Mathf.Approximately(value, 0))
|
||||
{
|
||||
material.SetFloat(id, value);
|
||||
}
|
||||
|
||||
break;
|
||||
case ShaderPropertyType.Texture:
|
||||
var tex = mpb.GetTexture(id);
|
||||
if (tex != default(Texture))
|
||||
{
|
||||
material.SetTexture(id, tex);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBeforeSerialize()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
id = Shader.PropertyToID(m_Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f3407e8e4c3c4cf0a8717c25bc1c790
|
||||
TextScriptImporter:
|
||||
guid: 53aa3f36032944b3fb1455e774c52396
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
8
Runtime/Internal/Extensions.meta
Normal file
8
Runtime/Internal/Extensions.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8cf8018dee45a4c42a19eec890eaa5b1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
134
Runtime/Internal/Extensions/CanvasExtensions.cs
Normal file
134
Runtime/Internal/Extensions/CanvasExtensions.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
#if UNITY_2021_3_0 || UNITY_2021_3_1 || UNITY_2021_3_2 || UNITY_2021_3_3 || UNITY_2021_3_4 || UNITY_2021_3_5 || UNITY_2021_3_6 || UNITY_2021_3_7 || UNITY_2021_3_8 || UNITY_2021_3_9
|
||||
#elif UNITY_2021_3_10 || UNITY_2021_3_11 || UNITY_2021_3_12 || UNITY_2021_3_13 || UNITY_2021_3_14 || UNITY_2021_3_15 || UNITY_2021_3_16 || UNITY_2021_3_17 || UNITY_2021_3_18 || UNITY_2021_3_19
|
||||
#elif UNITY_2021_3_20 || UNITY_2021_3_21 || UNITY_2021_3_22 || UNITY_2021_3_23 || UNITY_2021_3_24 || UNITY_2021_3_25 || UNITY_2021_3_26 || UNITY_2021_3_27 || UNITY_2021_3_28 || UNITY_2021_3_29
|
||||
#elif UNITY_2021_3_30 || UNITY_2021_3_31 || UNITY_2021_3_32 || UNITY_2021_3_33
|
||||
#elif UNITY_2022_2_0 || UNITY_2022_2_1 || UNITY_2022_2_2 || UNITY_2022_2_3 || UNITY_2022_2_4 || UNITY_2022_2_5 || UNITY_2022_2_6 || UNITY_2022_2_7 || UNITY_2022_2_8 || UNITY_2022_2_9
|
||||
#elif UNITY_2022_2_10 || UNITY_2022_2_11 || UNITY_2022_2_12 || UNITY_2022_2_13 || UNITY_2022_2_14
|
||||
#elif UNITY_2021_3 || UNITY_2022_2 || UNITY_2022_3 || UNITY_2023_2_OR_NEWER
|
||||
#define CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||
#endif
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
#if UNITY_MODULE_VR
|
||||
using UnityEngine.XR;
|
||||
#endif
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class CanvasExtensions
|
||||
{
|
||||
public static bool ShouldGammaToLinearInShader(this Canvas canvas)
|
||||
{
|
||||
return QualitySettings.activeColorSpace == ColorSpace.Linear &&
|
||||
#if CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||
canvas.vertexColorAlwaysGammaSpace;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool ShouldGammaToLinearInMesh(this Canvas canvas)
|
||||
{
|
||||
return QualitySettings.activeColorSpace == ColorSpace.Linear &&
|
||||
#if CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||
!canvas.vertexColorAlwaysGammaSpace;
|
||||
#else
|
||||
true;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool IsStereoCanvas(this Canvas canvas)
|
||||
{
|
||||
#if UNITY_MODULE_VR
|
||||
if (FrameCache.TryGet<bool>(canvas, nameof(IsStereoCanvas), out var stereo)) return stereo;
|
||||
|
||||
stereo =
|
||||
canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay && canvas.worldCamera != null
|
||||
&& XRSettings.enabled && !string.IsNullOrEmpty(XRSettings.loadedDeviceName);
|
||||
FrameCache.Set(canvas, nameof(IsStereoCanvas), stereo);
|
||||
return stereo;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view-projection matrix for a Canvas.
|
||||
/// </summary>
|
||||
public static void GetViewProjectionMatrix(this Canvas canvas, out Matrix4x4 vpMatrix)
|
||||
{
|
||||
canvas.GetViewProjectionMatrix(Camera.MonoOrStereoscopicEye.Mono, out vpMatrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view-projection matrix for a Canvas.
|
||||
/// </summary>
|
||||
public static void GetViewProjectionMatrix(this Canvas canvas, Camera.MonoOrStereoscopicEye eye,
|
||||
out Matrix4x4 vpMatrix)
|
||||
{
|
||||
if (FrameCache.TryGet(canvas, nameof(GetViewProjectionMatrix), out vpMatrix)) return;
|
||||
|
||||
canvas.GetViewProjectionMatrix(eye, out var viewMatrix, out var projectionMatrix);
|
||||
vpMatrix = viewMatrix * projectionMatrix;
|
||||
FrameCache.Set(canvas, nameof(GetViewProjectionMatrix), vpMatrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view and projection matrices for a Canvas.
|
||||
/// </summary>
|
||||
public static void GetViewProjectionMatrix(this Canvas canvas, out Matrix4x4 vMatrix, out Matrix4x4 pMatrix)
|
||||
{
|
||||
canvas.GetViewProjectionMatrix(Camera.MonoOrStereoscopicEye.Mono, out vMatrix, out pMatrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view and projection matrices for a Canvas.
|
||||
/// </summary>
|
||||
public static void GetViewProjectionMatrix(this Canvas canvas, Camera.MonoOrStereoscopicEye eye,
|
||||
out Matrix4x4 vMatrix, out Matrix4x4 pMatrix)
|
||||
{
|
||||
if (FrameCache.TryGet(canvas, "GetViewMatrix", (int)eye, out vMatrix) &&
|
||||
FrameCache.TryGet(canvas, "GetProjectionMatrix", (int)eye, out pMatrix))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get view and projection matrices.
|
||||
Profiler.BeginSample("(COF)[CanvasExt] GetViewProjectionMatrix");
|
||||
var rootCanvas = canvas.rootCanvas;
|
||||
var cam = rootCanvas.worldCamera;
|
||||
if (rootCanvas && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay && cam)
|
||||
{
|
||||
if (eye == Camera.MonoOrStereoscopicEye.Mono)
|
||||
{
|
||||
vMatrix = cam.worldToCameraMatrix;
|
||||
pMatrix = GL.GetGPUProjectionMatrix(cam.projectionMatrix, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
pMatrix = cam.GetStereoProjectionMatrix((Camera.StereoscopicEye)eye);
|
||||
vMatrix = cam.GetStereoViewMatrix((Camera.StereoscopicEye)eye);
|
||||
pMatrix = GL.GetGPUProjectionMatrix(pMatrix, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var pos = rootCanvas.transform.position;
|
||||
vMatrix = Matrix4x4.TRS(
|
||||
new Vector3(-pos.x, -pos.y, -1000),
|
||||
Quaternion.identity,
|
||||
new Vector3(1, 1, -1f));
|
||||
pMatrix = Matrix4x4.TRS(
|
||||
new Vector3(0, 0, -1),
|
||||
Quaternion.identity,
|
||||
new Vector3(1 / pos.x, 1 / pos.y, -2 / 10000f));
|
||||
}
|
||||
|
||||
FrameCache.Set(canvas, "GetViewMatrix", (int)eye, vMatrix);
|
||||
FrameCache.Set(canvas, "GetProjectionMatrix", (int)eye, pMatrix);
|
||||
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5f85388e938d9e4599afc6d9441ed57
|
||||
guid: 9dd767b8c0f95478386e7d5079cd44df
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
77
Runtime/Internal/Extensions/Color32Extensions.cs
Normal file
77
Runtime/Internal/Extensions/Color32Extensions.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class Color32Extensions
|
||||
{
|
||||
private static readonly List<Color32> s_Colors = new List<Color32>();
|
||||
private static byte[] s_LinearToGammaLut;
|
||||
private static byte[] s_GammaToLinearLut;
|
||||
|
||||
public static byte LinearToGamma(this byte self)
|
||||
{
|
||||
if (s_LinearToGammaLut == null)
|
||||
{
|
||||
s_LinearToGammaLut = new byte[256];
|
||||
for (var i = 0; i < 256; i++)
|
||||
{
|
||||
s_LinearToGammaLut[i] = (byte)(Mathf.LinearToGammaSpace(i / 255f) * 255f);
|
||||
}
|
||||
}
|
||||
|
||||
return s_LinearToGammaLut[self];
|
||||
}
|
||||
|
||||
public static byte GammaToLinear(this byte self)
|
||||
{
|
||||
if (s_GammaToLinearLut == null)
|
||||
{
|
||||
s_GammaToLinearLut = new byte[256];
|
||||
for (var i = 0; i < 256; i++)
|
||||
{
|
||||
s_GammaToLinearLut[i] = (byte)(Mathf.GammaToLinearSpace(i / 255f) * 255f);
|
||||
}
|
||||
}
|
||||
|
||||
return s_GammaToLinearLut[self];
|
||||
}
|
||||
|
||||
public static void LinearToGamma(this Mesh self)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[ColorExt] LinearToGamma (Mesh)");
|
||||
self.GetColors(s_Colors);
|
||||
var count = s_Colors.Count;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var c = s_Colors[i];
|
||||
c.r = c.r.LinearToGamma();
|
||||
c.g = c.g.LinearToGamma();
|
||||
c.b = c.b.LinearToGamma();
|
||||
s_Colors[i] = c;
|
||||
}
|
||||
|
||||
self.SetColors(s_Colors);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
public static void GammaToLinear(this Mesh self)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[ColorExt] GammaToLinear (Mesh)");
|
||||
self.GetColors(s_Colors);
|
||||
var count = s_Colors.Count;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var c = s_Colors[i];
|
||||
c.r = c.r.GammaToLinear();
|
||||
c.g = c.g.GammaToLinear();
|
||||
c.b = c.b.GammaToLinear();
|
||||
s_Colors[i] = c;
|
||||
}
|
||||
|
||||
self.SetColors(s_Colors);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a845100b226da488ab9037ad254b5860
|
||||
guid: 0ef431b9df32c410ea5fa46be81def6b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
198
Runtime/Internal/Extensions/ComponentExtensions.cs
Normal file
198
Runtime/Internal/Extensions/ComponentExtensions.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for Component class.
|
||||
/// </summary>
|
||||
internal static class ComponentExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
||||
/// </summary>
|
||||
public static T[] GetComponentsInChildren<T>(this Component self, int depth)
|
||||
where T : Component
|
||||
{
|
||||
var results = ListPool<T>.Rent();
|
||||
self.GetComponentsInChildren_Internal(results, depth);
|
||||
var array = results.ToArray();
|
||||
ListPool<T>.Return(ref results);
|
||||
return array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
||||
/// </summary>
|
||||
public static void GetComponentsInChildren<T>(this Component self, List<T> results, int depth)
|
||||
where T : Component
|
||||
{
|
||||
results.Clear();
|
||||
self.GetComponentsInChildren_Internal(results, depth);
|
||||
}
|
||||
|
||||
private static void GetComponentsInChildren_Internal<T>(this Component self, List<T> results, int depth)
|
||||
where T : Component
|
||||
{
|
||||
if (!self || results == null || depth < 0) return;
|
||||
|
||||
var tr = self.transform;
|
||||
if (tr.TryGetComponent<T>(out var t))
|
||||
{
|
||||
results.Add(t);
|
||||
}
|
||||
|
||||
if (depth - 1 < 0) return;
|
||||
var childCount = tr.childCount;
|
||||
for (var i = 0; i < childCount; i++)
|
||||
{
|
||||
tr.GetChild(i).GetComponentsInChildren(results, depth - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or add a component of a specific type to a GameObject.
|
||||
/// </summary>
|
||||
public static T GetOrAddComponent<T>(this Component self) where T : Component
|
||||
{
|
||||
if (!self) return null;
|
||||
return self.TryGetComponent<T>(out var component)
|
||||
? component
|
||||
: self.gameObject.AddComponent<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the root component of a specific type in the hierarchy of a GameObject.
|
||||
/// </summary>
|
||||
public static T GetRootComponent<T>(this Component self) where T : Component
|
||||
{
|
||||
T component = null;
|
||||
var transform = self.transform;
|
||||
while (transform)
|
||||
{
|
||||
if (transform.TryGetComponent<T>(out var c))
|
||||
{
|
||||
component = c;
|
||||
}
|
||||
|
||||
transform = transform.parent;
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a component of a specific type in the parent hierarchy of a GameObject.
|
||||
/// </summary>
|
||||
public static T GetComponentInParent<T>(this Component self, bool includeSelf, Transform stopAfter,
|
||||
Predicate<T> valid)
|
||||
where T : Component
|
||||
{
|
||||
var tr = includeSelf ? self.transform : self.transform.parent;
|
||||
while (tr)
|
||||
{
|
||||
if (tr.TryGetComponent<T>(out var c) && valid(c)) return c;
|
||||
if (tr == stopAfter) return null;
|
||||
tr = tr.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a component of a specific type to the children of a GameObject.
|
||||
/// </summary>
|
||||
public static void AddComponentOnChildren<T>(this Component self, HideFlags hideFlags, bool includeSelf)
|
||||
where T : Component
|
||||
{
|
||||
if (self == null) return;
|
||||
|
||||
Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Self");
|
||||
if (includeSelf && !self.TryGetComponent<T>(out _))
|
||||
{
|
||||
var c = self.gameObject.AddComponent<T>();
|
||||
c.hideFlags = hideFlags;
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Child");
|
||||
var childCount = self.transform.childCount;
|
||||
for (var i = 0; i < childCount; i++)
|
||||
{
|
||||
var child = self.transform.GetChild(i);
|
||||
if (child.TryGetComponent<T>(out _)) continue;
|
||||
|
||||
var c = child.gameObject.AddComponent<T>();
|
||||
c.hideFlags = hideFlags;
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
#if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48
|
||||
public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
|
||||
{
|
||||
if (!self) return null;
|
||||
if (!includeInactive) return self.GetComponentInParent<T>();
|
||||
|
||||
var current = self.transform;
|
||||
while (current)
|
||||
{
|
||||
if (current.TryGetComponent<T>(out var c)) return c;
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Verify whether it can be converted to the specified component.
|
||||
/// </summary>
|
||||
internal static bool CanConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||
{
|
||||
return context && context.GetType() != typeof(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert to the specified component.
|
||||
/// </summary>
|
||||
internal static void ConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||
{
|
||||
var target = context as MonoBehaviour;
|
||||
if (target == null) return;
|
||||
|
||||
var so = new SerializedObject(target);
|
||||
so.Update();
|
||||
|
||||
var oldEnable = target.enabled;
|
||||
target.enabled = false;
|
||||
|
||||
// Find MonoScript of the specified component.
|
||||
foreach (var script in Resources.FindObjectsOfTypeAll<MonoScript>())
|
||||
{
|
||||
if (script.GetClass() != typeof(T))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set 'm_Script' to convert.
|
||||
so.FindProperty("m_Script").objectReferenceValue = script;
|
||||
so.ApplyModifiedProperties();
|
||||
break;
|
||||
}
|
||||
|
||||
if (so.targetObject is MonoBehaviour mb)
|
||||
{
|
||||
mb.enabled = oldEnable;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 999f0ea10cb5f48ed89190a0ca83dd53
|
||||
guid: 8455ee485a5ee4cacbdf558f66af65fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
19
Runtime/Internal/Extensions/ListExtensions.cs
Normal file
19
Runtime/Internal/Extensions/ListExtensions.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for Component class.
|
||||
/// </summary>
|
||||
internal static class ListExtensions
|
||||
{
|
||||
public static void RemoveAtFast<T>(this List<T> self, int index)
|
||||
{
|
||||
if (self == null) return;
|
||||
|
||||
var lastIndex = self.Count - 1;
|
||||
self[index] = self[lastIndex];
|
||||
self.RemoveAt(lastIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0328b9fb8360e4f8e8a842f87d330466
|
||||
guid: 833553390099d40c9b212823f0852c46
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
48
Runtime/Internal/Extensions/Misc.cs
Normal file
48
Runtime/Internal/Extensions/Misc.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Diagnostics;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class Misc
|
||||
{
|
||||
public static void Destroy(Object obj)
|
||||
{
|
||||
if (!obj) return;
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DestroyImmediate(Object obj)
|
||||
{
|
||||
if (!obj) return;
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isEditor)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void SetDirty(Object obj)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!obj) return;
|
||||
EditorUtility.SetDirty(obj);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Internal/Extensions/Misc.cs.meta
Normal file
11
Runtime/Internal/Extensions/Misc.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39ed6a6b0a72e482488bd298b2ae762e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
58
Runtime/Internal/Extensions/SpriteExtensions.cs
Normal file
58
Runtime/Internal/Extensions/SpriteExtensions.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.U2D;
|
||||
#if UNITY_EDITOR
|
||||
using System.Reflection;
|
||||
#endif
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for Sprite class.
|
||||
/// </summary>
|
||||
internal static class SpriteExtensions
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
private static readonly Type s_SpriteEditorExtensionType =
|
||||
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
||||
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
||||
|
||||
private static readonly MethodInfo s_GetActiveAtlasTextureMethod = s_SpriteEditorExtensionType
|
||||
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
private static readonly MethodInfo s_GetActiveAtlasMethod = s_SpriteEditorExtensionType
|
||||
.GetMethod("GetActiveAtlas", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
/// <summary>
|
||||
/// Get the actual texture of a sprite in play mode or edit mode.
|
||||
/// </summary>
|
||||
public static Texture2D GetActualTexture(this Sprite self)
|
||||
{
|
||||
if (!self) return null;
|
||||
|
||||
if (Application.isPlaying) return self.texture;
|
||||
|
||||
var ret = s_GetActiveAtlasTextureMethod.Invoke(null, new object[] { self }) as Texture2D;
|
||||
return ret ? ret : self.texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the active sprite atlas of a sprite in play mode or edit mode.
|
||||
/// </summary>
|
||||
public static SpriteAtlas GetActiveAtlas(this Sprite self)
|
||||
{
|
||||
if (!self) return null;
|
||||
|
||||
return s_GetActiveAtlasMethod.Invoke(null, new object[] { self }) as SpriteAtlas;
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// Get the actual texture of a sprite in play mode.
|
||||
/// </summary>
|
||||
internal static Texture2D GetActualTexture(this Sprite self)
|
||||
{
|
||||
return self ? self.texture : null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Runtime/Internal/Extensions/SpriteExtensions.cs.meta
Normal file
11
Runtime/Internal/Extensions/SpriteExtensions.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7a2e11131111447cb7fc0394a14da65
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
46
Runtime/Internal/Extensions/Vector3Extensions.cs
Normal file
46
Runtime/Internal/Extensions/Vector3Extensions.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class Vector3Extensions
|
||||
{
|
||||
public static Vector3 Inverse(this Vector3 self)
|
||||
{
|
||||
self.x = Mathf.Approximately(self.x, 0) ? 1 : 1 / self.x;
|
||||
self.y = Mathf.Approximately(self.y, 0) ? 1 : 1 / self.y;
|
||||
self.z = Mathf.Approximately(self.z, 0) ? 1 : 1 / self.z;
|
||||
return self;
|
||||
}
|
||||
|
||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1)
|
||||
{
|
||||
self.Scale(other1);
|
||||
return self;
|
||||
}
|
||||
|
||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2)
|
||||
{
|
||||
self.Scale(other1);
|
||||
self.Scale(other2);
|
||||
return self;
|
||||
}
|
||||
|
||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2, Vector3 other3)
|
||||
{
|
||||
self.Scale(other1);
|
||||
self.Scale(other2);
|
||||
self.Scale(other3);
|
||||
return self;
|
||||
}
|
||||
|
||||
public static bool IsVisible(this Vector3 self)
|
||||
{
|
||||
return 0 < Mathf.Abs(self.x * self.y * self.z);
|
||||
}
|
||||
|
||||
public static bool IsVisible2D(this Vector3 self)
|
||||
{
|
||||
return 0 < Mathf.Abs(self.x * self.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Internal/Extensions/Vector3Extensions.cs.meta
Normal file
11
Runtime/Internal/Extensions/Vector3Extensions.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a7b5fb989e4b48c8bc7ecce834060f5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Runtime/Internal/ProjectSettings.meta
Normal file
8
Runtime/Internal/ProjectSettings.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 398e06c9985ad4291a95f0749c2927fb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
217
Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs
Normal file
217
Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
#endif
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
public abstract class PreloadedProjectSettings : ScriptableObject
|
||||
#if UNITY_EDITOR
|
||||
, IPreprocessBuildWithReport
|
||||
{
|
||||
int IOrderedCallback.callbackOrder => 0;
|
||||
|
||||
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
[InitializeOnEnterPlayMode]
|
||||
private static void Initialize()
|
||||
{
|
||||
const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
|
||||
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||
{
|
||||
var defaultSettings = GetDefaultSettings(t);
|
||||
if (!defaultSettings)
|
||||
{
|
||||
defaultSettings = t.GetProperty("instance", flags)
|
||||
?.GetValue(null, null) as PreloadedProjectSettings;
|
||||
SetDefaultSettings(defaultSettings);
|
||||
}
|
||||
else if (GetPreloadedSettings(t).Length != 1)
|
||||
{
|
||||
SetDefaultSettings(defaultSettings);
|
||||
}
|
||||
}
|
||||
|
||||
EditorApplication.QueuePlayerLoopUpdate();
|
||||
}
|
||||
|
||||
protected static string GetDefaultName(Type type, bool nicify)
|
||||
{
|
||||
var typeName = type.Name.Replace("ProjectSettings", "");
|
||||
return nicify
|
||||
? ObjectNames.NicifyVariableName(typeName)
|
||||
: typeName;
|
||||
}
|
||||
|
||||
private static Object[] GetPreloadedSettings(Type type)
|
||||
{
|
||||
return PlayerSettings.GetPreloadedAssets()
|
||||
.Where(x => x && x.GetType() == type)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
protected static PreloadedProjectSettings GetDefaultSettings(Type type)
|
||||
{
|
||||
return GetPreloadedSettings(type).FirstOrDefault() as PreloadedProjectSettings
|
||||
?? AssetDatabase.FindAssets($"t:{nameof(PreloadedProjectSettings)}")
|
||||
.Select(AssetDatabase.GUIDToAssetPath)
|
||||
.Select(AssetDatabase.LoadAssetAtPath<PreloadedProjectSettings>)
|
||||
.FirstOrDefault(x => x && x.GetType() == type);
|
||||
}
|
||||
|
||||
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
|
||||
{
|
||||
var type = asset.GetType();
|
||||
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
|
||||
{
|
||||
if (!AssetDatabase.IsValidFolder("Assets/ProjectSettings"))
|
||||
{
|
||||
AssetDatabase.CreateFolder("Assets", "ProjectSettings");
|
||||
}
|
||||
|
||||
var assetPath = $"Assets/ProjectSettings/{GetDefaultName(type, false)}.asset";
|
||||
assetPath = AssetDatabase.GenerateUniqueAssetPath(assetPath);
|
||||
AssetDatabase.CreateAsset(asset, assetPath);
|
||||
}
|
||||
|
||||
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
||||
var projectSettings = GetPreloadedSettings(type);
|
||||
PlayerSettings.SetPreloadedAssets(preloadedAssets
|
||||
.Where(x => x)
|
||||
.Except(projectSettings.Except(new[] { asset }))
|
||||
.Append(asset)
|
||||
.Distinct()
|
||||
.ToArray());
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
public abstract class PreloadedProjectSettings<T> : PreloadedProjectSettings
|
||||
where T : PreloadedProjectSettings<T>
|
||||
{
|
||||
private static T s_Instance;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private string _jsonText;
|
||||
|
||||
public static T instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Instance) return s_Instance;
|
||||
|
||||
s_Instance = GetDefaultSettings(typeof(T)) as T;
|
||||
if (s_Instance) return s_Instance;
|
||||
|
||||
s_Instance = CreateInstance<T>();
|
||||
if (!s_Instance)
|
||||
{
|
||||
s_Instance = null;
|
||||
return s_Instance;
|
||||
}
|
||||
|
||||
SetDefaultSettings(s_Instance);
|
||||
return s_Instance;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case PlayModeStateChange.ExitingEditMode:
|
||||
_jsonText = EditorJsonUtility.ToJson(this);
|
||||
break;
|
||||
case PlayModeStateChange.ExitingPlayMode:
|
||||
if (_jsonText != null)
|
||||
{
|
||||
EditorJsonUtility.FromJsonOverwrite(_jsonText, this);
|
||||
_jsonText = null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public static T instance => s_Instance ? s_Instance : s_Instance = CreateInstance<T>();
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the object becomes enabled and active.
|
||||
/// </summary>
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var isDefaultSettings = !s_Instance || s_Instance == this || GetDefaultSettings(typeof(T)) == this;
|
||||
if (!isDefaultSettings)
|
||||
{
|
||||
DestroyImmediate(this, true);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
#endif
|
||||
|
||||
if (s_Instance) return;
|
||||
s_Instance = this as T;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the behaviour becomes disabled.
|
||||
/// </summary>
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||
#endif
|
||||
if (s_Instance != this) return;
|
||||
|
||||
s_Instance = null;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected sealed class PreloadedProjectSettingsProvider : SettingsProvider
|
||||
{
|
||||
private Editor _editor;
|
||||
private PreloadedProjectSettings<T> _target;
|
||||
|
||||
public PreloadedProjectSettingsProvider(string path) : base(path, SettingsScope.Project)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnGUI(string searchContext)
|
||||
{
|
||||
if (!_target)
|
||||
{
|
||||
if (_editor)
|
||||
{
|
||||
DestroyImmediate(_editor);
|
||||
_editor = null;
|
||||
}
|
||||
|
||||
_target = instance;
|
||||
_editor = Editor.CreateEditor(_target);
|
||||
}
|
||||
|
||||
_editor.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 790ea008741dc411497c8794745319eb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Runtime/Internal/Utilities.meta
Normal file
8
Runtime/Internal/Utilities.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b2877595f27c4a70a426991d515434f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
81
Runtime/Internal/Utilities/FastAction.cs
Executable file
81
Runtime/Internal/Utilities/FastAction.cs
Executable file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a fast action.
|
||||
/// </summary>
|
||||
internal class FastActionBase<T>
|
||||
{
|
||||
private static readonly ObjectPool<LinkedListNode<T>> s_NodePool =
|
||||
new ObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true, x => x.Value = default);
|
||||
|
||||
private readonly LinkedList<T> _delegates = new LinkedList<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a delegate to the action.
|
||||
/// </summary>
|
||||
public void Add(T rhs)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[FastAction] Add Action");
|
||||
var node = s_NodePool.Rent();
|
||||
node.Value = rhs;
|
||||
_delegates.AddLast(node);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a delegate from the action.
|
||||
/// </summary>
|
||||
public void Remove(T rhs)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[FastAction] Remove Action");
|
||||
var node = _delegates.Find(rhs);
|
||||
if (node != null)
|
||||
{
|
||||
_delegates.Remove(node);
|
||||
s_NodePool.Return(ref node);
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the action with a callback function.
|
||||
/// </summary>
|
||||
protected void Invoke(Action<T> callback)
|
||||
{
|
||||
var node = _delegates.First;
|
||||
while (node != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(node.Value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
|
||||
node = node.Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A fast action without parameters.
|
||||
/// </summary>
|
||||
internal class FastAction : FastActionBase<Action>
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoke all the registered delegates.
|
||||
/// </summary>
|
||||
public void Invoke()
|
||||
{
|
||||
Invoke(action => action.Invoke());
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Internal/Utilities/FastAction.cs.meta
Normal file
11
Runtime/Internal/Utilities/FastAction.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7c8c268a827b4787a8e050f1fe95ad5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
102
Runtime/Internal/Utilities/FrameCache.cs
Normal file
102
Runtime/Internal/Utilities/FrameCache.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class FrameCache
|
||||
{
|
||||
private static readonly Dictionary<Type, IFrameCache> s_Caches = new Dictionary<Type, IFrameCache>();
|
||||
|
||||
static FrameCache()
|
||||
{
|
||||
s_Caches.Clear();
|
||||
UIExtraCallbacks.onLateAfterCanvasRebuild += ClearAllCache;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void Clear()
|
||||
{
|
||||
s_Caches.Clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Tries to retrieve a value from the frame cache with a specified key.
|
||||
/// </summary>
|
||||
public static bool TryGet<T>(object key1, string key2, out T result)
|
||||
{
|
||||
return GetFrameCache<T>().TryGet((key1.GetHashCode(), key2.GetHashCode()), out result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to retrieve a value from the frame cache with a specified key.
|
||||
/// </summary>
|
||||
public static bool TryGet<T>(object key1, string key2, int key3, out T result)
|
||||
{
|
||||
return GetFrameCache<T>().TryGet((key1.GetHashCode(), key2.GetHashCode() + key3), out result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value in the frame cache with a specified key.
|
||||
/// </summary>
|
||||
public static void Set<T>(object key1, string key2, T result)
|
||||
{
|
||||
GetFrameCache<T>().Set((key1.GetHashCode(), key2.GetHashCode()), result);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value in the frame cache with a specified key.
|
||||
/// </summary>
|
||||
public static void Set<T>(object key1, string key2, int key3, T result)
|
||||
{
|
||||
GetFrameCache<T>().Set((key1.GetHashCode(), key2.GetHashCode() + key3), result);
|
||||
}
|
||||
|
||||
private static void ClearAllCache()
|
||||
{
|
||||
foreach (var cache in s_Caches.Values)
|
||||
{
|
||||
cache.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static FrameCacheContainer<T> GetFrameCache<T>()
|
||||
{
|
||||
var t = typeof(T);
|
||||
if (s_Caches.TryGetValue(t, out var frameCache)) return frameCache as FrameCacheContainer<T>;
|
||||
|
||||
frameCache = new FrameCacheContainer<T>();
|
||||
s_Caches.Add(t, frameCache);
|
||||
|
||||
return (FrameCacheContainer<T>)frameCache;
|
||||
}
|
||||
|
||||
private interface IFrameCache
|
||||
{
|
||||
void Clear();
|
||||
}
|
||||
|
||||
private class FrameCacheContainer<T> : IFrameCache
|
||||
{
|
||||
private readonly Dictionary<(int, int), T> _caches = new Dictionary<(int, int), T>();
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_caches.Clear();
|
||||
}
|
||||
|
||||
public bool TryGet((int, int) key, out T result)
|
||||
{
|
||||
return _caches.TryGetValue(key, out result);
|
||||
}
|
||||
|
||||
public void Set((int, int) key, T result)
|
||||
{
|
||||
_caches[key] = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Internal/Utilities/FrameCache.cs.meta
Normal file
11
Runtime/Internal/Utilities/FrameCache.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f129e3b07ffb4d3bbb4cc5f6bd94087
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
259
Runtime/Internal/Utilities/Logging.cs
Normal file
259
Runtime/Internal/Utilities/Logging.cs
Normal file
@@ -0,0 +1,259 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#else
|
||||
using Conditional = System.Diagnostics.ConditionalAttribute;
|
||||
#endif
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class Logging
|
||||
{
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
private const string k_DisableSymbol = "DISABLE_COFFEE_LOGGER";
|
||||
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
private static void Log_Internal(LogType type, object tag, object message, Object context)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
AppendTag(s_Sb, tag);
|
||||
s_Sb.Append(message);
|
||||
switch (type)
|
||||
{
|
||||
case LogType.Error:
|
||||
case LogType.Assert:
|
||||
case LogType.Exception:
|
||||
Debug.LogError(s_Sb, context);
|
||||
break;
|
||||
case LogType.Warning:
|
||||
Debug.LogWarning(s_Sb, context);
|
||||
break;
|
||||
case LogType.Log:
|
||||
Debug.Log(s_Sb, context);
|
||||
break;
|
||||
}
|
||||
|
||||
s_Sb.Length = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
public static void LogIf(bool enable, object tag, object message, Object context = null)
|
||||
{
|
||||
if (!enable) return;
|
||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
public static void Log(object tag, object message, Object context = null)
|
||||
{
|
||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
public static void LogWarning(object tag, object message, Object context = null)
|
||||
{
|
||||
Log_Internal(LogType.Warning, tag, message, context ? context : tag as Object);
|
||||
}
|
||||
|
||||
public static void LogError(object tag, object message, Object context = null)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
Log_Internal(LogType.Error, tag, message, context ? context : tag as Object);
|
||||
#else
|
||||
Debug.LogError($"{tag}: {message}", context);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
public static void LogMulticast(Type type, string fieldName, object instance = null, string message = null)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
AppendTag(s_Sb, instance ?? type);
|
||||
|
||||
var handler = type
|
||||
.GetField(fieldName,
|
||||
BindingFlags.Static | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic)
|
||||
?.GetValue(instance);
|
||||
|
||||
var list = ((MulticastDelegate)handler)?.GetInvocationList() ?? Array.Empty<Delegate>();
|
||||
s_Sb.Append("<color=orange>");
|
||||
s_Sb.Append(type.Name);
|
||||
s_Sb.Append(".");
|
||||
s_Sb.Append(fieldName);
|
||||
s_Sb.Append(" has ");
|
||||
s_Sb.Append(list.Length);
|
||||
s_Sb.Append(" callbacks");
|
||||
if (message != null)
|
||||
{
|
||||
s_Sb.Append(" (");
|
||||
s_Sb.Append(message);
|
||||
s_Sb.Append(")");
|
||||
}
|
||||
|
||||
s_Sb.Append(":</color>");
|
||||
|
||||
for (var i = 0; i < list.Length; i++)
|
||||
{
|
||||
s_Sb.Append("\n - ");
|
||||
s_Sb.Append(list[i].Method.DeclaringType?.Name);
|
||||
s_Sb.Append(".");
|
||||
s_Sb.Append(list[i].Method.Name);
|
||||
}
|
||||
|
||||
Debug.Log(s_Sb);
|
||||
s_Sb.Length = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
private static void AppendTag(StringBuilder sb, object tag)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
try
|
||||
{
|
||||
sb.Append("f");
|
||||
sb.Append(Time.frameCount);
|
||||
sb.Append(":<color=#");
|
||||
AppendReadableCode(sb, tag);
|
||||
sb.Append("><b>[");
|
||||
|
||||
switch (tag)
|
||||
{
|
||||
case Type type:
|
||||
AppendType(sb, type);
|
||||
break;
|
||||
case Object uObject:
|
||||
AppendType(sb, tag.GetType());
|
||||
sb.Append(" #");
|
||||
sb.Append(uObject.name);
|
||||
break;
|
||||
default:
|
||||
AppendType(sb, tag.GetType());
|
||||
break;
|
||||
}
|
||||
|
||||
sb.Append("]</b></color> ");
|
||||
}
|
||||
catch
|
||||
{
|
||||
sb.Append("f");
|
||||
sb.Append(Time.frameCount);
|
||||
sb.Append(":<b>[");
|
||||
sb.Append(tag);
|
||||
sb.Append("]</b> ");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
private static void AppendType(StringBuilder sb, Type type)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
if (s_TypeNameCache.TryGetValue(type, out var name))
|
||||
{
|
||||
sb.Append(name);
|
||||
return;
|
||||
}
|
||||
|
||||
// New type found
|
||||
var start = sb.Length;
|
||||
if (0 < start && sb[start - 1] == '<' && (type.Name == "Material" || type.Name == "Color"))
|
||||
{
|
||||
sb.Append('@');
|
||||
}
|
||||
|
||||
sb.Append(type.Name);
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
sb.Length -= 2;
|
||||
sb.Append("<");
|
||||
foreach (var gType in type.GetGenericArguments())
|
||||
{
|
||||
AppendType(sb, gType);
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Length -= 2;
|
||||
sb.Append(">");
|
||||
}
|
||||
|
||||
s_TypeNameCache.Add(type, sb.ToString(start, sb.Length - start));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
private static void AppendReadableCode(StringBuilder sb, object tag)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
int hash;
|
||||
try
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case string text:
|
||||
hash = text.GetHashCode();
|
||||
break;
|
||||
case Type type:
|
||||
type = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
|
||||
hash = type.FullName?.GetHashCode() ?? 0;
|
||||
break;
|
||||
default:
|
||||
hash = tag.GetType().FullName?.GetHashCode() ?? 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
sb.Append("FFFFFF");
|
||||
return;
|
||||
}
|
||||
|
||||
hash = hash & (s_Codes.Length - 1);
|
||||
if (s_Codes[hash] == null)
|
||||
{
|
||||
var hue = hash / (float)s_Codes.Length;
|
||||
var modifier = 1f - Mathf.Clamp01(Mathf.Abs(hue - 0.65f) / 0.2f);
|
||||
var saturation = 0.7f + modifier * -0.2f;
|
||||
var value = 0.8f + modifier * 0.3f;
|
||||
s_Codes[hash] = ColorUtility.ToHtmlStringRGB(Color.HSVToRGB(hue, saturation, value));
|
||||
}
|
||||
|
||||
sb.Append(s_Codes[hash]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
private static readonly StringBuilder s_Sb = new StringBuilder();
|
||||
private static readonly string[] s_Codes = new string[64];
|
||||
private static readonly Dictionary<Type, string> s_TypeNameCache = new Dictionary<Type, string>();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Runtime/Internal/Utilities/Logging.cs.meta
Normal file
11
Runtime/Internal/Utilities/Logging.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8255313895da84e7cbdc876be3795334
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
93
Runtime/Internal/Utilities/MaterialRepository.cs
Normal file
93
Runtime/Internal/Utilities/MaterialRepository.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides functionality to manage materials.
|
||||
/// </summary>
|
||||
internal static class MaterialRepository
|
||||
{
|
||||
private static readonly ObjectRepository<Material> s_Repository = new ObjectRepository<Material>();
|
||||
|
||||
public static int count => s_Repository.count;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void Clear()
|
||||
{
|
||||
s_Repository.Clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a cached material based on the hash.
|
||||
/// </summary>
|
||||
public static bool Valid(Hash128 hash, Material material)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[MaterialRegistry] Valid");
|
||||
var ret = s_Repository.Valid(hash, material);
|
||||
Profiler.EndSample();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or retrieves a cached material based on the hash.
|
||||
/// </summary>
|
||||
public static void Get(Hash128 hash, ref Material material, Func<Material> onCreate)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||
s_Repository.Get(hash, ref material, onCreate);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or retrieves a cached material based on the hash.
|
||||
/// </summary>
|
||||
public static void Get(Hash128 hash, ref Material material, string shaderName)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x))
|
||||
{
|
||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable
|
||||
}, shaderName);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds or retrieves a cached material based on the hash.
|
||||
/// </summary>
|
||||
public static void Get(Hash128 hash, ref Material material, string shaderName, string[] keywords)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x.shaderName))
|
||||
{
|
||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
||||
shaderKeywords = x.keywords
|
||||
}, (shaderName, keywords));
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or retrieves a cached material based on the hash.
|
||||
/// </summary>
|
||||
public static void Get<T>(Hash128 hash, ref Material material, Func<T, Material> onCreate, T source)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||
s_Repository.Get(hash, ref material, onCreate, source);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a soft mask material from the cache.
|
||||
/// </summary>
|
||||
public static void Release(ref Material material)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[MaterialRepository] Release");
|
||||
s_Repository.Release(ref material);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Internal/Utilities/MaterialRepository.cs.meta
Normal file
11
Runtime/Internal/Utilities/MaterialRepository.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 702912f2ee2ec49bb8003a64151ae4f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
85
Runtime/Internal/Utilities/ObjectPool.cs
Normal file
85
Runtime/Internal/Utilities/ObjectPool.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Object pool.
|
||||
/// </summary>
|
||||
internal class ObjectPool<T>
|
||||
{
|
||||
private readonly Func<T> _onCreate; // Delegate for creating instances
|
||||
private readonly Action<T> _onReturn; // Delegate for returning instances to the pool
|
||||
private readonly Predicate<T> _onValid; // Delegate for checking if instances are valid
|
||||
private readonly Stack<T> _pool = new Stack<T>(32); // Object pool
|
||||
private int _count; // Total count of created instances
|
||||
|
||||
public ObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
|
||||
{
|
||||
_onCreate = onCreate;
|
||||
_onValid = onValid;
|
||||
_onReturn = onReturn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rent an instance from the pool.
|
||||
/// When you no longer need it, return it with <see cref="Return" />.
|
||||
/// </summary>
|
||||
public T Rent()
|
||||
{
|
||||
while (0 < _pool.Count)
|
||||
{
|
||||
var instance = _pool.Pop();
|
||||
if (_onValid(instance))
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no instances in the pool, create a new one.
|
||||
Logging.Log(this, $"A new instance is created (pooled: {_pool.Count}, created: {++_count}).");
|
||||
return _onCreate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return an instance to the pool and assign null.
|
||||
/// Be sure to return the instance obtained with <see cref="Rent" /> with this method.
|
||||
/// </summary>
|
||||
public void Return(ref T instance)
|
||||
{
|
||||
if (instance == null || _pool.Contains(instance)) return; // Ignore if already pooled or null.
|
||||
|
||||
_onReturn(instance); // Return the instance to the pool.
|
||||
_pool.Push(instance);
|
||||
Logging.Log(this, $"An instance is released (pooled: {_pool.Count}, created: {_count}).");
|
||||
instance = default; // Set the reference to null.
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Object pool for <see cref="List{T}" />.
|
||||
/// </summary>
|
||||
internal static class ListPool<T>
|
||||
{
|
||||
private static readonly ObjectPool<List<T>> s_ListPool =
|
||||
new ObjectPool<List<T>>(() => new List<T>(), _ => true, x => x.Clear());
|
||||
|
||||
/// <summary>
|
||||
/// Rent an instance from the pool.
|
||||
/// When you no longer need it, return it with <see cref="Return" />.
|
||||
/// </summary>
|
||||
public static List<T> Rent()
|
||||
{
|
||||
return s_ListPool.Rent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return an instance to the pool and assign null.
|
||||
/// Be sure to return the instance obtained with <see cref="Rent" /> with this method.
|
||||
/// </summary>
|
||||
public static void Return(ref List<T> toRelease)
|
||||
{
|
||||
s_ListPool.Return(ref toRelease);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Internal/Utilities/ObjectPool.cs.meta
Normal file
11
Runtime/Internal/Utilities/ObjectPool.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 632cb1ba34e6a4e80b55a32bb63ca369
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
218
Runtime/Internal/Utilities/ObjectRepository.cs
Normal file
218
Runtime/Internal/Utilities/ObjectRepository.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal class ObjectRepository<T> where T : Object
|
||||
{
|
||||
private readonly List<Entry> _cache = new List<Entry>();
|
||||
private readonly string _name;
|
||||
private readonly Action<T> _onRelease;
|
||||
private readonly Stack<Entry> _pool = new Stack<Entry>();
|
||||
|
||||
public ObjectRepository(Action<T> onRelease = null)
|
||||
{
|
||||
_name = $"{typeof(T).Name}Repository";
|
||||
if (onRelease == null)
|
||||
{
|
||||
_onRelease = x =>
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(x, false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(x);
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
_onRelease = onRelease;
|
||||
}
|
||||
}
|
||||
|
||||
public int count => _cache.Count;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
for (var i = 0; i < _cache.Count; i++)
|
||||
{
|
||||
var entry = _cache[i];
|
||||
if (entry == null) continue;
|
||||
|
||||
entry.Release(_onRelease);
|
||||
}
|
||||
|
||||
_cache.Clear();
|
||||
}
|
||||
|
||||
public bool Valid(Hash128 hash, T obj)
|
||||
{
|
||||
// Find existing entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Valid > Find existing entry");
|
||||
for (var i = 0; i < _cache.Count; ++i)
|
||||
{
|
||||
var entry = _cache[i];
|
||||
if (entry.hash != hash) continue;
|
||||
Profiler.EndSample();
|
||||
|
||||
// Existing entry found.
|
||||
return entry.storedObject == obj;
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or retrieves a cached object based on the hash.
|
||||
/// </summary>
|
||||
public void Get(Hash128 hash, ref T obj, Func<T> onCreate)
|
||||
{
|
||||
// Find existing entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Get > Find existing entry");
|
||||
for (var i = 0; i < _cache.Count; ++i)
|
||||
{
|
||||
var entry = _cache[i];
|
||||
if (entry.hash != hash) continue;
|
||||
|
||||
// Existing entry found.
|
||||
if (entry.storedObject != obj)
|
||||
{
|
||||
// if the object is different, release the old one.
|
||||
Release(ref obj);
|
||||
++entry.reference;
|
||||
obj = entry.storedObject;
|
||||
Logging.Log(_name, $"Get(#{count}): {entry}");
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
return;
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
// Create new entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Get > Create new entry");
|
||||
var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry();
|
||||
newEntry.storedObject = onCreate();
|
||||
newEntry.hash = hash;
|
||||
newEntry.reference = 1;
|
||||
_cache.Add(newEntry);
|
||||
Logging.Log(_name, $"Get(#{count}): {newEntry}");
|
||||
|
||||
Release(ref obj);
|
||||
obj = newEntry.storedObject;
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or retrieves a cached object based on the hash.
|
||||
/// </summary>
|
||||
public void Get<TS>(Hash128 hash, ref T obj, Func<TS, T> onCreate, TS source)
|
||||
{
|
||||
// Find existing entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Get > Find existing entry");
|
||||
for (var i = 0; i < _cache.Count; ++i)
|
||||
{
|
||||
var entry = _cache[i];
|
||||
if (entry.hash != hash) continue;
|
||||
|
||||
// Existing entry found.
|
||||
if (entry.storedObject != obj)
|
||||
{
|
||||
// if the object is different, release the old one.
|
||||
Release(ref obj);
|
||||
++entry.reference;
|
||||
obj = entry.storedObject;
|
||||
Logging.Log(_name, $"Get(#{count}): {entry}");
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
return;
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
// Create new entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Get > Create new entry");
|
||||
var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry();
|
||||
newEntry.storedObject = onCreate(source);
|
||||
newEntry.hash = hash;
|
||||
newEntry.reference = 1;
|
||||
_cache.Add(newEntry);
|
||||
Logging.Log(_name, $"Get(#{count}): {newEntry}");
|
||||
|
||||
Release(ref obj);
|
||||
obj = newEntry.storedObject;
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release a object.
|
||||
/// </summary>
|
||||
public void Release(ref T obj)
|
||||
{
|
||||
if (ReferenceEquals(obj, null)) return;
|
||||
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Release");
|
||||
for (var i = 0; i < _cache.Count; i++)
|
||||
{
|
||||
var entry = _cache[i];
|
||||
|
||||
if (entry.storedObject != obj)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (--entry.reference <= 0)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Release > RemoveAt");
|
||||
_cache.RemoveAtFast(i);
|
||||
Logging.Log(_name, $"Release(#{_cache.Count}): {entry}");
|
||||
entry.Release(_onRelease);
|
||||
_pool.Push(entry);
|
||||
Profiler.EndSample();
|
||||
break;
|
||||
}
|
||||
|
||||
Logging.Log(_name, $"Release(#{count}): {entry}");
|
||||
break;
|
||||
}
|
||||
|
||||
obj = null;
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
private class Entry
|
||||
{
|
||||
public Hash128 hash;
|
||||
public int reference;
|
||||
public T storedObject;
|
||||
|
||||
public void Release(Action<T> onRelease)
|
||||
{
|
||||
reference = 0;
|
||||
if (storedObject)
|
||||
{
|
||||
onRelease?.Invoke(storedObject);
|
||||
}
|
||||
|
||||
storedObject = null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"h{(uint)hash.GetHashCode()} (#{reference}), {storedObject}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Internal/Utilities/ObjectRepository.cs.meta
Normal file
11
Runtime/Internal/Utilities/ObjectRepository.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a713d67bdb31e45e296e5f18460717e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
92
Runtime/Internal/Utilities/UIExtraCallbacks.cs
Executable file
92
Runtime/Internal/Utilities/UIExtraCallbacks.cs
Executable file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides additional callbacks related to canvas and UI system.
|
||||
/// </summary>
|
||||
internal static class UIExtraCallbacks
|
||||
{
|
||||
private static bool s_IsInitializedAfterCanvasRebuild;
|
||||
private static readonly FastAction s_AfterCanvasRebuildAction = new FastAction();
|
||||
private static readonly FastAction s_LateAfterCanvasRebuildAction = new FastAction();
|
||||
private static readonly FastAction s_BeforeCanvasRebuildAction = new FastAction();
|
||||
|
||||
static UIExtraCallbacks()
|
||||
{
|
||||
Canvas.willRenderCanvases += OnBeforeCanvasRebuild;
|
||||
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases", message: "ctor");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that occurs after canvas rebuilds.
|
||||
/// </summary>
|
||||
public static event Action onLateAfterCanvasRebuild
|
||||
{
|
||||
add => s_LateAfterCanvasRebuildAction.Add(value);
|
||||
remove => s_LateAfterCanvasRebuildAction.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that occurs before canvas rebuilds.
|
||||
/// </summary>
|
||||
public static event Action onBeforeCanvasRebuild
|
||||
{
|
||||
add => s_BeforeCanvasRebuildAction.Add(value);
|
||||
remove => s_BeforeCanvasRebuildAction.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that occurs after canvas rebuilds.
|
||||
/// </summary>
|
||||
public static event Action onAfterCanvasRebuild
|
||||
{
|
||||
add => s_AfterCanvasRebuildAction.Add(value);
|
||||
remove => s_AfterCanvasRebuildAction.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the UIExtraCallbacks to ensure proper event handling.
|
||||
/// </summary>
|
||||
private static void InitializeAfterCanvasRebuild()
|
||||
{
|
||||
if (s_IsInitializedAfterCanvasRebuild) return;
|
||||
s_IsInitializedAfterCanvasRebuild = true;
|
||||
|
||||
CanvasUpdateRegistry.IsRebuildingLayout();
|
||||
Canvas.willRenderCanvases += OnAfterCanvasRebuild;
|
||||
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases",
|
||||
message: "InitializeAfterCanvasRebuild");
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnLoadMethod]
|
||||
#else
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
#endif
|
||||
private static void InitializeOnLoad()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback method called before canvas rebuilds.
|
||||
/// </summary>
|
||||
private static void OnBeforeCanvasRebuild()
|
||||
{
|
||||
s_BeforeCanvasRebuildAction.Invoke();
|
||||
InitializeAfterCanvasRebuild();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback method called after canvas rebuilds.
|
||||
/// </summary>
|
||||
private static void OnAfterCanvasRebuild()
|
||||
{
|
||||
s_AfterCanvasRebuildAction.Invoke();
|
||||
s_LateAfterCanvasRebuildAction.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Internal/Utilities/UIExtraCallbacks.cs.meta
Normal file
11
Runtime/Internal/Utilities/UIExtraCallbacks.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ea318e6e3e6c46aa97c72e28230bdc9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
716
Runtime/UIParticle.cs
Normal file
716
Runtime/UIParticle.cs
Normal file
@@ -0,0 +1,716 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Serialization;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Render maskable and sortable particle effect ,without Camera, RenderTexture or Canvas.
|
||||
/// </summary>
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
public class UIParticle : UIBehaviour, ISerializationCallbackReceiver
|
||||
{
|
||||
public enum AutoScalingMode
|
||||
{
|
||||
None,
|
||||
UIParticle,
|
||||
Transform
|
||||
}
|
||||
|
||||
public enum MeshSharing
|
||||
{
|
||||
None,
|
||||
Auto,
|
||||
Primary,
|
||||
PrimarySimulator,
|
||||
Replica
|
||||
}
|
||||
|
||||
public enum PositionMode
|
||||
{
|
||||
Relative,
|
||||
Absolute
|
||||
}
|
||||
|
||||
[HideInInspector]
|
||||
[SerializeField]
|
||||
[Obsolete]
|
||||
internal bool m_IsTrail;
|
||||
|
||||
[HideInInspector]
|
||||
[FormerlySerializedAs("m_IgnoreParent")]
|
||||
[SerializeField]
|
||||
[Obsolete]
|
||||
private bool m_IgnoreCanvasScaler;
|
||||
|
||||
[HideInInspector]
|
||||
[SerializeField]
|
||||
[Obsolete]
|
||||
internal bool m_AbsoluteMode;
|
||||
|
||||
[Tooltip("Particle effect scale")]
|
||||
[SerializeField]
|
||||
private Vector3 m_Scale3D = new Vector3(1, 1, 1);
|
||||
|
||||
[Tooltip("Animatable material properties.\n" +
|
||||
"If you want to change the material properties of the ParticleSystem in Animation, enable it.")]
|
||||
[SerializeField]
|
||||
internal AnimatableProperty[] m_AnimatableProperties = new AnimatableProperty[0];
|
||||
|
||||
[Tooltip("Particles")]
|
||||
[SerializeField]
|
||||
private List<ParticleSystem> m_Particles = new List<ParticleSystem>();
|
||||
|
||||
[Tooltip("Mesh sharing.\n" +
|
||||
"None: disable mesh sharing.\n" +
|
||||
"Auto: automatically select Primary/Replica.\n" +
|
||||
"Primary: provides particle simulation results to the same group.\n" +
|
||||
"Primary Simulator: Primary, but do not render the particle (simulation only).\n" +
|
||||
"Replica: render simulation results provided by the primary.")]
|
||||
[SerializeField]
|
||||
private MeshSharing m_MeshSharing = MeshSharing.None;
|
||||
|
||||
[Tooltip("Mesh sharing group ID.\n" +
|
||||
"If non-zero is specified, particle simulation results are shared within the group.")]
|
||||
[SerializeField]
|
||||
private int m_GroupId;
|
||||
|
||||
[SerializeField]
|
||||
private int m_GroupMaxId;
|
||||
|
||||
[Tooltip("Relative: The particles will be emitted from the scaled position of ParticleSystem.\n" +
|
||||
"Absolute: The particles will be emitted from the world position of ParticleSystem.")]
|
||||
[SerializeField]
|
||||
private PositionMode m_PositionMode = PositionMode.Relative;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Prevent the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem.")]
|
||||
[Obsolete]
|
||||
internal bool m_AutoScaling;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1)." +
|
||||
"UIParticle: UIParticle.scale will be adjusted.")]
|
||||
private AutoScalingMode m_AutoScalingMode = AutoScalingMode.Transform;
|
||||
|
||||
[SerializeField]
|
||||
private bool m_Maskable = true;
|
||||
|
||||
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
||||
private Canvas _canvas;
|
||||
private int _groupId;
|
||||
private Camera _bakeCamera;
|
||||
private DrivenRectTransformTracker _tracker;
|
||||
private Vector3 _storedScale;
|
||||
private bool _isScaleStored;
|
||||
|
||||
public RectTransform rectTransform => transform as RectTransform;
|
||||
|
||||
public Canvas canvas
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_canvas) return _canvas;
|
||||
|
||||
var tr = transform;
|
||||
while (tr && !_canvas)
|
||||
{
|
||||
if (tr.TryGetComponent(out _canvas)) return _canvas;
|
||||
tr = tr.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does this graphic allow masking.
|
||||
/// </summary>
|
||||
public bool maskable
|
||||
{
|
||||
get => m_Maskable;
|
||||
set
|
||||
{
|
||||
if (value == m_Maskable) return;
|
||||
m_Maskable = value;
|
||||
UpdateRendererMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mesh sharing.
|
||||
/// None: disable mesh sharing.
|
||||
/// Auto: automatically select Primary/Replica.
|
||||
/// Primary: provides particle simulation results to the same group.
|
||||
/// Primary Simulator: Primary, but do not render the particle (simulation only).
|
||||
/// Replica: render simulation results provided by the primary.
|
||||
/// </summary>
|
||||
public MeshSharing meshSharing
|
||||
{
|
||||
get => m_MeshSharing;
|
||||
set => m_MeshSharing = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mesh sharing group ID.
|
||||
/// If non-zero is specified, particle simulation results are shared within the group.
|
||||
/// </summary>
|
||||
public int groupId
|
||||
{
|
||||
get => _groupId;
|
||||
set
|
||||
{
|
||||
if (m_GroupId == value) return;
|
||||
m_GroupId = value;
|
||||
if (m_GroupId != m_GroupMaxId)
|
||||
{
|
||||
ResetGroupId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int groupMaxId
|
||||
{
|
||||
get => m_GroupMaxId;
|
||||
set
|
||||
{
|
||||
if (m_GroupMaxId == value) return;
|
||||
m_GroupMaxId = value;
|
||||
ResetGroupId();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Particle position mode.
|
||||
/// Relative: The particles will be emitted from the scaled position of the ParticleSystem.
|
||||
/// Absolute: The particles will be emitted from the world position of the ParticleSystem.
|
||||
/// </summary>
|
||||
public PositionMode positionMode
|
||||
{
|
||||
get => m_PositionMode;
|
||||
set => m_PositionMode = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Particle position mode.
|
||||
/// Relative: The particles will be emitted from the scaled position of the ParticleSystem.
|
||||
/// Absolute: The particles will be emitted from the world position of the ParticleSystem.
|
||||
/// </summary>
|
||||
public bool absoluteMode
|
||||
{
|
||||
get => m_PositionMode == PositionMode.Absolute;
|
||||
set => positionMode = value ? PositionMode.Absolute : PositionMode.Relative;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prevents the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem.
|
||||
/// </summary>
|
||||
[Obsolete("The autoScaling is now obsolete. Please use the autoScalingMode instead.", false)]
|
||||
public bool autoScaling
|
||||
{
|
||||
get => m_AutoScalingMode != AutoScalingMode.None;
|
||||
set => autoScalingMode = value ? AutoScalingMode.Transform : AutoScalingMode.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auto scaling mode.
|
||||
/// Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1).
|
||||
/// UIParticle: UIParticle.scale will be adjusted.
|
||||
/// </summary>
|
||||
public AutoScalingMode autoScalingMode
|
||||
{
|
||||
get => m_AutoScalingMode;
|
||||
set
|
||||
{
|
||||
if (m_AutoScalingMode == value) return;
|
||||
m_AutoScalingMode = value;
|
||||
|
||||
if (autoScalingMode != AutoScalingMode.Transform && _isScaleStored)
|
||||
{
|
||||
transform.localScale = _storedScale;
|
||||
_isScaleStored = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal bool useMeshSharing => m_MeshSharing != MeshSharing.None;
|
||||
|
||||
internal bool isPrimary =>
|
||||
m_MeshSharing == MeshSharing.Primary
|
||||
|| m_MeshSharing == MeshSharing.PrimarySimulator;
|
||||
|
||||
internal bool canSimulate =>
|
||||
m_MeshSharing == MeshSharing.None
|
||||
|| m_MeshSharing == MeshSharing.Auto
|
||||
|| m_MeshSharing == MeshSharing.Primary
|
||||
|| m_MeshSharing == MeshSharing.PrimarySimulator;
|
||||
|
||||
internal bool canRender =>
|
||||
m_MeshSharing == MeshSharing.None
|
||||
|| m_MeshSharing == MeshSharing.Auto
|
||||
|| m_MeshSharing == MeshSharing.Primary
|
||||
|| m_MeshSharing == MeshSharing.Replica;
|
||||
|
||||
/// <summary>
|
||||
/// Particle effect scale.
|
||||
/// </summary>
|
||||
public float scale
|
||||
{
|
||||
get => m_Scale3D.x;
|
||||
set => m_Scale3D = new Vector3(value, value, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Particle effect scale.
|
||||
/// </summary>
|
||||
public Vector3 scale3D
|
||||
{
|
||||
get => m_Scale3D;
|
||||
set => m_Scale3D = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Particle effect scale.
|
||||
/// </summary>
|
||||
public Vector3 scale3DForCalc => autoScalingMode == AutoScalingMode.Transform
|
||||
? m_Scale3D
|
||||
: m_Scale3D.GetScaled(canvasScale, transform.localScale);
|
||||
|
||||
public List<ParticleSystem> particles => m_Particles;
|
||||
|
||||
/// <summary>
|
||||
/// Get all base materials to render.
|
||||
/// </summary>
|
||||
public IEnumerable<Material> materials
|
||||
{
|
||||
get
|
||||
{
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (!r || !r.material) continue;
|
||||
yield return r.material;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Paused.
|
||||
/// </summary>
|
||||
public bool isPaused { get; private set; }
|
||||
|
||||
public Vector3 parentScale { get; private set; }
|
||||
|
||||
private Vector3 canvasScale { get; set; }
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
_isScaleStored = false;
|
||||
ResetGroupId();
|
||||
UIParticleUpdater.Register(this);
|
||||
|
||||
//
|
||||
if (0 < particles.Count)
|
||||
{
|
||||
RefreshParticles(particles);
|
||||
}
|
||||
else
|
||||
{
|
||||
RefreshParticles();
|
||||
}
|
||||
|
||||
UpdateRendererMaterial();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the behaviour becomes disabled.
|
||||
/// </summary>
|
||||
protected override void OnDisable()
|
||||
{
|
||||
_tracker.Clear();
|
||||
if (autoScalingMode == AutoScalingMode.Transform && _isScaleStored)
|
||||
{
|
||||
transform.localScale = _storedScale;
|
||||
}
|
||||
|
||||
_isScaleStored = false;
|
||||
UIParticleUpdater.Unregister(this);
|
||||
_renderers.ForEach(r => r.Reset());
|
||||
_canvas = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the state of the parent Canvas is changed.
|
||||
/// </summary>
|
||||
protected override void OnCanvasHierarchyChanged()
|
||||
{
|
||||
_canvas = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback for when properties have been changed by animation.
|
||||
/// </summary>
|
||||
protected override void OnDidApplyAnimationProperties()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when a direct or indirect parent of the transform of the GameObject has changed.
|
||||
/// </summary>
|
||||
protected override void OnTransformParentChanged()
|
||||
{
|
||||
_canvas = null;
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||
{
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||
{
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
if (m_IgnoreCanvasScaler || m_AutoScaling)
|
||||
{
|
||||
m_IgnoreCanvasScaler = false;
|
||||
m_AutoScaling = false;
|
||||
m_AutoScalingMode = AutoScalingMode.Transform;
|
||||
}
|
||||
|
||||
if (m_AbsoluteMode)
|
||||
{
|
||||
m_AbsoluteMode = false;
|
||||
m_PositionMode = PositionMode.Absolute;
|
||||
}
|
||||
#pragma warning restore CS0612 // Type or member is obsolete
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Play the ParticleSystems.
|
||||
/// </summary>
|
||||
public void Play()
|
||||
{
|
||||
particles.Exec(p => p.Simulate(0, false, true));
|
||||
isPaused = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pause the ParticleSystems.
|
||||
/// </summary>
|
||||
public void Pause()
|
||||
{
|
||||
particles.Exec(p => p.Pause());
|
||||
isPaused = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpause the ParticleSystems.
|
||||
/// </summary>
|
||||
public void Resume()
|
||||
{
|
||||
isPaused = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the ParticleSystems.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
particles.Exec(p => p.Stop());
|
||||
isPaused = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start emission of the ParticleSystems.
|
||||
/// </summary>
|
||||
public void StartEmission()
|
||||
{
|
||||
particles.Exec(p =>
|
||||
{
|
||||
var emission = p.emission;
|
||||
emission.enabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop emission of the ParticleSystems.
|
||||
/// </summary>
|
||||
public void StopEmission()
|
||||
{
|
||||
particles.Exec(p =>
|
||||
{
|
||||
var emission = p.emission;
|
||||
emission.enabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear the particles of the ParticleSystems.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
particles.Exec(p => p.Clear());
|
||||
isPaused = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh UIParticle using the ParticleSystem instance.
|
||||
/// </summary>
|
||||
public void SetParticleSystemInstance(GameObject instance)
|
||||
{
|
||||
SetParticleSystemInstance(instance, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh UIParticle using the ParticleSystem instance.
|
||||
/// </summary>
|
||||
public void SetParticleSystemInstance(GameObject instance, bool destroyOldParticles)
|
||||
{
|
||||
if (!instance) return;
|
||||
|
||||
var childCount = transform.childCount;
|
||||
for (var i = 0; i < childCount; i++)
|
||||
{
|
||||
var go = transform.GetChild(i).gameObject;
|
||||
go.SetActive(false);
|
||||
if (destroyOldParticles)
|
||||
{
|
||||
Misc.Destroy(go);
|
||||
}
|
||||
}
|
||||
|
||||
var tr = instance.transform;
|
||||
tr.SetParent(transform, false);
|
||||
tr.localPosition = Vector3.zero;
|
||||
|
||||
RefreshParticles(instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh UIParticle using the prefab.
|
||||
/// The prefab is automatically instantiated.
|
||||
/// </summary>
|
||||
public void SetParticleSystemPrefab(GameObject prefab)
|
||||
{
|
||||
if (!prefab) return;
|
||||
|
||||
SetParticleSystemInstance(Instantiate(prefab.gameObject), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh UIParticle.
|
||||
/// Collect ParticleSystems under the GameObject and refresh the UIParticle.
|
||||
/// </summary>
|
||||
public void RefreshParticles()
|
||||
{
|
||||
RefreshParticles(gameObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh UIParticle.
|
||||
/// Collect ParticleSystems under the GameObject and refresh the UIParticle.
|
||||
/// </summary>
|
||||
private void RefreshParticles(GameObject root)
|
||||
{
|
||||
if (!root) return;
|
||||
root.GetComponentsInChildren(true, particles);
|
||||
for (var i = particles.Count - 1; 0 <= i; i--)
|
||||
{
|
||||
var ps = particles[i];
|
||||
if (!ps || ps.GetComponentInParent<UIParticle>(true) != this)
|
||||
{
|
||||
particles.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < particles.Count; i++)
|
||||
{
|
||||
var ps = particles[i];
|
||||
var tsa = ps.textureSheetAnimation;
|
||||
if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0)
|
||||
{
|
||||
tsa.uvChannelMask = UVChannelFlags.UV0;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshParticles(particles);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh UIParticle using a list of ParticleSystems.
|
||||
/// </summary>
|
||||
public void RefreshParticles(List<ParticleSystem> particleSystems)
|
||||
{
|
||||
// Collect children UIParticleRenderer components.
|
||||
// #246: Nullptr exceptions when using nested UIParticle components in hierarchy
|
||||
_renderers.Clear();
|
||||
var childCount = transform.childCount;
|
||||
for (var i = 0; i < childCount; i++)
|
||||
{
|
||||
var child = transform.GetChild(i);
|
||||
if (child.TryGetComponent(out UIParticleRenderer uiParticleRenderer))
|
||||
{
|
||||
_renderers.Add(uiParticleRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the UIParticleRenderer components.
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
_renderers[i].Reset(i);
|
||||
}
|
||||
|
||||
// Set the ParticleSystem to the UIParticleRenderer. If the trail is enabled, set it additionally.
|
||||
var j = 0;
|
||||
for (var i = 0; i < particleSystems.Count; i++)
|
||||
{
|
||||
var ps = particleSystems[i];
|
||||
if (!ps) continue;
|
||||
GetRenderer(j++).Set(this, ps, false);
|
||||
|
||||
// If the trail is enabled, set it additionally.
|
||||
if (ps.trails.enabled)
|
||||
{
|
||||
GetRenderer(j++).Set(this, ps, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateTransformScale()
|
||||
{
|
||||
_tracker.Clear();
|
||||
canvasScale = canvas.rootCanvas.transform.localScale.Inverse();
|
||||
parentScale = transform.parent.lossyScale;
|
||||
if (autoScalingMode != AutoScalingMode.Transform)
|
||||
{
|
||||
if (_isScaleStored)
|
||||
{
|
||||
transform.localScale = _storedScale;
|
||||
}
|
||||
|
||||
_isScaleStored = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var currentScale = transform.localScale;
|
||||
_storedScale = currentScale;
|
||||
_isScaleStored = true;
|
||||
_tracker.Add(this, rectTransform, DrivenTransformProperties.Scale);
|
||||
var newScale = parentScale.Inverse();
|
||||
if (currentScale != newScale)
|
||||
{
|
||||
transform.localScale = newScale;
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateRenderers()
|
||||
{
|
||||
if (!isActiveAndEnabled) return;
|
||||
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (r) continue;
|
||||
|
||||
RefreshParticles(particles);
|
||||
break;
|
||||
}
|
||||
|
||||
var bakeCamera = GetBakeCamera();
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (!r) continue;
|
||||
|
||||
r.UpdateMesh(bakeCamera);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ResetGroupId()
|
||||
{
|
||||
_groupId = m_GroupId == m_GroupMaxId
|
||||
? m_GroupId
|
||||
: Random.Range(m_GroupId, m_GroupMaxId + 1);
|
||||
}
|
||||
|
||||
private void UpdateRendererMaterial()
|
||||
{
|
||||
for (var i = 0; i < _renderers.Count; i++)
|
||||
{
|
||||
var r = _renderers[i];
|
||||
if (!r) continue;
|
||||
r.maskable = maskable;
|
||||
r.SetMaterialDirty();
|
||||
}
|
||||
}
|
||||
|
||||
internal UIParticleRenderer GetRenderer(int index)
|
||||
{
|
||||
if (_renderers.Count <= index)
|
||||
{
|
||||
_renderers.Add(UIParticleRenderer.AddRenderer(this, index));
|
||||
}
|
||||
|
||||
if (!_renderers[index])
|
||||
{
|
||||
_renderers[index] = UIParticleRenderer.AddRenderer(this, index);
|
||||
}
|
||||
|
||||
return _renderers[index];
|
||||
}
|
||||
|
||||
private Camera GetBakeCamera()
|
||||
{
|
||||
if (!canvas) return Camera.main;
|
||||
if (_bakeCamera) return _bakeCamera;
|
||||
|
||||
// Find existing baking camera.
|
||||
var childCount = transform.childCount;
|
||||
for (var i = 0; i < childCount; i++)
|
||||
{
|
||||
if (transform.GetChild(i).TryGetComponent<Camera>(out var cam)
|
||||
&& cam.name == "[generated] UIParticle BakingCamera")
|
||||
{
|
||||
_bakeCamera = cam;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create baking camera.
|
||||
if (!_bakeCamera)
|
||||
{
|
||||
var go = new GameObject("[generated] UIParticle BakingCamera")
|
||||
{
|
||||
hideFlags = HideFlags.HideAndDontSave
|
||||
};
|
||||
go.SetActive(false);
|
||||
go.transform.SetParent(transform, false);
|
||||
_bakeCamera = go.AddComponent<Camera>();
|
||||
}
|
||||
|
||||
// Setup baking camera.
|
||||
_bakeCamera.enabled = false;
|
||||
_bakeCamera.orthographicSize = 1000;
|
||||
_bakeCamera.transform.SetPositionAndRotation(new Vector3(0, 0, -1000), Quaternion.identity);
|
||||
_bakeCamera.orthographic = true;
|
||||
_bakeCamera.farClipPlane = 2000f;
|
||||
_bakeCamera.clearFlags = CameraClearFlags.Nothing;
|
||||
_bakeCamera.cullingMask = 0; // Nothing
|
||||
_bakeCamera.allowHDR = false;
|
||||
_bakeCamera.allowMSAA = false;
|
||||
_bakeCamera.renderingPath = RenderingPath.Forward;
|
||||
_bakeCamera.useOcclusionCulling = false;
|
||||
|
||||
return _bakeCamera;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@ MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -100
|
||||
icon: {instanceID: 0}
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
262
Runtime/UIParticleAttractor.cs
Normal file
262
Runtime/UIParticleAttractor.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
using System;
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
[ExecuteAlways]
|
||||
public class UIParticleAttractor : MonoBehaviour
|
||||
{
|
||||
public enum Movement
|
||||
{
|
||||
Linear,
|
||||
Smooth,
|
||||
Sphere
|
||||
}
|
||||
|
||||
public enum UpdateMode
|
||||
{
|
||||
Normal,
|
||||
UnscaledTime
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private ParticleSystem m_ParticleSystem;
|
||||
|
||||
[Range(0.1f, 10f)]
|
||||
[SerializeField]
|
||||
private float m_DestinationRadius = 1;
|
||||
|
||||
[Range(0f, 0.95f)]
|
||||
[SerializeField]
|
||||
private float m_DelayRate;
|
||||
|
||||
[Range(0.001f, 100f)]
|
||||
[SerializeField]
|
||||
private float m_MaxSpeed = 1;
|
||||
|
||||
[SerializeField]
|
||||
private Movement m_Movement;
|
||||
|
||||
[SerializeField]
|
||||
private UpdateMode m_UpdateMode;
|
||||
|
||||
[SerializeField]
|
||||
private UnityEvent m_OnAttracted;
|
||||
|
||||
private UIParticle _uiParticle;
|
||||
|
||||
public float destinationRadius
|
||||
{
|
||||
get => m_DestinationRadius;
|
||||
set => m_DestinationRadius = Mathf.Clamp(value, 0.1f, 10f);
|
||||
}
|
||||
|
||||
public float delay
|
||||
{
|
||||
get => m_DelayRate;
|
||||
set => m_DelayRate = value;
|
||||
}
|
||||
|
||||
public float maxSpeed
|
||||
{
|
||||
get => m_MaxSpeed;
|
||||
set => m_MaxSpeed = value;
|
||||
}
|
||||
|
||||
public Movement movement
|
||||
{
|
||||
get => m_Movement;
|
||||
set => m_Movement = value;
|
||||
}
|
||||
|
||||
public UpdateMode updateMode
|
||||
{
|
||||
get => m_UpdateMode;
|
||||
set => m_UpdateMode = value;
|
||||
}
|
||||
|
||||
public UnityEvent onAttracted
|
||||
{
|
||||
get => m_OnAttracted;
|
||||
set => m_OnAttracted = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The target ParticleSystem to attract.
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
public new ParticleSystem particleSystem
|
||||
#else
|
||||
public ParticleSystem particleSystem
|
||||
#endif
|
||||
{
|
||||
get => m_ParticleSystem;
|
||||
set
|
||||
{
|
||||
m_ParticleSystem = value;
|
||||
ApplyParticleSystem();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
ApplyParticleSystem();
|
||||
UIParticleUpdater.Register(this);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
UIParticleUpdater.Unregister(this);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_uiParticle = null;
|
||||
m_ParticleSystem = null;
|
||||
}
|
||||
|
||||
internal void Attract()
|
||||
{
|
||||
if (m_ParticleSystem == null) return;
|
||||
|
||||
var count = m_ParticleSystem.particleCount;
|
||||
if (count == 0) return;
|
||||
|
||||
var particles = ParticleSystemExtensions.GetParticleArray(count);
|
||||
m_ParticleSystem.GetParticles(particles, count);
|
||||
|
||||
var dstPos = GetDestinationPosition();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
// Attracted
|
||||
var p = particles[i];
|
||||
if (0f < p.remainingLifetime && Vector3.Distance(p.position, dstPos) < m_DestinationRadius)
|
||||
{
|
||||
p.remainingLifetime = 0f;
|
||||
particles[i] = p;
|
||||
|
||||
if (m_OnAttracted != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_OnAttracted.Invoke();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calc attracting time
|
||||
var delayTime = p.startLifetime * m_DelayRate;
|
||||
var duration = p.startLifetime - delayTime;
|
||||
var time = Mathf.Max(0, p.startLifetime - p.remainingLifetime - delayTime);
|
||||
|
||||
// Delay
|
||||
if (time <= 0) continue;
|
||||
|
||||
// Attract
|
||||
p.position = GetAttractedPosition(p.position, dstPos, duration, time);
|
||||
p.velocity *= 0.5f;
|
||||
particles[i] = p;
|
||||
}
|
||||
|
||||
m_ParticleSystem.SetParticles(particles, count);
|
||||
}
|
||||
|
||||
private Vector3 GetDestinationPosition()
|
||||
{
|
||||
var isUI = _uiParticle && _uiParticle.enabled;
|
||||
var psPos = m_ParticleSystem.transform.position;
|
||||
var attractorPos = transform.position;
|
||||
var dstPos = attractorPos;
|
||||
var isLocalSpace = m_ParticleSystem.IsLocalSpace();
|
||||
|
||||
if (isLocalSpace)
|
||||
{
|
||||
dstPos = m_ParticleSystem.transform.InverseTransformPoint(dstPos);
|
||||
}
|
||||
|
||||
if (isUI)
|
||||
{
|
||||
var inverseScale = _uiParticle.parentScale.Inverse();
|
||||
var scale3d = _uiParticle.scale3DForCalc;
|
||||
dstPos = dstPos.GetScaled(inverseScale, scale3d.Inverse());
|
||||
|
||||
// Relative mode
|
||||
if (_uiParticle.positionMode == UIParticle.PositionMode.Relative)
|
||||
{
|
||||
var diff = _uiParticle.transform.position - psPos;
|
||||
diff.Scale(scale3d - inverseScale);
|
||||
diff.Scale(scale3d.Inverse());
|
||||
dstPos += diff;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying && !isLocalSpace)
|
||||
{
|
||||
dstPos += psPos - psPos.GetScaled(inverseScale, scale3d.Inverse());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return dstPos;
|
||||
}
|
||||
|
||||
private Vector3 GetAttractedPosition(Vector3 current, Vector3 target, float duration, float time)
|
||||
{
|
||||
var speed = m_MaxSpeed;
|
||||
switch (m_UpdateMode)
|
||||
{
|
||||
case UpdateMode.Normal:
|
||||
speed *= 60 * Time.deltaTime;
|
||||
break;
|
||||
case UpdateMode.UnscaledTime:
|
||||
speed *= 60 * Time.unscaledDeltaTime;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (m_Movement)
|
||||
{
|
||||
case Movement.Linear:
|
||||
speed /= duration;
|
||||
break;
|
||||
case Movement.Smooth:
|
||||
target = Vector3.Lerp(current, target, time / duration);
|
||||
break;
|
||||
case Movement.Sphere:
|
||||
target = Vector3.Slerp(current, target, time / duration);
|
||||
break;
|
||||
}
|
||||
|
||||
return Vector3.MoveTowards(current, target, speed);
|
||||
}
|
||||
|
||||
private void ApplyParticleSystem()
|
||||
{
|
||||
_uiParticle = null;
|
||||
if (m_ParticleSystem == null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isPlaying)
|
||||
#endif
|
||||
{
|
||||
Debug.LogError("No particle system attached to particle attractor script", this);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_uiParticle = m_ParticleSystem.GetComponentInParent<UIParticle>(true);
|
||||
if (_uiParticle && !_uiParticle.particles.Contains(m_ParticleSystem))
|
||||
{
|
||||
_uiParticle = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/UIParticleAttractor.cs.meta
Normal file
11
Runtime/UIParticleAttractor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00e55ae1441ff4583859c55384964d86
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Runtime/UIParticleProjectSettings.cs
Normal file
28
Runtime/UIParticleProjectSettings.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma warning disable CS0414
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
public class UIParticleProjectSettings : PreloadedProjectSettings<UIParticleProjectSettings>
|
||||
{
|
||||
[Header("Setting")]
|
||||
[SerializeField]
|
||||
internal bool m_EnableLinearToGamma = true;
|
||||
|
||||
public static bool enableLinearToGamma
|
||||
{
|
||||
get => instance.m_EnableLinearToGamma;
|
||||
set => instance.m_EnableLinearToGamma = value;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[SettingsProvider]
|
||||
private static SettingsProvider CreateSettingsProvider()
|
||||
{
|
||||
return new PreloadedProjectSettingsProvider("Project/UI/UI Particle");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Runtime/UIParticleProjectSettings.cs.meta
Normal file
11
Runtime/UIParticleProjectSettings.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f22a23b9d98e440478697f4adf30e61c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
700
Runtime/UIParticleRenderer.cs
Normal file
700
Runtime/UIParticleRenderer.cs
Normal file
@@ -0,0 +1,700 @@
|
||||
#if UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10
|
||||
#elif UNITY_2023_1_0 || UNITY_2023_1_1 || UNITY_2023_1_2 || UNITY_2023_1_3 || UNITY_2023_1_4 || UNITY_2023_1_5 || UNITY_2023_1_6 || UNITY_2023_1_7 || UNITY_2023_1_8 || UNITY_2023_1_9
|
||||
#elif UNITY_2023_1_10 || UNITY_2023_1_11 || UNITY_2023_1_12 || UNITY_2023_1_13 || UNITY_2023_1_14 || UNITY_2023_1_15 || UNITY_2023_1_16
|
||||
#elif UNITY_2022_3_OR_NEWER
|
||||
#define PS_BAKE_API_V2
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
[AddComponentMenu("")]
|
||||
internal class UIParticleRenderer : MaskableGraphic
|
||||
{
|
||||
private static readonly CombineInstance[] s_CombineInstances = { new CombineInstance() };
|
||||
private static readonly List<Material> s_Materials = new List<Material>(2);
|
||||
private static MaterialPropertyBlock s_Mpb;
|
||||
private static readonly List<UIParticleRenderer> s_Renderers = new List<UIParticleRenderer>(8);
|
||||
private static readonly Vector3[] s_Corners = new Vector3[4];
|
||||
private bool _delay;
|
||||
private int _index;
|
||||
private bool _isTrail;
|
||||
private Bounds _lastBounds;
|
||||
private Material _materialForRendering;
|
||||
private Material _modifiedMaterial;
|
||||
private UIParticle _parent;
|
||||
private ParticleSystem _particleSystem;
|
||||
private float _prevCanvasScale;
|
||||
private Vector3 _prevPsPos;
|
||||
private Vector3 _prevScale;
|
||||
private bool _isPrevStored;
|
||||
private Vector2Int _prevScreenSize;
|
||||
private bool _preWarm;
|
||||
private ParticleSystemRenderer _renderer;
|
||||
|
||||
public override Texture mainTexture => _isTrail ? null : _particleSystem.GetTextureForSprite();
|
||||
|
||||
public override bool raycastTarget => false;
|
||||
|
||||
private Rect rootCanvasRect
|
||||
{
|
||||
get
|
||||
{
|
||||
s_Corners[0] = transform.TransformPoint(_lastBounds.min.x, _lastBounds.min.y, 0);
|
||||
s_Corners[1] = transform.TransformPoint(_lastBounds.min.x, _lastBounds.max.y, 0);
|
||||
s_Corners[2] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.max.y, 0);
|
||||
s_Corners[3] = transform.TransformPoint(_lastBounds.max.x, _lastBounds.min.y, 0);
|
||||
if (canvas)
|
||||
{
|
||||
var worldToLocalMatrix = canvas.rootCanvas.transform.worldToLocalMatrix;
|
||||
for (var i = 0; i < 4; ++i)
|
||||
{
|
||||
s_Corners[i] = worldToLocalMatrix.MultiplyPoint(s_Corners[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var corner1 = (Vector2)s_Corners[0];
|
||||
var corner2 = (Vector2)s_Corners[0];
|
||||
for (var i = 1; i < 4; ++i)
|
||||
{
|
||||
if (s_Corners[i].x < corner1.x)
|
||||
{
|
||||
corner1.x = s_Corners[i].x;
|
||||
}
|
||||
else if (s_Corners[i].x > corner2.x)
|
||||
{
|
||||
corner2.x = s_Corners[i].x;
|
||||
}
|
||||
|
||||
if (s_Corners[i].y < corner1.y)
|
||||
{
|
||||
corner1.y = s_Corners[i].y;
|
||||
}
|
||||
else if (s_Corners[i].y > corner2.y)
|
||||
{
|
||||
corner2.y = s_Corners[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
return new Rect(corner1, corner2 - corner1);
|
||||
}
|
||||
}
|
||||
|
||||
public override Material materialForRendering
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_materialForRendering)
|
||||
{
|
||||
_materialForRendering = base.materialForRendering;
|
||||
}
|
||||
|
||||
return _materialForRendering;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset(int index = -1)
|
||||
{
|
||||
if (_renderer)
|
||||
{
|
||||
_renderer.enabled = true;
|
||||
}
|
||||
|
||||
_parent = null;
|
||||
_particleSystem = null;
|
||||
_renderer = null;
|
||||
if (0 <= index)
|
||||
{
|
||||
_index = index;
|
||||
}
|
||||
|
||||
//_emitter = null;
|
||||
if (this && isActiveAndEnabled)
|
||||
{
|
||||
material = null;
|
||||
canvasRenderer.Clear();
|
||||
_lastBounds = new Bounds();
|
||||
enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaterialRepository.Release(ref _modifiedMaterial);
|
||||
_materialForRendering = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
if (!s_CombineInstances[0].mesh)
|
||||
{
|
||||
s_CombineInstances[0].mesh = new Mesh
|
||||
{
|
||||
name = "[UIParticleRenderer] Combine Instance Mesh",
|
||||
hideFlags = HideFlags.HideAndDontSave
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
|
||||
MaterialRepository.Release(ref _modifiedMaterial);
|
||||
_materialForRendering = null;
|
||||
_isPrevStored = false;
|
||||
}
|
||||
|
||||
public static UIParticleRenderer AddRenderer(UIParticle parent, int index)
|
||||
{
|
||||
// Create renderer object.
|
||||
var go = new GameObject("[generated] UIParticleRenderer", typeof(UIParticleRenderer))
|
||||
{
|
||||
hideFlags = HideFlags.HideAndDontSave,
|
||||
layer = parent.gameObject.layer
|
||||
};
|
||||
|
||||
// Set parent.
|
||||
var transform = go.transform;
|
||||
transform.SetParent(parent.transform, false);
|
||||
transform.localPosition = Vector3.zero;
|
||||
transform.localRotation = Quaternion.identity;
|
||||
transform.localScale = Vector3.one;
|
||||
|
||||
// Add renderer component.
|
||||
var renderer = go.GetComponent<UIParticleRenderer>();
|
||||
renderer._parent = parent;
|
||||
renderer._index = index;
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform material modification in this function.
|
||||
/// </summary>
|
||||
public override Material GetModifiedMaterial(Material baseMaterial)
|
||||
{
|
||||
if (!IsActive() || !_parent)
|
||||
{
|
||||
MaterialRepository.Release(ref _modifiedMaterial);
|
||||
return baseMaterial;
|
||||
}
|
||||
|
||||
var modifiedMaterial = base.GetModifiedMaterial(baseMaterial);
|
||||
|
||||
//
|
||||
var texture = mainTexture;
|
||||
if (texture == null && _parent.m_AnimatableProperties.Length == 0)
|
||||
{
|
||||
MaterialRepository.Release(ref _modifiedMaterial);
|
||||
return modifiedMaterial;
|
||||
}
|
||||
|
||||
//
|
||||
var hash = new Hash128(
|
||||
modifiedMaterial ? (uint)modifiedMaterial.GetInstanceID() : 0,
|
||||
texture ? (uint)texture.GetInstanceID() : 0,
|
||||
0 < _parent.m_AnimatableProperties.Length ? (uint)GetInstanceID() : 0,
|
||||
#if UNITY_EDITOR
|
||||
(uint)EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode()
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
);
|
||||
if (!MaterialRepository.Valid(hash, _modifiedMaterial))
|
||||
{
|
||||
MaterialRepository.Get(hash, ref _modifiedMaterial, x => new Material(x.mat)
|
||||
{
|
||||
hideFlags = HideFlags.HideAndDontSave,
|
||||
mainTexture = x.texture ? x.texture : x.mat.mainTexture
|
||||
}, (mat: modifiedMaterial, texture));
|
||||
}
|
||||
|
||||
return _modifiedMaterial;
|
||||
}
|
||||
|
||||
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
|
||||
{
|
||||
_parent = parent;
|
||||
maskable = parent.maskable;
|
||||
|
||||
gameObject.layer = parent.gameObject.layer;
|
||||
|
||||
_particleSystem = ps;
|
||||
_preWarm = _particleSystem.main.prewarm;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isPlaying)
|
||||
#endif
|
||||
{
|
||||
if (_particleSystem.isPlaying || _preWarm)
|
||||
{
|
||||
_particleSystem.Clear();
|
||||
_particleSystem.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
ps.TryGetComponent(out _renderer);
|
||||
_renderer.enabled = false;
|
||||
|
||||
//_emitter = emitter;
|
||||
_isTrail = isTrail;
|
||||
|
||||
_renderer.GetSharedMaterials(s_Materials);
|
||||
material = s_Materials[isTrail ? 1 : 0];
|
||||
s_Materials.Clear();
|
||||
|
||||
// Support sprite.
|
||||
var tsa = ps.textureSheetAnimation;
|
||||
if (tsa.mode == ParticleSystemAnimationMode.Sprites && tsa.uvChannelMask == 0)
|
||||
{
|
||||
tsa.uvChannelMask = UVChannelFlags.UV0;
|
||||
}
|
||||
|
||||
_prevScale = GetWorldScale();
|
||||
_prevPsPos = _particleSystem.transform.position;
|
||||
_prevScreenSize = new Vector2Int(Screen.width, Screen.height);
|
||||
_prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
|
||||
_delay = true;
|
||||
|
||||
canvasRenderer.SetTexture(null);
|
||||
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
public void UpdateMesh(Camera bakeCamera)
|
||||
{
|
||||
// No particle to render: Clear mesh.
|
||||
if (
|
||||
!isActiveAndEnabled || !_particleSystem || !_parent
|
||||
|| !canvasRenderer || !canvas || !bakeCamera
|
||||
|| _parent.meshSharing == UIParticle.MeshSharing.Replica
|
||||
|| !transform.lossyScale.GetScaled(_parent.scale3DForCalc).IsVisible() // Scale is not visible.
|
||||
|| (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle.
|
||||
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|| canvasRenderer.GetInheritedAlpha() <
|
||||
0.01f // #102: Do not bake particle system to mesh when the alpha is zero.
|
||||
#endif
|
||||
)
|
||||
{
|
||||
Profiler.BeginSample("[UIParticleRenderer] Clear Mesh");
|
||||
workerMesh.Clear();
|
||||
canvasRenderer.SetMesh(workerMesh);
|
||||
_lastBounds = new Bounds();
|
||||
Profiler.EndSample();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var main = _particleSystem.main;
|
||||
var scale = GetWorldScale();
|
||||
var psPos = _particleSystem.transform.position;
|
||||
|
||||
// Simulate particles.
|
||||
Profiler.BeginSample("[UIParticle] Bake Mesh > Simulate Particles");
|
||||
if (!_isTrail && _parent.canSimulate)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
SimulateForEditor(psPos - _prevPsPos, scale);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ResolveResolutionChange(psPos, scale);
|
||||
Simulate(scale, _parent.isPaused || _delay);
|
||||
|
||||
if (_delay && !_parent.isPaused)
|
||||
{
|
||||
Simulate(scale, _parent.isPaused);
|
||||
}
|
||||
|
||||
// When the ParticleSystem simulation is complete, stop it.
|
||||
if (!main.loop
|
||||
&& main.duration <= _particleSystem.time
|
||||
&& (_particleSystem.IsAlive() || _particleSystem.particleCount == 0)
|
||||
)
|
||||
{
|
||||
_particleSystem.Stop(false);
|
||||
}
|
||||
}
|
||||
|
||||
_prevScale = scale;
|
||||
_prevPsPos = psPos;
|
||||
_delay = false;
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
// Bake mesh.
|
||||
Profiler.BeginSample("[UIParticleRenderer] Bake Mesh");
|
||||
s_CombineInstances[0].mesh.Clear(false);
|
||||
|
||||
// Assertion failed on expression: 'ps->array_size()' #278
|
||||
var extends = s_CombineInstances[0].mesh.bounds.extents.x;
|
||||
if (!float.IsNaN(extends) && !float.IsInfinity(extends) && 0 < extends)
|
||||
{
|
||||
s_CombineInstances[0].mesh.RecalculateBounds();
|
||||
}
|
||||
|
||||
if (_isTrail && _parent.canSimulate && 0 < _particleSystem.particleCount)
|
||||
{
|
||||
#if PS_BAKE_API_V2
|
||||
_renderer.BakeTrailsMesh(s_CombineInstances[0].mesh, bakeCamera,
|
||||
ParticleSystemBakeMeshOptions.BakeRotationAndScale);
|
||||
#else
|
||||
_renderer.BakeTrailsMesh(s_CombineInstances[0].mesh, bakeCamera, true);
|
||||
#endif
|
||||
}
|
||||
else if (!_isTrail && _renderer.CanBakeMesh())
|
||||
{
|
||||
_particleSystem.ValidateShape();
|
||||
#if PS_BAKE_API_V2
|
||||
_renderer.BakeMesh(s_CombineInstances[0].mesh, bakeCamera,
|
||||
ParticleSystemBakeMeshOptions.BakeRotationAndScale);
|
||||
#else
|
||||
_renderer.BakeMesh(s_CombineInstances[0].mesh, bakeCamera, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Too many vertices to render.
|
||||
if (65535 <= s_CombineInstances[0].mesh.vertexCount)
|
||||
{
|
||||
Debug.LogErrorFormat(this,
|
||||
"Too many vertices to render. index={0}, isTrail={1}, vertexCount={2}(>=65535)",
|
||||
_index,
|
||||
_isTrail,
|
||||
s_CombineInstances[0].mesh.vertexCount
|
||||
);
|
||||
s_CombineInstances[0].mesh.Clear(false);
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
// Combine mesh to transform. ([ParticleSystem local ->] world -> renderer local)
|
||||
Profiler.BeginSample("[UIParticleRenderer] Combine Mesh");
|
||||
if (_parent.canSimulate)
|
||||
{
|
||||
if (_parent.positionMode == UIParticle.PositionMode.Absolute)
|
||||
{
|
||||
s_CombineInstances[0].transform =
|
||||
canvasRenderer.transform.worldToLocalMatrix
|
||||
* GetWorldMatrix(psPos, scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
var diff = _particleSystem.transform.position - _parent.transform.position;
|
||||
s_CombineInstances[0].transform =
|
||||
canvasRenderer.transform.worldToLocalMatrix
|
||||
* Matrix4x4.Translate(diff.GetScaled(scale - Vector3.one))
|
||||
* GetWorldMatrix(psPos, scale);
|
||||
}
|
||||
|
||||
workerMesh.CombineMeshes(s_CombineInstances, true, true);
|
||||
|
||||
workerMesh.RecalculateBounds();
|
||||
var bounds = workerMesh.bounds;
|
||||
var center = bounds.center;
|
||||
center.z = 0;
|
||||
bounds.center = center;
|
||||
var extents = bounds.extents;
|
||||
extents.z = 0;
|
||||
bounds.extents = extents;
|
||||
workerMesh.bounds = bounds;
|
||||
_lastBounds = bounds;
|
||||
|
||||
// Convert linear color to gamma color.
|
||||
if (UIParticleProjectSettings.enableLinearToGamma && canvas.ShouldGammaToLinearInMesh())
|
||||
{
|
||||
workerMesh.LinearToGamma();
|
||||
}
|
||||
|
||||
var components = ListPool<Component>.Rent();
|
||||
GetComponents(typeof(IMeshModifier), components);
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
for (var i = 0; i < components.Count; i++)
|
||||
{
|
||||
((IMeshModifier)components[i]).ModifyMesh(workerMesh);
|
||||
}
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
ListPool<Component>.Return(ref components);
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
// Update animatable material properties.
|
||||
Profiler.BeginSample("[UIParticleRenderer] Update Animatable Material Properties");
|
||||
UpdateMaterialProperties();
|
||||
Profiler.EndSample();
|
||||
|
||||
// Get grouped renderers.
|
||||
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
|
||||
s_Renderers.Clear();
|
||||
if (_parent.useMeshSharing)
|
||||
{
|
||||
UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, s_Renderers);
|
||||
}
|
||||
|
||||
for (var i = 0; i < s_Renderers.Count; i++)
|
||||
{
|
||||
if (s_Renderers[i] == this) continue;
|
||||
|
||||
s_Renderers[i].canvasRenderer.SetMesh(workerMesh);
|
||||
s_Renderers[i]._lastBounds = _lastBounds;
|
||||
s_Renderers[i].canvasRenderer.materialCount = 1;
|
||||
s_Renderers[i].canvasRenderer.SetMaterial(materialForRendering, 0);
|
||||
}
|
||||
|
||||
if (_parent.canRender)
|
||||
{
|
||||
canvasRenderer.SetMesh(workerMesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
workerMesh.Clear();
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
s_Renderers.Clear();
|
||||
}
|
||||
|
||||
public override void SetMaterialDirty()
|
||||
{
|
||||
_materialForRendering = null;
|
||||
base.SetMaterialDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call to update the geometry of the Graphic onto the CanvasRenderer.
|
||||
/// </summary>
|
||||
protected override void UpdateGeometry()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Cull(Rect clipRect, bool validRect)
|
||||
{
|
||||
var cull = _lastBounds.extents == Vector3.zero
|
||||
|| !validRect
|
||||
|| !clipRect.Overlaps(rootCanvasRect, true);
|
||||
if (canvasRenderer.cull == cull) return;
|
||||
|
||||
canvasRenderer.cull = cull;
|
||||
UISystemProfilerApi.AddMarker("MaskableGraphic.cullingChanged", this);
|
||||
onCullStateChanged.Invoke(cull);
|
||||
OnCullingChanged();
|
||||
}
|
||||
|
||||
private Vector3 GetWorldScale()
|
||||
{
|
||||
Profiler.BeginSample("[UIParticleRenderer] GetWorldScale");
|
||||
var scale = _parent.scale3DForCalc.GetScaled(_parent.parentScale);
|
||||
|
||||
if (_parent.autoScalingMode == UIParticle.AutoScalingMode.UIParticle
|
||||
&& _particleSystem.main.scalingMode == ParticleSystemScalingMode.Local
|
||||
&& _parent.canvas)
|
||||
{
|
||||
scale = scale.GetScaled(_parent.canvas.rootCanvas.transform.localScale);
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
return scale;
|
||||
}
|
||||
|
||||
private Matrix4x4 GetWorldMatrix(Vector3 psPos, Vector3 scale)
|
||||
{
|
||||
var space = _particleSystem.GetActualSimulationSpace();
|
||||
if (_isTrail && _particleSystem.trails.worldSpace)
|
||||
{
|
||||
space = ParticleSystemSimulationSpace.World;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
switch (space)
|
||||
{
|
||||
case ParticleSystemSimulationSpace.World:
|
||||
return Matrix4x4.Translate(psPos)
|
||||
* Matrix4x4.Scale(scale)
|
||||
* Matrix4x4.Translate(-psPos);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (space)
|
||||
{
|
||||
case ParticleSystemSimulationSpace.Local:
|
||||
return Matrix4x4.Translate(psPos)
|
||||
* Matrix4x4.Scale(scale);
|
||||
case ParticleSystemSimulationSpace.World:
|
||||
return Matrix4x4.Scale(scale);
|
||||
case ParticleSystemSimulationSpace.Custom:
|
||||
return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))
|
||||
* Matrix4x4.Scale(scale);
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For world simulation, interpolate particle positions when the screen size is changed.
|
||||
/// </summary>
|
||||
/// <param name="psPos"></param>
|
||||
/// <param name="scale"></param>
|
||||
private void ResolveResolutionChange(Vector3 psPos, Vector3 scale)
|
||||
{
|
||||
var screenSize = new Vector2Int(Screen.width, Screen.height);
|
||||
var isWorldSpace = _particleSystem.IsWorldSpace();
|
||||
var canvasScale = _parent.canvas ? _parent.canvas.scaleFactor : 1f;
|
||||
var resolutionChanged = _prevScreenSize != screenSize
|
||||
|| !Mathf.Approximately(_prevCanvasScale, canvasScale);
|
||||
if (resolutionChanged && isWorldSpace && _isPrevStored)
|
||||
{
|
||||
// Update particle array size and get particles.
|
||||
var size = _particleSystem.particleCount;
|
||||
var particles = ParticleSystemExtensions.GetParticleArray(size);
|
||||
_particleSystem.GetParticles(particles, size);
|
||||
|
||||
// Resolution resolver:
|
||||
// (psPos / scale) / (prevPsPos / prevScale) -> psPos * scale.inv * prevPsPos.inv * prevScale
|
||||
var modifier = psPos.GetScaled(
|
||||
scale.Inverse(),
|
||||
_prevPsPos.Inverse(),
|
||||
_prevScale);
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
var particle = particles[i];
|
||||
particle.position = particle.position.GetScaled(modifier);
|
||||
particles[i] = particle;
|
||||
}
|
||||
|
||||
_particleSystem.SetParticles(particles, size);
|
||||
|
||||
// Delay: Do not progress in the frame where the resolution has been changed.
|
||||
_delay = true;
|
||||
_prevScale = scale;
|
||||
_prevPsPos = psPos;
|
||||
_isPrevStored = true;
|
||||
}
|
||||
|
||||
_prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
|
||||
_prevScreenSize = screenSize;
|
||||
}
|
||||
|
||||
private void Simulate(Vector3 scale, bool paused)
|
||||
{
|
||||
var main = _particleSystem.main;
|
||||
var deltaTime = paused
|
||||
? 0
|
||||
: main.useUnscaledTime
|
||||
? Time.unscaledDeltaTime
|
||||
: Time.deltaTime;
|
||||
|
||||
// Pre-warm:
|
||||
if (0 < deltaTime && _preWarm)
|
||||
{
|
||||
deltaTime += main.duration;
|
||||
_preWarm = false;
|
||||
}
|
||||
|
||||
// get world position.
|
||||
var isLocalSpace = _particleSystem.IsLocalSpace();
|
||||
var psTransform = _particleSystem.transform;
|
||||
var originLocalPosition = psTransform.localPosition;
|
||||
var originLocalRotation = psTransform.localRotation;
|
||||
var originWorldPosition = psTransform.position;
|
||||
var originWorldRotation = psTransform.rotation;
|
||||
var emission = _particleSystem.emission;
|
||||
var rateOverDistance = emission.enabled
|
||||
&& 0 < emission.rateOverDistance.constant
|
||||
&& 0 < emission.rateOverDistanceMultiplier;
|
||||
if (rateOverDistance && !paused && _isPrevStored)
|
||||
{
|
||||
// (For rate-over-distance emission,) Move to previous scaled position, simulate (delta = 0).
|
||||
var prevScaledPos = isLocalSpace
|
||||
? _prevPsPos
|
||||
: _prevPsPos.GetScaled(_prevScale.Inverse());
|
||||
psTransform.SetPositionAndRotation(prevScaledPos, originWorldRotation);
|
||||
_particleSystem.Simulate(0, false, false, false);
|
||||
}
|
||||
|
||||
// Move to scaled position, simulate, revert to origin position.
|
||||
var scaledPos = isLocalSpace
|
||||
? originWorldPosition
|
||||
: originWorldPosition.GetScaled(scale.Inverse());
|
||||
psTransform.SetPositionAndRotation(scaledPos, originWorldRotation);
|
||||
_particleSystem.Simulate(deltaTime, false, false, false);
|
||||
psTransform.localPosition = originLocalPosition;
|
||||
psTransform.localRotation = originLocalRotation;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void SimulateForEditor(Vector3 diffPos, Vector3 scale)
|
||||
{
|
||||
// Extra world simulation.
|
||||
var isWorldSpace = _particleSystem.IsWorldSpace();
|
||||
if (isWorldSpace && 0 < Vector3.SqrMagnitude(diffPos))
|
||||
{
|
||||
Profiler.BeginSample("[UIParticle] Bake Mesh > Extra world simulation");
|
||||
diffPos.x *= 1f - 1f / Mathf.Max(0.001f, scale.x);
|
||||
diffPos.y *= 1f - 1f / Mathf.Max(0.001f, scale.y);
|
||||
diffPos.z *= 1f - 1f / Mathf.Max(0.001f, scale.z);
|
||||
|
||||
var size = _particleSystem.particleCount;
|
||||
var particles = ParticleSystemExtensions.GetParticleArray(size);
|
||||
_particleSystem.GetParticles(particles, size);
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
var p = particles[i];
|
||||
p.position += diffPos;
|
||||
particles[i] = p;
|
||||
}
|
||||
|
||||
_particleSystem.SetParticles(particles, size);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void UpdateMaterialProperties()
|
||||
{
|
||||
if (_parent.m_AnimatableProperties.Length == 0) return;
|
||||
|
||||
if (s_Mpb == null)
|
||||
{
|
||||
s_Mpb = new MaterialPropertyBlock();
|
||||
}
|
||||
|
||||
_renderer.GetPropertyBlock(s_Mpb);
|
||||
if (s_Mpb.isEmpty) return;
|
||||
|
||||
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
||||
if (!materialForRendering) return;
|
||||
|
||||
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
|
||||
{
|
||||
var ap = _parent.m_AnimatableProperties[i];
|
||||
ap.UpdateMaterialProperties(materialForRendering, s_Mpb);
|
||||
}
|
||||
|
||||
s_Mpb.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/UIParticleRenderer.cs.meta
Normal file
11
Runtime/UIParticleRenderer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e66d2d1ba43c4cc4bc3e754e403297b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
121
Runtime/UIParticleUpdater.cs
Normal file
121
Runtime/UIParticleUpdater.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System.Collections.Generic;
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
internal static class UIParticleUpdater
|
||||
{
|
||||
private static readonly List<UIParticle> s_ActiveParticles = new List<UIParticle>();
|
||||
private static readonly List<UIParticleAttractor> s_ActiveAttractors = new List<UIParticleAttractor>();
|
||||
private static readonly HashSet<int> s_UpdatedGroupIds = new HashSet<int>();
|
||||
private static int s_FrameCount;
|
||||
|
||||
public static int uiParticleCount => s_ActiveParticles.Count;
|
||||
|
||||
public static void Register(UIParticle particle)
|
||||
{
|
||||
if (!particle) return;
|
||||
s_ActiveParticles.Add(particle);
|
||||
}
|
||||
|
||||
public static void Unregister(UIParticle particle)
|
||||
{
|
||||
if (!particle) return;
|
||||
s_ActiveParticles.Remove(particle);
|
||||
}
|
||||
|
||||
public static void Register(UIParticleAttractor attractor)
|
||||
{
|
||||
if (!attractor) return;
|
||||
s_ActiveAttractors.Add(attractor);
|
||||
}
|
||||
|
||||
public static void Unregister(UIParticleAttractor attractor)
|
||||
{
|
||||
if (!attractor) return;
|
||||
s_ActiveAttractors.Remove(attractor);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnLoadMethod]
|
||||
#else
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
#endif
|
||||
private static void InitializeOnLoad()
|
||||
{
|
||||
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
|
||||
}
|
||||
|
||||
private static void Refresh()
|
||||
{
|
||||
// Do not allow it to be called in the same frame.
|
||||
if (s_FrameCount == Time.frameCount) return;
|
||||
s_FrameCount = Time.frameCount;
|
||||
|
||||
// Simulate -> Primary
|
||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||
{
|
||||
var uip = s_ActiveParticles[i];
|
||||
if (!uip || !uip.canvas || !uip.isPrimary || !s_UpdatedGroupIds.Add(uip.groupId)) continue;
|
||||
|
||||
uip.UpdateTransformScale();
|
||||
uip.UpdateRenderers();
|
||||
}
|
||||
|
||||
// Simulate -> Others
|
||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||
{
|
||||
var uip = s_ActiveParticles[i];
|
||||
if (!uip || !uip.canvas) continue;
|
||||
|
||||
uip.UpdateTransformScale();
|
||||
|
||||
if (!uip.useMeshSharing)
|
||||
{
|
||||
uip.UpdateRenderers();
|
||||
}
|
||||
else if (s_UpdatedGroupIds.Add(uip.groupId))
|
||||
{
|
||||
uip.UpdateRenderers();
|
||||
}
|
||||
}
|
||||
|
||||
s_UpdatedGroupIds.Clear();
|
||||
|
||||
// Attract
|
||||
for (var i = 0; i < s_ActiveAttractors.Count; i++)
|
||||
{
|
||||
s_ActiveAttractors[i].Attract();
|
||||
}
|
||||
}
|
||||
|
||||
public static void GetGroupedRenderers(int groupId, int index, List<UIParticleRenderer> results)
|
||||
{
|
||||
results.Clear();
|
||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||
{
|
||||
var uip = s_ActiveParticles[i];
|
||||
if (uip.useMeshSharing && uip.groupId == groupId)
|
||||
{
|
||||
results.Add(uip.GetRenderer(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static UIParticle GetPrimary(int groupId)
|
||||
{
|
||||
UIParticle primary = null;
|
||||
for (var i = 0; i < s_ActiveParticles.Count; i++)
|
||||
{
|
||||
var uip = s_ActiveParticles[i];
|
||||
if (!uip.useMeshSharing || uip.groupId != groupId) continue;
|
||||
if (uip.isPrimary) return uip;
|
||||
if (!primary && uip.canSimulate) primary = uip;
|
||||
}
|
||||
|
||||
return primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Runtime/Utilities.meta
Normal file
8
Runtime/Utilities.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66c42f0f30de84ca4bd8305a1188af85
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
175
Runtime/Utilities/ParticleSystemExtensions.cs
Normal file
175
Runtime/Utilities/ParticleSystemExtensions.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class ParticleSystemExtensions
|
||||
{
|
||||
private static ParticleSystem.Particle[] s_TmpParticles = new ParticleSystem.Particle[2048];
|
||||
|
||||
public static ParticleSystem.Particle[] GetParticleArray(int size)
|
||||
{
|
||||
if (s_TmpParticles.Length < size)
|
||||
{
|
||||
while (s_TmpParticles.Length < size)
|
||||
{
|
||||
size = Mathf.NextPowerOfTwo(size);
|
||||
}
|
||||
|
||||
s_TmpParticles = new ParticleSystem.Particle[size];
|
||||
}
|
||||
|
||||
return s_TmpParticles;
|
||||
}
|
||||
|
||||
public static void ValidateShape(this ParticleSystem self)
|
||||
{
|
||||
var shape = self.shape;
|
||||
if (shape.enabled && shape.alignToDirection)
|
||||
{
|
||||
if (Mathf.Approximately(shape.scale.x * shape.scale.y * shape.scale.z, 0))
|
||||
{
|
||||
if (Mathf.Approximately(shape.scale.x, 0))
|
||||
{
|
||||
shape.scale.Set(0.0001f, shape.scale.y, shape.scale.z);
|
||||
}
|
||||
else if (Mathf.Approximately(shape.scale.y, 0))
|
||||
{
|
||||
shape.scale.Set(shape.scale.x, 0.0001f, shape.scale.z);
|
||||
}
|
||||
else if (Mathf.Approximately(shape.scale.z, 0))
|
||||
{
|
||||
shape.scale.Set(shape.scale.x, shape.scale.y, 0.0001f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CanBakeMesh(this ParticleSystemRenderer self)
|
||||
{
|
||||
// #69: Editor crashes when mesh is set to null when `ParticleSystem.RenderMode = Mesh`
|
||||
if (self.renderMode == ParticleSystemRenderMode.Mesh && self.mesh == null) return false;
|
||||
|
||||
// #61: When `ParticleSystem.RenderMode = None`, an error occurs
|
||||
if (self.renderMode == ParticleSystemRenderMode.None) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ParticleSystemSimulationSpace GetActualSimulationSpace(this ParticleSystem self)
|
||||
{
|
||||
var main = self.main;
|
||||
var space = main.simulationSpace;
|
||||
if (space == ParticleSystemSimulationSpace.Custom && !main.customSimulationSpace)
|
||||
{
|
||||
space = ParticleSystemSimulationSpace.Local;
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
public static bool IsLocalSpace(this ParticleSystem self)
|
||||
{
|
||||
return GetActualSimulationSpace(self) == ParticleSystemSimulationSpace.Local;
|
||||
}
|
||||
|
||||
public static bool IsWorldSpace(this ParticleSystem self)
|
||||
{
|
||||
return GetActualSimulationSpace(self) == ParticleSystemSimulationSpace.World;
|
||||
}
|
||||
|
||||
public static void SortForRendering(this List<ParticleSystem> self, Transform transform, bool sortByMaterial)
|
||||
{
|
||||
self.Sort((a, b) =>
|
||||
{
|
||||
var aRenderer = a.GetComponent<ParticleSystemRenderer>();
|
||||
var bRenderer = b.GetComponent<ParticleSystemRenderer>();
|
||||
|
||||
// Render queue: ascending
|
||||
var aMat = aRenderer.sharedMaterial ? aRenderer.sharedMaterial : aRenderer.trailMaterial;
|
||||
var bMat = bRenderer.sharedMaterial ? bRenderer.sharedMaterial : bRenderer.trailMaterial;
|
||||
if (!aMat && !bMat) return 0;
|
||||
if (!aMat) return -1;
|
||||
if (!bMat) return 1;
|
||||
|
||||
if (sortByMaterial)
|
||||
{
|
||||
return aMat.GetInstanceID() - bMat.GetInstanceID();
|
||||
}
|
||||
|
||||
if (aMat.renderQueue != bMat.renderQueue)
|
||||
{
|
||||
return aMat.renderQueue - bMat.renderQueue;
|
||||
}
|
||||
|
||||
// Sorting layer: ascending
|
||||
if (aRenderer.sortingLayerID != bRenderer.sortingLayerID)
|
||||
{
|
||||
return SortingLayer.GetLayerValueFromID(aRenderer.sortingLayerID) -
|
||||
SortingLayer.GetLayerValueFromID(bRenderer.sortingLayerID);
|
||||
}
|
||||
|
||||
// Sorting order: ascending
|
||||
if (aRenderer.sortingOrder != bRenderer.sortingOrder)
|
||||
{
|
||||
return aRenderer.sortingOrder - bRenderer.sortingOrder;
|
||||
}
|
||||
|
||||
// Z position & sortingFudge: descending
|
||||
var aTransform = a.transform;
|
||||
var bTransform = b.transform;
|
||||
var aPos = transform.InverseTransformPoint(aTransform.position).z + aRenderer.sortingFudge;
|
||||
var bPos = transform.InverseTransformPoint(bTransform.position).z + bRenderer.sortingFudge;
|
||||
if (!Mathf.Approximately(aPos, bPos))
|
||||
{
|
||||
return (int)Mathf.Sign(bPos - aPos);
|
||||
}
|
||||
|
||||
return (int)Mathf.Sign(GetIndex(self, a) - GetIndex(self, b));
|
||||
});
|
||||
}
|
||||
|
||||
private static int GetIndex(IList<ParticleSystem> list, Object ps)
|
||||
{
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (list[i].GetInstanceID() == ps.GetInstanceID())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static Texture2D GetTextureForSprite(this ParticleSystem self)
|
||||
{
|
||||
if (!self) return null;
|
||||
|
||||
// Get sprite's texture.
|
||||
var tsaModule = self.textureSheetAnimation;
|
||||
if (!tsaModule.enabled || tsaModule.mode != ParticleSystemAnimationMode.Sprites) return null;
|
||||
|
||||
for (var i = 0; i < tsaModule.spriteCount; i++)
|
||||
{
|
||||
var sprite = tsaModule.GetSprite(i);
|
||||
if (!sprite) continue;
|
||||
|
||||
return sprite.GetActualTexture();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void Exec(this List<ParticleSystem> self, Action<ParticleSystem> action)
|
||||
{
|
||||
foreach (var p in self)
|
||||
{
|
||||
if (!p) continue;
|
||||
action.Invoke(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Utilities/ParticleSystemExtensions.cs.meta
Normal file
11
Runtime/Utilities/ParticleSystemExtensions.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e51604bfb810e44519e2710fd1b8af90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 064daa6b97d6846ec9334e98d642f081
|
||||
DefaultImporter:
|
||||
userData:
|
||||
@@ -1,85 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Coffee.UIExtensions;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
public class CFX_Demo_With_UIParticle : MonoBehaviour
|
||||
{
|
||||
private UIParticle UiParticle;
|
||||
private Toggle spawnOnUI;
|
||||
private MonoBehaviour demo;
|
||||
|
||||
// Start is called before the first frame update
|
||||
private void Start()
|
||||
{
|
||||
UiParticle = GetComponentInChildren<UIParticle>();
|
||||
spawnOnUI = GetComponentInChildren<Toggle>();
|
||||
|
||||
demo = FindObjectOfType("CFX_Demo_New") as MonoBehaviour
|
||||
?? FindObjectOfType("WFX_Demo_New") as MonoBehaviour;
|
||||
|
||||
SetCanvasWidth(800);
|
||||
SetCanvasRenderOverlay(true);
|
||||
}
|
||||
|
||||
private Object FindObjectOfType(string typeName)
|
||||
{
|
||||
var type = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(x => x.GetTypes())
|
||||
.FirstOrDefault(x => x.Name == typeName);
|
||||
|
||||
return type == null ? null : FindObjectOfType(type);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
private void Update()
|
||||
{
|
||||
if (!spawnOnUI.isOn || !demo || !Input.GetMouseButtonDown(0)) return;
|
||||
|
||||
foreach (Transform child in UiParticle.transform)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
var particle = demo.GetType()
|
||||
.GetMethod("spawnParticle", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Invoke(demo, new object[0]) as GameObject;
|
||||
particle.transform.localScale = Vector3.one;
|
||||
UiParticle.SetParticleSystemInstance(particle);
|
||||
}
|
||||
|
||||
public void SetCanvasWidth(int width)
|
||||
{
|
||||
var scaler = GetComponentInParent<CanvasScaler>();
|
||||
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
|
||||
scaler.matchWidthOrHeight = 0;
|
||||
var resolution = scaler.referenceResolution;
|
||||
resolution.x = width;
|
||||
scaler.referenceResolution = resolution;
|
||||
}
|
||||
|
||||
public void SetCanvasRenderOverlay(bool enable)
|
||||
{
|
||||
var canvas = GetComponentInParent<Canvas>();
|
||||
if (enable)
|
||||
{
|
||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
}
|
||||
else
|
||||
{
|
||||
canvas.worldCamera = Camera.main;
|
||||
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
||||
canvas.planeDistance = 5;
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadScene(string scene)
|
||||
{
|
||||
SceneManager.LoadScene(scene);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
Cartoon FX & War FX Demo
|
||||
===
|
||||
|
||||
Please import assets "Cartoon FX Free" and/or "War FX Free" from Unity asset store.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a81f9cd434f104e1fad7ffa20eb7a3d4
|
||||
DefaultImporter:
|
||||
userData:
|
||||
8
Samples~/Demo/Animations.meta
Normal file
8
Samples~/Demo/Animations.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 097ebac92791448c1871b0dffb43c4c6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
339
Samples~/Demo/Animations/UIParticle_Demo_Animatable.controller
Normal file
339
Samples~/Demo/Animations/UIParticle_Demo_Animatable.controller
Normal file
@@ -0,0 +1,339 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Animatable
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters: []
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
m_StateMachine: {fileID: 1107990299158400902}
|
||||
m_Mask: {fileID: 0}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
--- !u!74 &74971957227727780
|
||||
AnimationClip:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Animatable
|
||||
serializedVersion: 6
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 1
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves: []
|
||||
m_ScaleCurves: []
|
||||
m_FloatCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: material._MainTex_ST.x
|
||||
path:
|
||||
classID: 199
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: material._MainTex_ST.y
|
||||
path:
|
||||
classID: 199
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: material._MainTex_ST.z
|
||||
path:
|
||||
classID: 199
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: -0.6
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 1
|
||||
value: 0.6
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 1.5
|
||||
value: 0.6
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: material._MainTex_ST.w
|
||||
path:
|
||||
classID: 199
|
||||
script: {fileID: 0}
|
||||
m_PPtrCurves: []
|
||||
m_SampleRate: 30
|
||||
m_WrapMode: 0
|
||||
m_Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_ClipBindingConstant:
|
||||
genericBindings:
|
||||
- serializedVersion: 2
|
||||
path: 0
|
||||
attribute: 914802057
|
||||
script: {fileID: 0}
|
||||
typeID: 199
|
||||
customType: 22
|
||||
isPPtrCurve: 0
|
||||
- serializedVersion: 2
|
||||
path: 0
|
||||
attribute: 109495689
|
||||
script: {fileID: 0}
|
||||
typeID: 199
|
||||
customType: 22
|
||||
isPPtrCurve: 0
|
||||
- serializedVersion: 2
|
||||
path: 0
|
||||
attribute: 377931145
|
||||
script: {fileID: 0}
|
||||
typeID: 199
|
||||
customType: 22
|
||||
isPPtrCurve: 0
|
||||
- serializedVersion: 2
|
||||
path: 0
|
||||
attribute: 646366601
|
||||
script: {fileID: 0}
|
||||
typeID: 199
|
||||
customType: 22
|
||||
isPPtrCurve: 0
|
||||
pptrCurveMapping: []
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 1.5
|
||||
m_OrientationOffsetY: 0
|
||||
m_Level: 0
|
||||
m_CycleOffset: 0
|
||||
m_HasAdditiveReferencePose: 0
|
||||
m_LoopTime: 1
|
||||
m_LoopBlend: 0
|
||||
m_LoopBlendOrientation: 0
|
||||
m_LoopBlendPositionY: 0
|
||||
m_LoopBlendPositionXZ: 0
|
||||
m_KeepOriginalOrientation: 0
|
||||
m_KeepOriginalPositionY: 1
|
||||
m_KeepOriginalPositionXZ: 0
|
||||
m_HeightFromFeet: 0
|
||||
m_Mirror: 0
|
||||
m_EditorCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: material._MainTex_ST.x
|
||||
path:
|
||||
classID: 199
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: material._MainTex_ST.y
|
||||
path:
|
||||
classID: 199
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: material._MainTex_ST.z
|
||||
path:
|
||||
classID: 199
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: -0.6
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 1
|
||||
value: 0.6
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 1.5
|
||||
value: 0.6
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: material._MainTex_ST.w
|
||||
path:
|
||||
classID: 199
|
||||
script: {fileID: 0}
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events: []
|
||||
--- !u!1102 &1102093862037490004
|
||||
AnimatorState:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Play
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 74971957227727780}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1107 &1107990299158400902
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Base Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 1102093862037490004}
|
||||
m_Position: {x: 288, y: 48, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 48, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: 1102093862037490004}
|
||||
4
Samples~/Demo/UIParticle_Demo.renderTexture.meta → Samples~/Demo/Animations/UIParticle_Demo_Animatable.controller.meta
Normal file → Executable file
4
Samples~/Demo/UIParticle_Demo.renderTexture.meta → Samples~/Demo/Animations/UIParticle_Demo_Animatable.controller.meta
Normal file → Executable file
@@ -1,8 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab4cc8f5f51c14175af41c4daa68cbf5
|
||||
guid: 23dca587da071cd41ac3a7fc070bea5c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 8400000
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
268
Samples~/Demo/Animations/UIParticle_Demo_Pop.controller
Normal file
268
Samples~/Demo/Animations/UIParticle_Demo_Pop.controller
Normal file
@@ -0,0 +1,268 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Pop
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters: []
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
m_StateMachine: {fileID: 1107303963999173640}
|
||||
m_Mask: {fileID: 0}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
--- !u!74 &74513151621551130
|
||||
AnimationClip:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Pop
|
||||
serializedVersion: 6
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 1
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves: []
|
||||
m_ScaleCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: {x: 1, y: 1, z: 1}
|
||||
inSlope: {x: 0, y: 0, z: 0}
|
||||
outSlope: {x: 0, y: 0, z: 0}
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
|
||||
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
|
||||
- serializedVersion: 3
|
||||
time: 0.06666667
|
||||
value: {x: 1.5, y: 1.5, z: 1.5}
|
||||
inSlope: {x: 0, y: 0, z: 0}
|
||||
outSlope: {x: 0, y: 0, z: 0}
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
|
||||
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
|
||||
- serializedVersion: 3
|
||||
time: 0.5
|
||||
value: {x: 1, y: 1, z: 1}
|
||||
inSlope: {x: 0, y: 0, z: 0}
|
||||
outSlope: {x: 0, y: 0, z: 0}
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
|
||||
outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334}
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
path:
|
||||
m_FloatCurves: []
|
||||
m_PPtrCurves: []
|
||||
m_SampleRate: 30
|
||||
m_WrapMode: 0
|
||||
m_Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_ClipBindingConstant:
|
||||
genericBindings: []
|
||||
pptrCurveMapping: []
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 0.5
|
||||
m_OrientationOffsetY: 0
|
||||
m_Level: 0
|
||||
m_CycleOffset: 0
|
||||
m_HasAdditiveReferencePose: 0
|
||||
m_LoopTime: 0
|
||||
m_LoopBlend: 0
|
||||
m_LoopBlendOrientation: 0
|
||||
m_LoopBlendPositionY: 0
|
||||
m_LoopBlendPositionXZ: 0
|
||||
m_KeepOriginalOrientation: 0
|
||||
m_KeepOriginalPositionY: 1
|
||||
m_KeepOriginalPositionXZ: 0
|
||||
m_HeightFromFeet: 0
|
||||
m_Mirror: 0
|
||||
m_EditorCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.06666667
|
||||
value: 1.5
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.5
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_LocalScale.x
|
||||
path:
|
||||
classID: 224
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.06666667
|
||||
value: 1.5
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.5
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_LocalScale.y
|
||||
path:
|
||||
classID: 224
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.06666667
|
||||
value: 1.5
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.5
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_LocalScale.z
|
||||
path:
|
||||
classID: 224
|
||||
script: {fileID: 0}
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events: []
|
||||
--- !u!1102 &1102311490129699446
|
||||
AnimatorState:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Pop
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 74513151621551130}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1107 &1107303963999173640
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Base Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 1102311490129699446}
|
||||
m_Position: {x: 240, y: 96, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: 1102311490129699446}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: caa1268363f2e40dbb845db5e8e1b22a
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
215
Samples~/Demo/Animations/UIParticle_Demo_Wave.controller
Normal file
215
Samples~/Demo/Animations/UIParticle_Demo_Wave.controller
Normal file
@@ -0,0 +1,215 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Wave
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters: []
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
m_StateMachine: {fileID: 1107303963999173640}
|
||||
m_Mask: {fileID: 0}
|
||||
m_Motions: []
|
||||
m_Behaviours: []
|
||||
m_BlendingMode: 0
|
||||
m_SyncedLayerIndex: -1
|
||||
m_DefaultWeight: 0
|
||||
m_IKPass: 0
|
||||
m_SyncedLayerAffectsTiming: 0
|
||||
m_Controller: {fileID: 9100000}
|
||||
--- !u!74 &74084382941425094
|
||||
AnimationClip:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Wave
|
||||
serializedVersion: 6
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 1
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves: []
|
||||
m_ScaleCurves: []
|
||||
m_FloatCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 200
|
||||
tangentMode: 69
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.5
|
||||
value: 100
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 1.5
|
||||
value: -100
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 2
|
||||
value: 0
|
||||
inSlope: 200
|
||||
outSlope: 0
|
||||
tangentMode: 69
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_AnchoredPosition.y
|
||||
path:
|
||||
classID: 224
|
||||
script: {fileID: 0}
|
||||
m_PPtrCurves: []
|
||||
m_SampleRate: 30
|
||||
m_WrapMode: 0
|
||||
m_Bounds:
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
m_Extent: {x: 0, y: 0, z: 0}
|
||||
m_ClipBindingConstant:
|
||||
genericBindings: []
|
||||
pptrCurveMapping: []
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 2
|
||||
m_OrientationOffsetY: 0
|
||||
m_Level: 0
|
||||
m_CycleOffset: 0
|
||||
m_HasAdditiveReferencePose: 0
|
||||
m_LoopTime: 1
|
||||
m_LoopBlend: 0
|
||||
m_LoopBlendOrientation: 0
|
||||
m_LoopBlendPositionY: 0
|
||||
m_LoopBlendPositionXZ: 0
|
||||
m_KeepOriginalOrientation: 0
|
||||
m_KeepOriginalPositionY: 1
|
||||
m_KeepOriginalPositionXZ: 0
|
||||
m_HeightFromFeet: 0
|
||||
m_Mirror: 0
|
||||
m_EditorCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 200
|
||||
tangentMode: 69
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.5
|
||||
value: 100
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 1.5
|
||||
value: -100
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 2
|
||||
value: 0
|
||||
inSlope: 200
|
||||
outSlope: 0
|
||||
tangentMode: 69
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_AnchoredPosition.y
|
||||
path:
|
||||
classID: 224
|
||||
script: {fileID: 0}
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events: []
|
||||
--- !u!1102 &1102311490129699446
|
||||
AnimatorState:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Wave
|
||||
m_Speed: 1
|
||||
m_CycleOffset: 0
|
||||
m_Transitions: []
|
||||
m_StateMachineBehaviours: []
|
||||
m_Position: {x: 50, y: 50, z: 0}
|
||||
m_IKOnFeet: 0
|
||||
m_WriteDefaultValues: 1
|
||||
m_Mirror: 0
|
||||
m_SpeedParameterActive: 0
|
||||
m_MirrorParameterActive: 0
|
||||
m_CycleOffsetParameterActive: 0
|
||||
m_TimeParameterActive: 0
|
||||
m_Motion: {fileID: 74084382941425094}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1107 &1107303963999173640
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Base Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 1102311490129699446}
|
||||
m_Position: {x: 240, y: 96, z: 0}
|
||||
m_ChildStateMachines: []
|
||||
m_AnyStateTransitions: []
|
||||
m_EntryTransitions: []
|
||||
m_StateMachineTransitions: {}
|
||||
m_StateMachineBehaviours: []
|
||||
m_AnyStatePosition: {x: 50, y: 20, z: 0}
|
||||
m_EntryPosition: {x: 50, y: 120, z: 0}
|
||||
m_ExitPosition: {x: 800, y: 120, z: 0}
|
||||
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
|
||||
m_DefaultState: {fileID: 1102311490129699446}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e7d928ccc1b7404d80e0d0205434aeb
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Samples~/Demo/Materials.meta
Normal file
8
Samples~/Demo/Materials.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b9a6924ce61a4f099a4c610c8c78fd1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -5,8 +5,9 @@ Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Spread
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Animatable
|
||||
m_Shader: {fileID: 4800000, guid: ecfa8f5732b504ef98fba10aa18d0326, type: 3}
|
||||
m_ShaderKeywords:
|
||||
m_LightmapFlags: 4
|
||||
@@ -39,7 +40,7 @@ Material:
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Texture: {fileID: 2800000, guid: e834c7963556c9b4cbad7f1bee63f597, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
@@ -63,7 +64,6 @@ Material:
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _InvFade: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
@@ -77,9 +77,9 @@ Material:
|
||||
- _StencilReadMask: 255
|
||||
- _StencilWriteMask: 255
|
||||
- _UVSec: 0
|
||||
- _UseUIAlphaClip: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _ClipRect: {r: -32767, g: -32767, b: 32767, a: 32767}
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _TintColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 356b9d0e2cad849c3b53c7e9e1680cb7
|
||||
guid: 96e9806111c7f4ad18c9467cbbe2c4fd
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
BIN
Samples~/Demo/Materials/UIParticle_Demo_Animatable.png
Executable file
BIN
Samples~/Demo/Materials/UIParticle_Demo_Animatable.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
132
Samples~/Demo/Materials/UIParticle_Demo_Animatable.png.meta
Normal file
132
Samples~/Demo/Materials/UIParticle_Demo_Animatable.png.meta
Normal file
@@ -0,0 +1,132 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e834c7963556c9b4cbad7f1bee63f597
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 64
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 64
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: iPhone
|
||||
maxTextureSize: 64
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Android
|
||||
maxTextureSize: 64
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 64
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 78789b3115ea945b6ad75ef039075475
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
84
Samples~/Demo/Materials/UIParticle_Demo_Dot.mat
Normal file
84
Samples~/Demo/Materials/UIParticle_Demo_Dot.mat
Normal file
@@ -0,0 +1,84 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: UIParticle_Demo_Dot
|
||||
m_Shader: {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords:
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: 3001
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
- _BumpScale: 1
|
||||
- _ColorMask: 15
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _Stencil: 0
|
||||
- _StencilComp: 8
|
||||
- _StencilOp: 0
|
||||
- _StencilReadMask: 255
|
||||
- _StencilWriteMask: 255
|
||||
- _UVSec: 0
|
||||
- _UseUIAlphaClip: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
8
Samples~/Demo/Materials/UIParticle_Demo_Dot.mat.meta
Normal file
8
Samples~/Demo/Materials/UIParticle_Demo_Dot.mat.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b35a584a784274746b87deef91c15c5c
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
Before Width: | Height: | Size: 585 KiB After Width: | Height: | Size: 585 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user