├── .gitignore ├── Character Shadow Config.asset ├── Character Shadow Config.asset.meta ├── Documentation~ ├── CharShadow.png ├── CharShadow_Additional.png └── TransparentShadow.png ├── LICENSE ├── LICENSE.meta ├── Prefabs.meta ├── Prefabs ├── CharacterShadowCamera.prefab └── CharacterShadowCamera.prefab.meta ├── README.md ├── README.md.meta ├── Sample.meta ├── Sample ├── SimpleToonShader.meta └── SimpleToonShader │ ├── SimpleToon.mat │ ├── SimpleToon.mat.meta │ ├── SimpleToon.shader │ ├── SimpleToon.shader.meta │ ├── SimpleToonInput.hlsl │ ├── SimpleToonInput.hlsl.meta │ ├── SimpleToonOutlinePass.hlsl │ ├── SimpleToonOutlinePass.hlsl.meta │ ├── SimpleToonPass.hlsl │ └── SimpleToonPass.hlsl.meta ├── Scripts.meta ├── Scripts ├── CharShadowCamera.cs ├── CharShadowCamera.cs.meta ├── CharacterShadowConfig.cs ├── CharacterShadowConfig.cs.meta ├── CharacterShadowMap.cs ├── CharacterShadowMap.cs.meta ├── CharacterShadowPass.cs ├── CharacterShadowPass.cs.meta ├── CharacterShadowUtils.cs ├── CharacterShadowUtils.cs.meta ├── TransparentShadowPass.cs └── TransparentShadowPass.cs.meta ├── Shaders.meta ├── Shaders ├── CharacterShadowDepthPass.hlsl ├── CharacterShadowDepthPass.hlsl.meta ├── CharacterShadowInput.hlsl ├── CharacterShadowInput.hlsl.meta ├── CharacterShadowTransforms.hlsl ├── CharacterShadowTransforms.hlsl.meta ├── DeclareCharacterShadowTexture.hlsl ├── DeclareCharacterShadowTexture.hlsl.meta ├── TransparentShadowPass.hlsl └── TransparentShadowPass.hlsl.meta ├── ToonCharacterShadow.asmdef ├── ToonCharacterShadow.asmdef.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Asset meta data should only be ignored when the corresponding asset is also ignored 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | # Unity3D generated file on crash reports 52 | sysinfo.txt 53 | 54 | # Builds 55 | *.apk 56 | *.unitypackage 57 | 58 | # Crashlytics generated file 59 | crashlytics-build.properties 60 | 61 | -------------------------------------------------------------------------------- /Character Shadow Config.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 26fa71aeef3fbd442b561d36aa95f04e, type: 3} 13 | m_Name: Character Shadow Config 14 | m_EditorClassIdentifier: 15 | enableTransparentShadow: 0 16 | useBrightestLight: 1 17 | followLayerMask: 18 | serializedVersion: 2 19 | m_Bits: 0 20 | bias: 0.001 21 | normalBias: 0.001 22 | stepSmoothness: 0.0001 23 | textureScale: 4 24 | transparentTextureScale: 2 25 | precision: 14 26 | softShadowMode: 0 27 | highSoftShadowBlurDistance: 1 28 | cascadeSplit: {x: 3.5, y: 7, z: 11, w: 22} 29 | -------------------------------------------------------------------------------- /Character Shadow Config.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dd9492f06eeb65641b16d4a9ff8b8afb 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Documentation~/CharShadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mseonKim/UnityToonCharacterShadow/927ba595fafde437201b7293d4f0d8a9921381e8/Documentation~/CharShadow.png -------------------------------------------------------------------------------- /Documentation~/CharShadow_Additional.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mseonKim/UnityToonCharacterShadow/927ba595fafde437201b7293d4f0d8a9921381e8/Documentation~/CharShadow_Additional.png -------------------------------------------------------------------------------- /Documentation~/TransparentShadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mseonKim/UnityToonCharacterShadow/927ba595fafde437201b7293d4f0d8a9921381e8/Documentation~/TransparentShadow.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3bfa69db7bb47c647a289018fccaaf7b 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bb84a08b2311f3848bfd1789205ae9a9 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs/CharacterShadowCamera.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &6136915108219549633 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 5252935033044734855} 12 | - component: {fileID: 392706524546034796} 13 | - component: {fileID: 9085085320535407843} 14 | - component: {fileID: 1931952733531555982} 15 | m_Layer: 0 16 | m_Name: CharacterShadowCamera 17 | m_TagString: Untagged 18 | m_Icon: {fileID: 0} 19 | m_NavMeshLayer: 0 20 | m_StaticEditorFlags: 0 21 | m_IsActive: 1 22 | --- !u!4 &5252935033044734855 23 | Transform: 24 | m_ObjectHideFlags: 0 25 | m_CorrespondingSourceObject: {fileID: 0} 26 | m_PrefabInstance: {fileID: 0} 27 | m_PrefabAsset: {fileID: 0} 28 | m_GameObject: {fileID: 6136915108219549633} 29 | serializedVersion: 2 30 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 31 | m_LocalPosition: {x: 0, y: 0, z: 0} 32 | m_LocalScale: {x: 1, y: 1, z: 1} 33 | m_ConstrainProportionsScale: 0 34 | m_Children: [] 35 | m_Father: {fileID: 0} 36 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 37 | --- !u!114 &392706524546034796 38 | MonoBehaviour: 39 | m_ObjectHideFlags: 0 40 | m_CorrespondingSourceObject: {fileID: 0} 41 | m_PrefabInstance: {fileID: 0} 42 | m_PrefabAsset: {fileID: 0} 43 | m_GameObject: {fileID: 6136915108219549633} 44 | m_Enabled: 1 45 | m_EditorHideFlags: 0 46 | m_Script: {fileID: 11500000, guid: a266bf7ce9be8e441bd5230e939285d1, type: 3} 47 | m_Name: 48 | m_EditorClassIdentifier: 49 | _targets: [] 50 | activeTarget: {fileID: 0} 51 | config: {fileID: 11400000, guid: dd9492f06eeb65641b16d4a9ff8b8afb, type: 2} 52 | charBoundOffset: 1 53 | targetOffsetY: 0 54 | cameraDistance: 3.5 55 | --- !u!20 &9085085320535407843 56 | Camera: 57 | m_ObjectHideFlags: 0 58 | m_CorrespondingSourceObject: {fileID: 0} 59 | m_PrefabInstance: {fileID: 0} 60 | m_PrefabAsset: {fileID: 0} 61 | m_GameObject: {fileID: 6136915108219549633} 62 | m_Enabled: 0 63 | serializedVersion: 2 64 | m_ClearFlags: 2 65 | m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} 66 | m_projectionMatrixMode: 1 67 | m_GateFitMode: 2 68 | m_FOVAxisMode: 0 69 | m_Iso: 200 70 | m_ShutterSpeed: 0.005 71 | m_Aperture: 16 72 | m_FocusDistance: 10 73 | m_FocalLength: 50 74 | m_BladeCount: 5 75 | m_Curvature: {x: 2, y: 11} 76 | m_BarrelClipping: 0.25 77 | m_Anamorphism: 0 78 | m_SensorSize: {x: 36, y: 24} 79 | m_LensShift: {x: 0, y: 0} 80 | m_NormalizedViewPortRect: 81 | serializedVersion: 2 82 | x: 0 83 | y: 0 84 | width: 1 85 | height: 1 86 | near clip plane: 0.1 87 | far clip plane: 10 88 | field of view: 30 89 | orthographic: 0 90 | orthographic size: 1 91 | m_Depth: 0 92 | m_CullingMask: 93 | serializedVersion: 2 94 | m_Bits: 1536 95 | m_RenderingPath: -1 96 | m_TargetTexture: {fileID: 0} 97 | m_TargetDisplay: 0 98 | m_TargetEye: 3 99 | m_HDR: 1 100 | m_AllowMSAA: 1 101 | m_AllowDynamicResolution: 0 102 | m_ForceIntoRT: 0 103 | m_OcclusionCulling: 0 104 | m_StereoConvergence: 10 105 | m_StereoSeparation: 0.022 106 | --- !u!114 &1931952733531555982 107 | MonoBehaviour: 108 | m_ObjectHideFlags: 0 109 | m_CorrespondingSourceObject: {fileID: 0} 110 | m_PrefabInstance: {fileID: 0} 111 | m_PrefabAsset: {fileID: 0} 112 | m_GameObject: {fileID: 6136915108219549633} 113 | m_Enabled: 1 114 | m_EditorHideFlags: 0 115 | m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} 116 | m_Name: 117 | m_EditorClassIdentifier: 118 | m_RenderShadows: 1 119 | m_RequiresDepthTextureOption: 2 120 | m_RequiresOpaqueTextureOption: 2 121 | m_CameraType: 0 122 | m_Cameras: [] 123 | m_RendererIndex: -1 124 | m_VolumeLayerMask: 125 | serializedVersion: 2 126 | m_Bits: 1 127 | m_VolumeTrigger: {fileID: 0} 128 | m_VolumeFrameworkUpdateModeOption: 2 129 | m_RenderPostProcessing: 0 130 | m_Antialiasing: 0 131 | m_AntialiasingQuality: 2 132 | m_StopNaN: 0 133 | m_Dithering: 0 134 | m_ClearDepth: 1 135 | m_AllowXRRendering: 1 136 | m_AllowHDROutput: 1 137 | m_UseScreenCoordOverride: 0 138 | m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} 139 | m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} 140 | m_RequiresDepthTexture: 0 141 | m_RequiresColorTexture: 0 142 | m_Version: 2 143 | m_TaaSettings: 144 | quality: 3 145 | frameInfluence: 0.1 146 | jitterScale: 1 147 | mipBias: 0 148 | varianceClampScale: 0.9 149 | contrastAdaptiveSharpening: 0 150 | -------------------------------------------------------------------------------- /Prefabs/CharacterShadowCamera.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2e5256c8eb358444963d4f48b8aacfa 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Toon Character Shadow 2 | 3 | This package contains detailed character shadow feature for toon shading in PC/Console platforms, Unity URP projects. 4 | 5 | 6 | ## Character ShadowMap 7 | ![CharacterShadow](./Documentation~/CharShadow.png) 8 | Character Shadowmap is designed to improve character lighting quality by adding shadow for a single character. There's a room for improvement to cover more than one character, however, currently unsupported without customizing script. 9 | 10 | ## Additional ShadowMap 11 | It also supports additional local shadow if `useBrightestLight` enabled. 12 | Automatically calculates the most effective lights to the character among all spot lights matching the `FollowLayerMask` in the scene each frame. If the intensity of the brightest spot light is stronger than MainLight(Directional Light), use it for `CharacterShadowMap` instead of the MainLight. 13 | 14 | ![AdditionalShadow](./Documentation~/CharShadow_Additional.png) 15 | 16 | 17 | ## Transparent Shadow 18 | Transparent shadow is supported as well. However, it uses more memory so enable this when you do need this feature. 19 | ![TransparentShadow](./Documentation~/TransparentShadow.png) -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c882f7a08034982479cc22aa96eb7cd4 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Sample.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e975364c6c465ad40abc60ff3d98fd49 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Sample/SimpleToonShader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ba7793ff6aeb4bc45b3df199b4f6f3a6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Sample/SimpleToonShader/SimpleToon.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 8 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: SimpleToon 11 | m_Shader: {fileID: 4800000, guid: afb23a8667798404a82b5ebfc74f1884, type: 3} 12 | m_Parent: {fileID: 0} 13 | m_ModifiedSerializedProperties: 0 14 | m_ValidKeywords: [] 15 | m_InvalidKeywords: [] 16 | m_LightmapFlags: 4 17 | m_EnableInstancingVariants: 0 18 | m_DoubleSidedGI: 0 19 | m_CustomRenderQueue: -1 20 | stringTagMap: {} 21 | disabledShaderPasses: [] 22 | m_LockedProperties: 23 | m_SavedProperties: 24 | serializedVersion: 3 25 | m_TexEnvs: 26 | - _BaseMap: 27 | m_Texture: {fileID: 0} 28 | m_Scale: {x: 1, y: 1} 29 | m_Offset: {x: 0, y: 0} 30 | - _BumpMap: 31 | m_Texture: {fileID: 0} 32 | m_Scale: {x: 1, y: 1} 33 | m_Offset: {x: 0, y: 0} 34 | - _ClippingMask: 35 | m_Texture: {fileID: 0} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - _DetailAlbedoMap: 39 | m_Texture: {fileID: 0} 40 | m_Scale: {x: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - _DetailMask: 43 | m_Texture: {fileID: 0} 44 | m_Scale: {x: 1, y: 1} 45 | m_Offset: {x: 0, y: 0} 46 | - _DetailNormalMap: 47 | m_Texture: {fileID: 0} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _EmissionMap: 51 | m_Texture: {fileID: 0} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _MainTex: 55 | m_Texture: {fileID: 0} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | - _MatCapMap: 59 | m_Texture: {fileID: 0} 60 | m_Scale: {x: 1, y: 1} 61 | m_Offset: {x: 0, y: 0} 62 | - _MatCap_Sampler: 63 | m_Texture: {fileID: 0} 64 | m_Scale: {x: 1, y: 1} 65 | m_Offset: {x: 0, y: 0} 66 | - _MetallicGlossMap: 67 | m_Texture: {fileID: 0} 68 | m_Scale: {x: 1, y: 1} 69 | m_Offset: {x: 0, y: 0} 70 | - _NormalMap: 71 | m_Texture: {fileID: 0} 72 | m_Scale: {x: 1, y: 1} 73 | m_Offset: {x: 0, y: 0} 74 | - _OcclusionMap: 75 | m_Texture: {fileID: 0} 76 | m_Scale: {x: 1, y: 1} 77 | m_Offset: {x: 0, y: 0} 78 | - _Outline_Sampler: 79 | m_Texture: {fileID: 0} 80 | m_Scale: {x: 1, y: 1} 81 | m_Offset: {x: 0, y: 0} 82 | - _ParallaxMap: 83 | m_Texture: {fileID: 0} 84 | m_Scale: {x: 1, y: 1} 85 | m_Offset: {x: 0, y: 0} 86 | - _SpecGlossMap: 87 | m_Texture: {fileID: 0} 88 | m_Scale: {x: 1, y: 1} 89 | m_Offset: {x: 0, y: 0} 90 | - unity_Lightmaps: 91 | m_Texture: {fileID: 0} 92 | m_Scale: {x: 1, y: 1} 93 | m_Offset: {x: 0, y: 0} 94 | - unity_LightmapsInd: 95 | m_Texture: {fileID: 0} 96 | m_Scale: {x: 1, y: 1} 97 | m_Offset: {x: 0, y: 0} 98 | - unity_ShadowMasks: 99 | m_Texture: {fileID: 0} 100 | m_Scale: {x: 1, y: 1} 101 | m_Offset: {x: 0, y: 0} 102 | m_Ints: [] 103 | m_Floats: 104 | - _AlphaClip: 0 105 | - _AlphaToMask: 0 106 | - _BaseColor_Step: 0.5 107 | - _Blend: 0 108 | - _BlendModePreserveSpecular: 1 109 | - _BlurLevelMatcap: 0 110 | - _BumpScale: 0 111 | - _ClearCoatMask: 0 112 | - _ClearCoatSmoothness: 0 113 | - _Cull: 2 114 | - _CullMode: 2 115 | - _Cutoff: 0.5 116 | - _DetailAlbedoMapScale: 1 117 | - _DetailNormalMapScale: 1 118 | - _DstBlend: 0 119 | - _DstBlendAlpha: 0 120 | - _EnvironmentReflections: 1 121 | - _Farthest_Distance: 10 122 | - _FixLightColor: 0 123 | - _GlossMapScale: 0 124 | - _Glossiness: 0 125 | - _GlossyReflections: 0 126 | - _Metallic: 0 127 | - _Nearest_Distance: 0.5 128 | - _OcclusionStrength: 1 129 | - _Offset_Z: 0 130 | - _Outline_Width: 1 131 | - _Parallax: 0.005 132 | - _QueueOffset: 0 133 | - _ReceiveShadows: 1 134 | - _Rim_Strength: 4 135 | - _ShadeStep: 0.5 136 | - _ShadeStepFeather: 0.01 137 | - _ShadeStepOffset: 0.01 138 | - _Smoothness: 0.5 139 | - _SmoothnessTextureChannel: 0 140 | - _SpecularHighlights: 1 141 | - _SrcBlend: 1 142 | - _SrcBlendAlpha: 1 143 | - _StepSmoothness: 0.01 144 | - _Surface: 0 145 | - _USE_CHAR_SHADOW: 0 146 | - _VRChat: 0 147 | - _WorkflowMode: 1 148 | - _ZWrite: 1 149 | m_Colors: 150 | - _BaseColor: {r: 1, g: 1, b: 1, a: 1} 151 | - _Color: {r: 1, g: 1, b: 1, a: 1} 152 | - _DefaultLightColor: {r: 0.8, g: 0.8, b: 0.8, a: 1} 153 | - _DefaultLightDir: {r: 0, g: 0, b: 0, a: 0} 154 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 155 | - _MatCapColor: {r: 1, g: 1, b: 1, a: 1} 156 | - _Outline_Color: {r: 0, g: 0, b: 0, a: 1} 157 | - _RimLightColor: {r: 1, g: 1, b: 1, a: 1} 158 | - _ShadeColor: {r: 0.3018868, g: 0.3018868, b: 0.3018868, a: 1} 159 | - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} 160 | m_BuildTextureStacks: [] 161 | --- !u!114 &1491777630235562560 162 | MonoBehaviour: 163 | m_ObjectHideFlags: 11 164 | m_CorrespondingSourceObject: {fileID: 0} 165 | m_PrefabInstance: {fileID: 0} 166 | m_PrefabAsset: {fileID: 0} 167 | m_GameObject: {fileID: 0} 168 | m_Enabled: 1 169 | m_EditorHideFlags: 0 170 | m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} 171 | m_Name: 172 | m_EditorClassIdentifier: 173 | version: 7 174 | -------------------------------------------------------------------------------- /Sample/SimpleToonShader/SimpleToon.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b9cf553b55241e340b7dd9079ed1b1b8 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Sample/SimpleToonShader/SimpleToon.shader: -------------------------------------------------------------------------------- 1 | Shader "SimpleToon" 2 | { 3 | Properties 4 | { 5 | [Enum(OFF,0,FRONT,1,BACK,2)] _CullMode("Cull Mode", int) = 2 //OFF/FRONT/BACK 6 | _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 7 | _MainTex ("Base Map", 2D) = "white" {} 8 | [HideInInspector] _BaseMap ("BaseMap", 2D) = "white" {} 9 | _BaseColor ("Base Color", Color) = (1,1,1,1) 10 | _ShadeColor ("Shade Color", Color) = (1,1,1,1) 11 | _BaseColor_Step ("BaseColor Step", Range(0, 1)) = 0.5 12 | _StepSmoothness ("Step Smoothness", Range(0, 0.5)) = 0.01 13 | _NormalMap ("Normal Map", 2D) = "bump" {} 14 | _BumpScale ("Normal Map Strength", Range(0, 1)) = 0 15 | _ClippingMask ("Clipping Mask", 2D) = "white" {} 16 | 17 | // Rim Light 18 | _RimLightColor ("RimLight Color", Color) = (1,1,1,1) 19 | _Rim_Strength ("Rim Strength", Float) = 4 20 | 21 | // MatCap 22 | _MatCapColor ("MatCap Color", Color) = (1,1,1,1) 23 | _MatCapMap ("MatCap Map", 2D) = "black" {} 24 | 25 | // Outline 26 | _Outline_Color ("Outline Color", Color) = (0,0,0,1) 27 | _Outline_Width ("Outline Width", Float ) = 0 28 | 29 | // Character Shadow 30 | [Toggle] _USE_CHAR_SHADOW ("Character Shadow", Float) = 0 31 | } 32 | SubShader 33 | { 34 | PackageRequirements 35 | { 36 | "com.unity.render-pipelines.universal": "14.0.0" 37 | } 38 | Tags 39 | { 40 | "RenderType"="Opaque" 41 | "RenderPipeline" = "UniversalPipeline" 42 | } 43 | Pass 44 | { 45 | Name "Outline" 46 | Tags 47 | { 48 | "LightMode"="SRPDefaultUnlit" 49 | } 50 | Cull Front 51 | 52 | HLSLPROGRAM 53 | #pragma vertex vert 54 | #pragma fragment frag 55 | 56 | #include "SimpleToonInput.hlsl" 57 | #include "SimpleToonOutlinePass.hlsl" 58 | 59 | ENDHLSL 60 | } 61 | Pass 62 | { 63 | Name "ForwardLit" 64 | Tags{"LightMode" = "UniversalForward"} 65 | Cull[_CullMode] 66 | Blend SrcAlpha OneMinusSrcAlpha 67 | 68 | HLSLPROGRAM 69 | #pragma vertex vert 70 | #pragma fragment frag 71 | 72 | #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" 73 | #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" 74 | 75 | // ------------------------------------- 76 | // Universal Render Pipeline keywords 77 | #pragma multi_compile _ _MAIN_LIGHT_SHADOWS 78 | #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE 79 | #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS 80 | #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS 81 | #pragma multi_compile _ _SHADOWS_SOFT 82 | #pragma multi_compile _ _FORWARD_PLUS 83 | #pragma multi_compile_fragment _ _LIGHT_COOKIES 84 | 85 | #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE 86 | // ------------------------------------- 87 | // Unity defined keywords 88 | #pragma multi_compile _ DIRLIGHTMAP_COMBINED 89 | #pragma multi_compile _ LIGHTMAP_ON 90 | #pragma multi_compile_fog 91 | 92 | // ------------------------------------- 93 | // Character Shadow keywords 94 | #pragma shader_feature _HIGH_CHAR_SOFTSHADOW 95 | 96 | #include "SimpleToonInput.hlsl" 97 | #include "SimpleToonPass.hlsl" 98 | ENDHLSL 99 | } 100 | 101 | Pass 102 | { 103 | Name "ShadowCaster" 104 | Tags{"LightMode" = "ShadowCaster"} 105 | 106 | ZWrite On 107 | ZTest LEqual 108 | Cull[_CullMode] 109 | 110 | HLSLPROGRAM 111 | #pragma target 2.0 112 | 113 | // Required to compile gles 2.0 with standard srp library 114 | #pragma prefer_hlslcc gles 115 | 116 | #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 117 | 118 | #pragma vertex ShadowPassVertex 119 | #pragma fragment ShadowPassFragment 120 | 121 | #include "SimpleToonInput.hlsl" 122 | #include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl" 123 | ENDHLSL 124 | } 125 | Pass 126 | { 127 | Name "DepthOnly" 128 | Tags{"LightMode" = "DepthOnly"} 129 | 130 | ZWrite On 131 | ColorMask 0 132 | Cull[_CullMode] 133 | 134 | HLSLPROGRAM 135 | #pragma target 2.0 136 | 137 | // Required to compile gles 2.0 with standard srp library 138 | #pragma prefer_hlslcc gles 139 | #pragma exclude_renderers d3d11_9x 140 | 141 | #pragma vertex DepthOnlyVertex 142 | #pragma fragment DepthOnlyFragment 143 | 144 | // ------------------------------------- 145 | // Material Keywords 146 | #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 147 | 148 | #include "SimpleToonInput.hlsl" 149 | #include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl" 150 | ENDHLSL 151 | } 152 | // This pass is used when drawing to a _CameraNormalsTexture texture 153 | Pass 154 | { 155 | Name "DepthNormals" 156 | Tags{"LightMode" = "DepthNormals"} 157 | 158 | ZWrite On 159 | Cull[_Cull] 160 | 161 | HLSLPROGRAM 162 | #pragma target 2.0 163 | #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Version.hlsl" 164 | 165 | 166 | // Required to compile gles 2.0 with standard srp library 167 | #pragma prefer_hlslcc gles 168 | #pragma exclude_renderers d3d11_9x 169 | 170 | #pragma vertex DepthNormalsVertex 171 | #pragma fragment DepthNormalsFragment 172 | 173 | // ------------------------------------- 174 | // Material Keywords 175 | #pragma shader_feature_local _PARALLAXMAP 176 | #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 177 | 178 | #include "SimpleToonInput.hlsl" 179 | #include "Packages/com.unity.render-pipelines.universal/Shaders/DepthNormalsPass.hlsl" 180 | 181 | ENDHLSL 182 | } 183 | 184 | Pass 185 | { 186 | Name "CharacterDepth" 187 | Tags{"LightMode" = "CharacterDepth"} 188 | 189 | ZWrite On 190 | ZTest LEqual 191 | Cull Off 192 | BlendOp Max 193 | 194 | HLSLPROGRAM 195 | #pragma target 2.0 196 | 197 | // Required to compile gles 2.0 with standard srp library 198 | #pragma prefer_hlslcc gles 199 | #pragma exclude_renderers d3d11_9x 200 | #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 201 | 202 | #pragma vertex CharShadowVertex 203 | #pragma fragment CharShadowFragment 204 | 205 | #include "SimpleToonInput.hlsl" 206 | #include "Packages/com.unity.tooncharactershadow/Shaders/CharacterShadowDepthPass.hlsl" 207 | ENDHLSL 208 | } 209 | 210 | Pass 211 | { 212 | Name "TransparentShadow" 213 | Tags {"LightMode" = "TransparentShadow"} 214 | 215 | ZWrite Off 216 | ZTest Off 217 | Cull Off 218 | Blend One One 219 | BlendOp Max 220 | 221 | HLSLPROGRAM 222 | #pragma target 2.0 223 | 224 | #pragma prefer_hlslcc gles 225 | #pragma exclude_renderers d3d11_9x 226 | #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 227 | #pragma shader_feature_local _ALPHATEST_ON 228 | 229 | #pragma vertex TransparentShadowVert 230 | #pragma fragment TransparentShadowFragment 231 | 232 | #include "SimpleToonInput.hlsl" 233 | #include "Packages/com.unity.tooncharactershadow/Shaders/TransparentShadowPass.hlsl" 234 | ENDHLSL 235 | } 236 | Pass 237 | { 238 | Name "TransparentAlphaSum" 239 | Tags {"LightMode" = "TransparentAlphaSum"} 240 | 241 | ZWrite Off 242 | ZTest Off 243 | Cull Off 244 | Blend One One 245 | BlendOp Add 246 | 247 | HLSLPROGRAM 248 | #pragma target 2.0 249 | 250 | #pragma prefer_hlslcc gles 251 | #pragma exclude_renderers d3d11_9x 252 | #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 253 | #pragma shader_feature_local _ALPHATEST_ON 254 | 255 | #pragma vertex TransparentAlphaSumVert 256 | #pragma fragment TransparentAlphaSumFragment 257 | 258 | #include "SimpleToonInput.hlsl" 259 | #include "Packages/com.unity.tooncharactershadow/Shaders/TransparentShadowPass.hlsl" 260 | ENDHLSL 261 | } 262 | } 263 | } -------------------------------------------------------------------------------- /Sample/SimpleToonShader/SimpleToon.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: afb23a8667798404a82b5ebfc74f1884 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Sample/SimpleToonShader/SimpleToonInput.hlsl: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_TOON_INPUT_INCLUDED 2 | #define SIMPLE_TOON_INPUT_INCLUDED 3 | 4 | #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" 5 | #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl" 6 | #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl" 7 | 8 | CBUFFER_START(UnityPerMaterial) 9 | float4 _BaseColor; 10 | float4 _ShadeColor; 11 | float _BaseColor_Step; 12 | float _StepSmoothness; 13 | float _BumpScale; 14 | float _Rim_Strength; 15 | float4 _RimLightColor; 16 | float4 _MatCapColor; 17 | 18 | float4 _Outline_Color; 19 | float _Outline_Width; 20 | half _Cutoff; 21 | float _USE_CHAR_SHADOW; 22 | 23 | float4 _MainTex_ST; 24 | float4 _BaseMap_ST; 25 | float4 _NormalMap_ST; 26 | float4 _ClippingMask_ST; 27 | float4 _MatCapMap_ST; 28 | CBUFFER_END 29 | 30 | TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); 31 | TEXTURE2D(_NormalMap); 32 | TEXTURE2D(_ClippingMask); 33 | TEXTURE2D(_MatCapMap); SAMPLER(sampler_MatCapMap); 34 | 35 | #endif -------------------------------------------------------------------------------- /Sample/SimpleToonShader/SimpleToonInput.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 60ac8a07468f3234da9019acb1b08d29 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Sample/SimpleToonShader/SimpleToonOutlinePass.hlsl: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_TOON_OUTLINE_PASS_INCLUDED 2 | #define SIMPLE_TOON_OUTLINE_PASS_INCLUDED 3 | 4 | struct VertexInput 5 | { 6 | float4 vertex : POSITION; 7 | float3 normal : NORMAL; 8 | float2 texcoord0 : TEXCOORD0; 9 | 10 | }; 11 | struct VertexOutput 12 | { 13 | float4 pos : SV_POSITION; 14 | }; 15 | 16 | VertexOutput vert (VertexInput v) 17 | { 18 | VertexOutput o = (VertexOutput)0; 19 | float outlineWidth = _Outline_Width * 0.001; 20 | o.pos = TransformObjectToHClip(v.vertex.xyz + v.normal * outlineWidth); 21 | return o; 22 | } 23 | 24 | float4 frag(VertexOutput i) : SV_TARGET 25 | { 26 | return _Outline_Color; 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /Sample/SimpleToonShader/SimpleToonOutlinePass.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62778cda5dcbef84da1049a815d39895 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Sample/SimpleToonShader/SimpleToonPass.hlsl: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_TOON_PASS_INCLUDED 2 | #define SIMPLE_TOON_PASS_INCLUDED 3 | 4 | #include "Packages/com.unity.tooncharactershadow/Shaders/DeclareCharacterShadowTexture.hlsl" 5 | 6 | struct VertexInput 7 | { 8 | float4 vertex : POSITION; 9 | float3 normal : NORMAL; 10 | float2 texcoord0 : TEXCOORD0; 11 | float2 staticLightmapUV : TEXCOORD1; 12 | float2 dynamicLightmapUV : TEXCOORD2; 13 | }; 14 | 15 | struct VertexOutput 16 | { 17 | float4 pos : SV_POSITION; 18 | float2 uv0 : TEXCOORD0; 19 | float3 posWorld : TEXCOORD1; 20 | float3 normalWS : TEXCOORD2; 21 | DECLARE_LIGHTMAP_OR_SH(staticLightmapUV, vertexSH, 3); 22 | #ifdef DYNAMICLIGHTMAP_ON 23 | float2 dynamicLightmapUV : TEXCOORD4; // Dynamic lightmap UVs 24 | #endif 25 | }; 26 | 27 | half LinearStep(half minValue, half maxValue, half In) 28 | { 29 | return saturate((In-minValue) / (maxValue-minValue)); 30 | } 31 | 32 | VertexOutput vert(VertexInput v) 33 | { 34 | VertexOutput o = (VertexOutput)0; 35 | // UNITY_TRANSFER_INSTANCE_ID(v, o); 36 | // UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); 37 | o.pos = TransformObjectToHClip(v.vertex.xyz); 38 | o.uv0 = v.texcoord0; 39 | o.normalWS = TransformObjectToWorldDir(v.normal); 40 | o.posWorld = TransformObjectToWorld(v.vertex.xyz); 41 | return o; 42 | } 43 | 44 | half GetCharMainShadow(float3 worldPos, float opacity) 45 | { 46 | return SampleCharacterAndTransparentShadow(worldPos, opacity); 47 | } 48 | half GetCharAdditionalShadow(float3 worldPos, float opacity, uint lightIndex) 49 | { 50 | return SampleAdditionalCharacterAndTransparentShadow(worldPos, opacity, lightIndex); 51 | } 52 | 53 | float4 frag(VertexOutput i, half facing : VFACE) : SV_TARGET 54 | { 55 | half alpha = 0; 56 | BRDFData brdfData; 57 | InitializeBRDFData(_BaseColor.rgb, 0, 0, 1, alpha, brdfData); 58 | 59 | float4 _BaseMap_var = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, TRANSFORM_TEX(i.uv0, _MainTex)); 60 | float3 color = _BaseMap_var.rgb; 61 | float opacity = _BaseMap_var.a * _BaseColor.a; 62 | 63 | i.normalWS = normalize(i.normalWS); 64 | float4 _NormalMap_var = SAMPLE_TEXTURE2D(_NormalMap, sampler_MainTex, TRANSFORM_TEX(i.uv0, _NormalMap)); 65 | float3 normalWS = lerp(i.normalWS, _NormalMap_var.rgb, _BumpScale); 66 | float2 normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(i.pos); 67 | 68 | 69 | Light mainLight = GetMainLight(); 70 | half3 mainLightColor = mainLight.color * (mainLight.distanceAttenuation * mainLight.shadowAttenuation); 71 | 72 | // Half Lambert 73 | float M = _BaseColor_Step + _StepSmoothness; 74 | float m = _BaseColor_Step - _StepSmoothness; 75 | float3 baseColor = lerp(_ShadeColor.rgb, _BaseColor.rgb, LinearStep(m, M, dot(mainLight.direction, normalWS) * 0.5 + 0.5)); 76 | 77 | half ssShadowAtten = 0; 78 | if (_USE_CHAR_SHADOW > 0) 79 | { 80 | ssShadowAtten = GetCharMainShadow(i.posWorld, opacity); 81 | baseColor = lerp(baseColor, _ShadeColor.rgb, ssShadowAtten); 82 | } 83 | 84 | color *= baseColor * mainLightColor; 85 | 86 | #if defined(_ADDITIONAL_LIGHTS) 87 | uint pixelLightCount = GetAdditionalLightsCount(); 88 | half3 additionalLightsColor = 0; 89 | 90 | // Directional Lights 91 | #if USE_FORWARD_PLUS 92 | for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++) 93 | { 94 | FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK 95 | 96 | Light light = GetAdditionalLight(lightIndex, i.posWorld, 0); 97 | 98 | #ifdef _LIGHT_LAYERS 99 | if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers)) 100 | #endif 101 | { 102 | half halfLambert = dot(light.direction, normalWS) * 0.5 + 0.5; 103 | half3 lightColor = light.color.rgb * light.distanceAttenuation * light.shadowAttenuation; 104 | half3 finalBaseColor = lerp(_ShadeColor.rgb, _BaseColor.rgb, LinearStep(m, M, halfLambert)); 105 | if (_USE_CHAR_SHADOW > 0) 106 | { 107 | ssShadowAtten = GetCharAdditionalShadow(i.posWorld, opacity, lightIndex); 108 | finalBaseColor = lerp(baseColor, _ShadeColor.rgb, ssShadowAtten); 109 | } 110 | additionalLightsColor += _BaseMap_var.rgb * lightColor * finalBaseColor; 111 | } 112 | } 113 | #endif 114 | 115 | // Local Lights 116 | InputData inputData = (InputData)0; 117 | inputData.positionWS = i.posWorld; 118 | inputData.normalizedScreenSpaceUV = normalizedScreenSpaceUV; 119 | LIGHT_LOOP_BEGIN(pixelLightCount) 120 | Light light = GetAdditionalLight(lightIndex, inputData.positionWS, 0); 121 | 122 | #ifdef _LIGHT_LAYERS 123 | if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers)) 124 | #endif 125 | { 126 | half halfLambert = dot(light.direction, normalWS) * 0.5 + 0.5; 127 | half3 lightColor = light.color.rgb * light.distanceAttenuation * light.shadowAttenuation; 128 | half3 finalBaseColor = lerp(_ShadeColor.rgb, _BaseColor.rgb, LinearStep(m, M, halfLambert)); 129 | if (_USE_CHAR_SHADOW > 0) 130 | { 131 | ssShadowAtten = GetCharAdditionalShadow(i.posWorld, opacity, lightIndex); 132 | finalBaseColor = lerp(baseColor, _ShadeColor.rgb, ssShadowAtten); 133 | } 134 | additionalLightsColor += _BaseMap_var.rgb * lightColor * finalBaseColor; 135 | } 136 | LIGHT_LOOP_END 137 | 138 | color += additionalLightsColor; 139 | #endif 140 | 141 | // Rim Light 142 | float3 viewDir = normalize(_WorldSpaceCameraPos - i.posWorld).xyz; 143 | half emission = LinearStep(0.25, 0.75, pow(1 - saturate(dot(viewDir, normalWS)), _Rim_Strength)); 144 | half3 rimColor = (_RimLightColor * emission).rgb; 145 | if (facing < 0.1) 146 | { 147 | rimColor = 0; 148 | } 149 | color += rimColor; 150 | 151 | // Matcap 152 | float3 viewNormal = TransformWorldToViewDir(normalWS); 153 | float2 matcapUV = viewNormal.xy * 0.5 + 0.5; 154 | float3 _MatCap_Sampler_var = SAMPLE_TEXTURE2D(_MatCapMap, sampler_MatCapMap, TRANSFORM_TEX(matcapUV, _MatCapMap)).rgb; 155 | color += _MatCap_Sampler_var * _MatCapColor.rgb; 156 | 157 | // GI 158 | #if defined(DYNAMICLIGHTMAP_ON) 159 | float3 bakedGI = SAMPLE_GI(i.staticLightmapUV, i.dynamicLightmapUV, i.vertexSH, normalWS); 160 | #else 161 | float3 bakedGI = SAMPLE_GI(i.staticLightmapUV, i.vertexSH, normalWS); 162 | #endif 163 | MixRealtimeAndBakedGI(mainLight, normalWS, bakedGI); 164 | float3 giColor = GlobalIllumination(brdfData, brdfData, 0, bakedGI, 0, i.posWorld, normalWS, viewDir, normalizedScreenSpaceUV); 165 | color += giColor; 166 | 167 | float4 finalColor = float4(color, opacity); 168 | return finalColor; 169 | } 170 | 171 | #endif -------------------------------------------------------------------------------- /Sample/SimpleToonShader/SimpleToonPass.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 84401c4594101f34193b85235b45d89a 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9f32cce52be5c6a46a14266f67642a22 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scripts/CharShadowCamera.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices.ComTypes; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | // Note: 7 | // We assume that there's only 1 camera except for render texture cameras in a scene. 8 | namespace ToonCharacterShadow 9 | { 10 | [ExecuteAlways] 11 | [RequireComponent(typeof(Camera))] 12 | public class CharShadowCamera : MonoBehaviour 13 | { 14 | public static CharShadowCamera Instance => s_Instance; 15 | private static CharShadowCamera s_Instance; 16 | 17 | [SerializeField, Tooltip("The camera will follow the first active target transform.")] 18 | private Transform[] _targets; // Character Transform. 19 | [HideInInspector] public Transform activeTarget; 20 | public CharacterShadowConfig config; 21 | public float charBoundOffset = 1; 22 | public float targetOffsetY = 0f; 23 | public float cameraDistance = 4f; 24 | 25 | private Camera m_LightCamera; 26 | public Camera lightCamera => m_LightCamera; 27 | 28 | private Light _mainLight; 29 | private List _sceneLights; 30 | 31 | private void OnValidate() 32 | { 33 | } 34 | 35 | void Awake() 36 | { 37 | s_Instance = this; 38 | _sceneLights = new List(256); 39 | } 40 | 41 | // Start is called before the first frame update 42 | void Start() 43 | { 44 | m_LightCamera = GetComponent(); 45 | RefreshSceneLights(); 46 | } 47 | 48 | void Update() 49 | { 50 | // Find active target 51 | foreach (var target in _targets) 52 | { 53 | if (target != null && target.gameObject.activeInHierarchy == true) 54 | { 55 | activeTarget = target; 56 | break; 57 | } 58 | } 59 | } 60 | 61 | /// 62 | /// NOTE) Make sure run this API in external script when dynamic lights are spawned at runtime. But should be care before due to performance. 63 | /// 64 | public void RefreshSceneLights() 65 | { 66 | _sceneLights.Clear(); 67 | foreach (var light in GameObject.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None)) 68 | { 69 | if (light.gameObject.isStatic) 70 | continue; 71 | 72 | // Set Main Light as the first found directional light. 73 | if (light.type == LightType.Directional && light.isActiveAndEnabled) 74 | { 75 | if (_mainLight == null) 76 | _mainLight = light; 77 | } 78 | 79 | if (light.type == LightType.Spot) 80 | { 81 | _sceneLights.Add(light); 82 | } 83 | } 84 | } 85 | 86 | public void SetLightCameraTransform(Light light) 87 | { 88 | if (lightCamera == null) 89 | return; 90 | 91 | var camTransform = lightCamera.transform; 92 | 93 | var newRotation = light.transform.rotation.eulerAngles; 94 | newRotation.z = 0f; 95 | camTransform.rotation = Quaternion.Euler(newRotation); 96 | var dir = light.transform.rotation * Vector3.forward; 97 | 98 | var distance = cameraDistance; 99 | var dest = (activeTarget?.position ?? Vector3.zero); 100 | camTransform.position = dest + (Vector3.up * targetOffsetY) + (-dir * distance); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Scripts/CharShadowCamera.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a266bf7ce9be8e441bd5230e939285d1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/CharacterShadowConfig.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace ToonCharacterShadow 4 | { 5 | public enum CustomShadowMapSize 6 | { 7 | X1 = 1, 8 | X2 = 2, 9 | X4 = 4, 10 | X8 = 8, 11 | } 12 | 13 | public enum CustomShadowMapPrecision 14 | { 15 | RFloat = 14, 16 | RHalf = 15, 17 | } 18 | 19 | public enum CharSoftShadowMode 20 | { 21 | Normal, 22 | High, 23 | } 24 | 25 | [CreateAssetMenu(menuName = "ToonGraphics/CharacterShadowConfig")] 26 | public class CharacterShadowConfig : ScriptableObject 27 | { 28 | [Tooltip("If enabled, Transparent shadowmap will be rendered.")] 29 | public bool enableTransparentShadow = false; 30 | [Tooltip("[Forward+ Only] If enabled, use the stronger light among MainLight & the brighest spot light.")] 31 | public bool useBrightestLight = true; 32 | public LayerMask followLayerMask; 33 | public float bias = 0.001f; 34 | public float normalBias = 0.001f; 35 | public float stepSmoothness = 0.0001f; 36 | public CustomShadowMapSize textureScale = CustomShadowMapSize.X4; 37 | public CustomShadowMapSize transparentTextureScale = CustomShadowMapSize.X2; 38 | public CustomShadowMapPrecision precision = CustomShadowMapPrecision.RFloat; 39 | public CharSoftShadowMode softShadowMode = CharSoftShadowMode.Normal; 40 | public float highSoftShadowBlurDistance = 4f; 41 | public Vector4 cascadeSplit = new Vector4(3.5f, 7f, 11f, 22f); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Scripts/CharacterShadowConfig.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 26fa71aeef3fbd442b561d36aa95f04e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/CharacterShadowMap.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Rendering; 3 | using UnityEngine.Rendering.Universal; 4 | using Unity.Collections; 5 | using System.Collections.Generic; 6 | 7 | namespace ToonCharacterShadow 8 | { 9 | public class CharacterShadowMap : ScriptableRendererFeature 10 | { 11 | private CharacterShadowPass m_CharShadowPass; 12 | private TransparentShadowPass m_CharTransparentShadowPass; 13 | public CharacterShadowConfig config; 14 | [Tooltip("Link this renderer data")] 15 | public UniversalRendererData urpData; 16 | 17 | 18 | public override void Create() 19 | { 20 | m_CharShadowPass = new CharacterShadowPass(RenderPassEvent.BeforeRenderingPrePasses, RenderQueueRange.opaque); 21 | m_CharShadowPass.ConfigureInput(ScriptableRenderPassInput.None); 22 | m_CharTransparentShadowPass = new TransparentShadowPass(RenderPassEvent.BeforeRenderingOpaques, RenderQueueRange.transparent); 23 | m_CharTransparentShadowPass.ConfigureInput(ScriptableRenderPassInput.None); 24 | } 25 | 26 | public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) 27 | { 28 | if (config == null) 29 | return; 30 | 31 | if (!CharacterShadowUtils.IfCharShadowUpdateNeeded(renderingData)) 32 | return; 33 | 34 | if (renderingData.cameraData.cameraType == CameraType.Reflection) 35 | return; 36 | 37 | // Additional shadow is only available in forward+ 38 | bool additionalShadowEnabled = urpData != null ? urpData.renderingMode == RenderingMode.ForwardPlus : false; 39 | 40 | m_CharShadowPass.Setup("CharacterShadowMap", renderingData, config, additionalShadowEnabled); 41 | renderer.EnqueuePass(m_CharShadowPass); 42 | if (config.enableTransparentShadow) 43 | { 44 | m_CharTransparentShadowPass.Setup("TransparentShadowMap", renderingData, config); 45 | renderer.EnqueuePass(m_CharTransparentShadowPass); 46 | } 47 | } 48 | 49 | protected override void Dispose(bool disposing) 50 | { 51 | m_CharShadowPass.Dispose(); 52 | m_CharTransparentShadowPass.Dispose(); 53 | } 54 | 55 | } 56 | } -------------------------------------------------------------------------------- /Scripts/CharacterShadowMap.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1edbe97ff2917a84f9a0d4942a865ac0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - config: {fileID: 11400000, guid: dd9492f06eeb65641b16d4a9ff8b8afb, type: 2} 8 | - urpData: {instanceID: 0} 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Scripts/CharacterShadowPass.cs: -------------------------------------------------------------------------------- 1 | /// How to use 2 | /// 1. Add 'CharacterShadowCamera' prefab to your scene. 3 | /// 2. Add pass to your shader to use 'CharacterShadowDepthPass.hlsl' with "CharacterDepth" LightMode. (See below example) 4 | /* [Pass Example - Unity Toon Shader] 5 | * NOTE) We assume that the shader use "_ClippingMask" property. 6 | * Pass 7 | * { 8 | * Name "CharacterDepth" 9 | * Tags{"LightMode" = "CharacterDepth"} 10 | * 11 | * ZWrite On 12 | * ZTest LEqual 13 | * Cull Off 14 | * BlendOp Max 15 | * 16 | * HLSLPROGRAM 17 | * #pragma target 2.0 18 | * 19 | * // Required to compile gles 2.0 with standard srp library 20 | * #pragma prefer_hlslcc gles 21 | * #pragma exclude_renderers d3d11_9x 22 | * #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 23 | * 24 | * #pragma vertex CharShadowVertex 25 | * #pragma fragment CharShadowFragment 26 | * 27 | * #include "Packages/com.unity.tooncharactershadow/Shaders/CharacterShadowDepthPass.hlsl" 28 | * ENDHLSL 29 | * } 30 | */ 31 | 32 | using UnityEngine; 33 | using UnityEngine.Rendering; 34 | using UnityEngine.Rendering.Universal; 35 | 36 | namespace ToonCharacterShadow 37 | { 38 | public class CharacterShadowPass : ScriptableRenderPass 39 | { 40 | /* ID */ 41 | private static readonly ShaderTagId k_ShaderTagId = new ShaderTagId("CharacterDepth"); 42 | private static class IDs 43 | { 44 | public static int _CharShadowMap = Shader.PropertyToID("_CharShadowMap"); 45 | public static int _CharShadowParams = Shader.PropertyToID("_CharShadowParams"); 46 | public static int _ViewMatrix = Shader.PropertyToID("_CharShadowViewM"); 47 | public static int _ProjMatrix = Shader.PropertyToID("_CharShadowProjM"); 48 | public static int _ShadowOffset0 = Shader.PropertyToID("_CharShadowOffset0"); 49 | public static int _ShadowOffset1 = Shader.PropertyToID("_CharShadowOffset1"); 50 | public static int _ShadowMapSize = Shader.PropertyToID("_CharShadowmapSize"); 51 | public static int _CharShadowCascadeParams = Shader.PropertyToID("_CharShadowCascadeParams"); 52 | public static int _UseBrightestLight = Shader.PropertyToID("_UseBrightestLight"); 53 | } 54 | 55 | 56 | /* Member Variables */ 57 | private RTHandle m_CharShadowRT; 58 | private ProfilingSampler m_ProfilingSampler; 59 | private PassData m_PassData; 60 | private static int[] s_TextureSize = new int[2] { 1, 1 }; 61 | private CharSoftShadowMode m_SoftShadowMode; 62 | private float m_cascadeResolutionScale = 1f; 63 | private float m_cascadeMaxDistance; 64 | private FilteringSettings m_FilteringSettings; 65 | 66 | 67 | public CharacterShadowPass(RenderPassEvent evt, RenderQueueRange renderQueueRange) 68 | { 69 | m_PassData = new PassData(); 70 | m_FilteringSettings = new FilteringSettings(renderQueueRange); 71 | renderPassEvent = evt; 72 | } 73 | 74 | public void Dispose() 75 | { 76 | m_CharShadowRT?.Release(); 77 | } 78 | 79 | public void Setup(string featureName, in RenderingData renderingData, CharacterShadowConfig config, bool additionalShadowEnabled) 80 | { 81 | m_ProfilingSampler = new ProfilingSampler(featureName); 82 | m_PassData.bias = new Vector3(config.bias, config.normalBias, 0f); 83 | m_PassData.stepSmoothness = config.stepSmoothness; 84 | m_PassData.highSoftShadowBlurDistance = config.highSoftShadowBlurDistance; 85 | var scale = (int)config.textureScale; 86 | m_cascadeResolutionScale = CharacterShadowUtils.FindCascadedShadowMapResolutionScale(renderingData, config.cascadeSplit); 87 | m_cascadeMaxDistance = config.cascadeSplit.w; 88 | s_TextureSize[0] = 1024 * scale; 89 | s_TextureSize[1] = 1024 * scale; 90 | m_PassData.precision = (int)config.precision; 91 | m_PassData.useBrightestLight = additionalShadowEnabled ? config.useBrightestLight : false; 92 | m_PassData.followLightLayer = config.followLayerMask; 93 | m_SoftShadowMode = config.softShadowMode; 94 | } 95 | 96 | public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) 97 | { 98 | var descriptor = new RenderTextureDescriptor(s_TextureSize[0], s_TextureSize[1], (RenderTextureFormat)m_PassData.precision, 0); 99 | descriptor.dimension = TextureDimension.Tex2D; 100 | descriptor.sRGB = false; 101 | // Allocate Char Shadowmap 102 | RenderingUtils.ReAllocateIfNeeded(ref m_CharShadowRT, descriptor, FilterMode.Bilinear, name:"CharShadowMap"); 103 | cmd.SetGlobalTexture(IDs._CharShadowMap, m_CharShadowRT); 104 | 105 | m_PassData.charShadowRT = m_CharShadowRT; 106 | cmd.SetGlobalVector(IDs._CharShadowCascadeParams, new Vector4(m_cascadeMaxDistance, m_cascadeResolutionScale, 0, 0)); 107 | cmd.SetGlobalInt(IDs._UseBrightestLight, m_PassData.useBrightestLight ? 1 : 0); 108 | CoreUtils.SetKeyword(cmd, "_HIGH_CHAR_SOFTSHADOW", m_SoftShadowMode == CharSoftShadowMode.High); 109 | } 110 | 111 | private static void SetCharShadowConfig(CommandBuffer cmd, PassData passData, ref RenderingData renderingData) 112 | { 113 | CharacterShadowUtils.SetShadowmapLightData(cmd, ref renderingData, passData.useBrightestLight, passData.followLightLayer); 114 | 115 | var lightCamera = CharShadowCamera.Instance.lightCamera; 116 | if (lightCamera != null) 117 | { 118 | float widthScale = (float)Screen.width / (float)Screen.height; 119 | passData.projectM = lightCamera.projectionMatrix; 120 | passData.viewM = lightCamera.worldToCameraMatrix; 121 | passData.viewM.m00 *= widthScale; 122 | } 123 | 124 | // Set global properties 125 | float invShadowMapWidth = 1.0f / s_TextureSize[0]; 126 | float invShadowMapHeight = 1.0f / s_TextureSize[1]; 127 | float invHalfShadowMapWidth = 0.5f * invShadowMapWidth; 128 | float invHalfShadowMapHeight = 0.5f * invShadowMapHeight; 129 | 130 | cmd.SetGlobalVector(IDs._CharShadowParams, new Vector4(passData.bias.x, passData.bias.y, passData.stepSmoothness, passData.highSoftShadowBlurDistance)); 131 | cmd.SetGlobalMatrix(IDs._ViewMatrix, passData.viewM); 132 | cmd.SetGlobalMatrix(IDs._ProjMatrix, passData.projectM); 133 | 134 | cmd.SetGlobalVector(IDs._ShadowOffset0, new Vector4(-invHalfShadowMapWidth, -invHalfShadowMapHeight, invHalfShadowMapWidth, -invHalfShadowMapHeight)); 135 | cmd.SetGlobalVector(IDs._ShadowOffset1, new Vector4(-invHalfShadowMapWidth, invHalfShadowMapHeight, invHalfShadowMapWidth, invHalfShadowMapHeight)); 136 | cmd.SetGlobalVector(IDs._ShadowMapSize, new Vector4(invShadowMapWidth, invShadowMapHeight, s_TextureSize[0], s_TextureSize[1])); 137 | } 138 | 139 | // Cleanup any allocated resources that were created during the execution of this render pass. 140 | public override void OnCameraCleanup(CommandBuffer cmd) 141 | { 142 | 143 | } 144 | 145 | public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) 146 | { 147 | m_PassData.filteringSettings = m_FilteringSettings; 148 | m_PassData.profilingSampler = m_ProfilingSampler; 149 | 150 | ExecuteCharShadowPass(context, m_PassData, ref renderingData); 151 | } 152 | 153 | private static void ExecuteCharShadowPass(ScriptableRenderContext context, PassData passData, ref RenderingData renderingData) 154 | { 155 | var cmd = CommandBufferPool.Get(); 156 | var filteringSettings = passData.filteringSettings; 157 | var drawSettings = RenderingUtils.CreateDrawingSettings(k_ShaderTagId, ref renderingData, SortingCriteria.CommonOpaque); 158 | 159 | using (new ProfilingScope(cmd, passData.profilingSampler)) 160 | { 161 | // Shadowmap 162 | SetCharShadowConfig(cmd, passData, ref renderingData); 163 | CoreUtils.SetRenderTarget(cmd, passData.charShadowRT, ClearFlag.Color, 0, CubemapFace.Unknown, 0); 164 | context.ExecuteCommandBuffer(cmd); 165 | cmd.Clear(); 166 | 167 | context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filteringSettings); 168 | } 169 | 170 | context.ExecuteCommandBuffer(cmd); 171 | CommandBufferPool.Release(cmd); 172 | } 173 | 174 | private class PassData 175 | { 176 | public FilteringSettings filteringSettings; 177 | public ProfilingSampler profilingSampler; 178 | public Matrix4x4 viewM; 179 | public Matrix4x4 projectM; 180 | public Vector3 bias; 181 | public float stepSmoothness; 182 | public float highSoftShadowBlurDistance; 183 | public int precision; 184 | public bool useBrightestLight; 185 | public LayerMask followLightLayer; 186 | public RTHandle charShadowRT; 187 | } 188 | } 189 | } -------------------------------------------------------------------------------- /Scripts/CharacterShadowPass.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f54506c82a3597042bb12bd53c36b2aa 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/CharacterShadowUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | using UnityEngine.Rendering; 6 | using UnityEngine.Rendering.Universal; 7 | using Unity.Collections; 8 | 9 | namespace ToonCharacterShadow 10 | { 11 | public static class CharacterShadowUtils 12 | { 13 | private const float CHAR_SHADOW_CULLING_DIST = 18.0f; 14 | private static List s_vSpotLights = new List(256); 15 | private static List s_vSpotLightIndices = new List(256); 16 | private static List> s_SortedSpotLights = new List>(256); 17 | private static int s_CharShadowLocalLightIndex = Shader.PropertyToID("_CharShadowLocalLightIndex"); 18 | private static int s_BrightestLightDirection = Shader.PropertyToID("_BrightestLightDirection"); 19 | 20 | public static bool IfCharShadowUpdateNeeded(in RenderingData renderingData) 21 | { 22 | var cameraWorldPos = renderingData.cameraData.camera.transform.position; 23 | if (CharShadowCamera.Instance == null || CharShadowCamera.Instance.activeTarget == null) 24 | { 25 | return false; 26 | } 27 | var charWorldPos = CharShadowCamera.Instance.activeTarget.position; 28 | var diff = Vector3.Distance(cameraWorldPos,charWorldPos); 29 | return diff < CHAR_SHADOW_CULLING_DIST; 30 | } 31 | 32 | /// 33 | /// CharShadowMap Cascade index - 1(near), 0.5, 0.25, 0.125(far) 34 | /// 35 | public static float FindCascadedShadowMapResolutionScale(in RenderingData renderingData, Vector4 cascadeSplit) 36 | { 37 | var cameraWorldPos = renderingData.cameraData.camera.transform.position; 38 | if (CharShadowCamera.Instance == null || CharShadowCamera.Instance.activeTarget == null) 39 | { 40 | return 0.125f; 41 | } 42 | var charWorldPos = CharShadowCamera.Instance.activeTarget.position; 43 | var diff = Vector3.Distance(cameraWorldPos, charWorldPos); 44 | if (diff < cascadeSplit.x) 45 | return 1f; 46 | else if (diff < cascadeSplit.y) 47 | return 0.5f; 48 | else if (diff < cascadeSplit.z) 49 | return 0.25f; 50 | return 0.125f; 51 | } 52 | 53 | /// 54 | /// 1. if (useBrighestLightOnly == true) : LightIndex = spot or mainLight. 55 | /// 2. if (useBrighestLightOnly == false) : LightIndex = mainLight 56 | /// 57 | public static void SetShadowmapLightData(CommandBuffer cmd, ref RenderingData renderingData, bool useBrighestLight, LayerMask followLightLayer) 58 | { 59 | var spotLightIndices = CalculateMostIntensiveLightIndices(ref renderingData, followLightLayer); 60 | var visibleLights = renderingData.lightData.visibleLights; 61 | if (spotLightIndices == null || (spotLightIndices[0] < 0 && spotLightIndices[1] < 0)) 62 | { 63 | if (renderingData.lightData.mainLightIndex != -1) 64 | { 65 | CharShadowCamera.Instance.SetLightCameraTransform(visibleLights[renderingData.lightData.mainLightIndex].light); 66 | cmd.SetGlobalVector(s_BrightestLightDirection, -visibleLights[renderingData.lightData.mainLightIndex].light.transform.forward); 67 | } 68 | return; 69 | } 70 | 71 | var lightCount = renderingData.lightData.visibleLights.Length; 72 | var lightOffset = 0; 73 | while (lightOffset < lightCount && visibleLights[lightOffset].lightType == LightType.Directional) 74 | { 75 | lightOffset++; 76 | } 77 | var hasMainLight = 0; 78 | 79 | float mainLightStrength = 0f; 80 | int brightestLightIndex = -1; 81 | int brightestSpotLightIndex = -1; 82 | var brightestLightDirection = new Vector3(0, -1, 0); 83 | 84 | // Find stronger light among mainLight & brighest spot light 85 | if (renderingData.lightData.mainLightIndex != -1 && lightOffset != 0) 86 | { 87 | hasMainLight = 1; 88 | brightestSpotLightIndex = spotLightIndices[0] + hasMainLight; 89 | brightestLightIndex = renderingData.lightData.mainLightIndex; 90 | 91 | var mainLight = visibleLights[renderingData.lightData.mainLightIndex].light; 92 | var mainLightColor = mainLight.color * mainLight.intensity; 93 | mainLightStrength = mainLightColor.r * 0.299f + mainLightColor.g * 0.587f + mainLightColor.b * 0.114f; 94 | } 95 | else 96 | { 97 | if (spotLightIndices[0] >= 0) 98 | { 99 | brightestLightIndex = brightestSpotLightIndex = spotLightIndices[0] + hasMainLight; 100 | } 101 | else 102 | { 103 | brightestLightIndex = brightestSpotLightIndex = spotLightIndices[1] + hasMainLight; 104 | } 105 | } 106 | 107 | // Replace with the brighest spot light 108 | if (useBrighestLight && brightestSpotLightIndex >= 0) 109 | { 110 | var brightestSpotLightColor = visibleLights[brightestSpotLightIndex].light.color * visibleLights[brightestSpotLightIndex].light.intensity; 111 | var brightestSpotLightStrength = brightestSpotLightColor.r * 0.299f + brightestSpotLightColor.g * 0.587f + brightestSpotLightColor.b * 0.114f; 112 | brightestLightIndex = (hasMainLight == 1 && mainLightStrength >= brightestSpotLightStrength) ? renderingData.lightData.mainLightIndex : brightestSpotLightIndex; 113 | } 114 | 115 | // Update Light Camera transform (Main or Brighest light) 116 | if (brightestLightIndex >= 0 && brightestLightIndex < visibleLights.Length) 117 | { 118 | CharShadowCamera.Instance.SetLightCameraTransform(visibleLights[brightestLightIndex].light); 119 | brightestLightDirection = -visibleLights[brightestLightIndex].light.transform.forward; 120 | } 121 | 122 | // Send to GPU 123 | cmd.SetGlobalVector(s_BrightestLightDirection, brightestLightDirection); 124 | cmd.SetGlobalInt(s_CharShadowLocalLightIndex, brightestSpotLightIndex >= 0 ? brightestSpotLightIndex - hasMainLight : -1); 125 | } 126 | 127 | /// 128 | /// [0]: FollowLight, [1]: Additional SpotLight 129 | /// 130 | private static List CalculateMostIntensiveLightIndices(ref RenderingData renderingData, LayerMask followLayer) 131 | { 132 | if (CharShadowCamera.Instance == null || CharShadowCamera.Instance.activeTarget == null) 133 | { 134 | return null; 135 | } 136 | 137 | var lightCount = renderingData.lightData.visibleLights.Length; 138 | var lightOffset = 0; 139 | while (lightOffset < lightCount && renderingData.lightData.visibleLights[lightOffset].lightType == LightType.Directional) 140 | { 141 | lightOffset++; 142 | } 143 | lightCount -= lightOffset; 144 | var directionalLightCount = lightOffset; 145 | if (renderingData.lightData.mainLightIndex != -1 && directionalLightCount != 0) directionalLightCount -= 1; 146 | var visibleLights = renderingData.lightData.visibleLights.GetSubArray(lightOffset, lightCount); 147 | 148 | s_vSpotLights.Clear(); 149 | s_vSpotLightIndices.Clear(); 150 | s_SortedSpotLights.Clear(); 151 | 152 | // Extract spot lights 153 | for (int i = 0; i < visibleLights.Length; i++) 154 | { 155 | if (visibleLights[i].lightType == LightType.Spot) 156 | { 157 | s_vSpotLightIndices.Add(i + directionalLightCount); 158 | s_vSpotLights.Add(visibleLights[i]); 159 | } 160 | } 161 | 162 | // Calculate light intensity 163 | var target = CharShadowCamera.Instance.activeTarget; 164 | for (int i = 0; i < s_vSpotLights.Count; i++) 165 | { 166 | var light = s_vSpotLights[i].light; 167 | var diff = target.position - light.transform.position; 168 | var dirToTarget = Vector3.Normalize(diff); 169 | var L = light.transform.rotation * Vector3.forward; 170 | var dotL = Vector3.Dot(dirToTarget, L); 171 | var distance = diff.magnitude; 172 | var cos = Mathf.Cos(light.spotAngle * Mathf.Deg2Rad); 173 | if (dotL <= cos || distance > light.range) 174 | { 175 | continue; 176 | } 177 | 178 | var finalColor = s_vSpotLights[i].finalColor; 179 | var atten = 1f - distance / light.range; 180 | var strength = (finalColor.r * 0.229f + finalColor.g * 0.587f + finalColor.b * 0.114f) * atten * cos; 181 | if (strength > 0.01f) 182 | { 183 | s_SortedSpotLights.Add(new KeyValuePair(strength, s_vSpotLightIndices[i])); 184 | } 185 | } 186 | // Sort 187 | s_SortedSpotLights.Sort((x, y) => y.Key.CompareTo(x.Key)); 188 | 189 | var charSpotLightIndices = new List(2) { -1, -1 }; 190 | int followLightLayer = (int)Mathf.Log(followLayer.value, 2); 191 | for (int i = 0; i < s_SortedSpotLights.Count; i++) 192 | { 193 | var curr = s_SortedSpotLights[i].Value; 194 | if (visibleLights[curr].light.gameObject.layer == followLightLayer) 195 | { 196 | if (charSpotLightIndices[0] < 0) 197 | charSpotLightIndices[0] = curr; 198 | } 199 | else 200 | { 201 | if (charSpotLightIndices[1] < 0) 202 | charSpotLightIndices[1] = curr; 203 | } 204 | } 205 | 206 | return charSpotLightIndices; 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Scripts/CharacterShadowUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 951f4818585b7064fa8cccaab165cbe4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/TransparentShadowPass.cs: -------------------------------------------------------------------------------- 1 | /// NOTE) 2 | /// This feature should be used only for character's cloth. 3 | /// Otherwise, the shadow will cast to far object as well. 4 | /// Limitations: Not will behave natural if more than 2 transparent clothes overlapped. 5 | 6 | /// How to use 7 | /// 1. Add pass to your shader to use 'TransparentShadowPass.hlsl' 8 | /// with "TransparentShadow" and "TransparentAlphaSum" LightMode. (See below example) 9 | /* [Pass Example - Unity Toon Shader] 10 | * NOTE) We assume that the shader use "_MainTex" and "_BaseColor", "_ClippingMask" properties. 11 | * Pass 12 | * { 13 | * Name "TransparentShadow" 14 | * Tags {"LightMode" = "TransparentShadow"} 15 | * 16 | * ZWrite Off 17 | * ZTest Off 18 | * Cull Off 19 | * Blend One One 20 | * BlendOp Max 21 | * 22 | * HLSLPROGRAM 23 | * #pragma target 2.0 24 | * 25 | * #pragma prefer_hlslcc gles 26 | * #pragma exclude_renderers d3d11_9x 27 | * #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 28 | * #pragma shader_feature_local _ALPHATEST_ON 29 | * 30 | * #pragma vertex TransparentShadowVert 31 | * #pragma fragment TransparentShadowFragment 32 | * 33 | * #include "Packages/com.unity.tooncharactershadow/Shaders/TransparentShadowPass.hlsl" 34 | * ENDHLSL 35 | * } 36 | * Pass 37 | * { 38 | * Name "TransparentAlphaSum" 39 | * Tags {"LightMode" = "TransparentAlphaSum"} 40 | * 41 | * ZWrite Off 42 | * ZTest Off 43 | * Cull Off 44 | * Blend One One 45 | * BlendOp Add 46 | * 47 | * HLSLPROGRAM 48 | * #pragma target 2.0 49 | * 50 | * #pragma prefer_hlslcc gles 51 | * #pragma exclude_renderers d3d11_9x 52 | * #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 53 | * #pragma shader_feature_local _ALPHATEST_ON 54 | * 55 | * #pragma vertex TransparentAlphaSumVert 56 | * #pragma fragment TransparentAlphaSumFragment 57 | * 58 | * #include "Packages/com.unity.tooncharactershadow/Shaders/TransparentShadowPass.hlsl" 59 | * ENDHLSL 60 | * } 61 | */ 62 | 63 | using UnityEngine; 64 | using UnityEngine.Rendering; 65 | using UnityEngine.Rendering.Universal; 66 | using UnityEngine.Experimental.Rendering; 67 | 68 | namespace ToonCharacterShadow 69 | { 70 | public class TransparentShadowPass : ScriptableRenderPass 71 | { 72 | /* Static Variables */ 73 | private static readonly ShaderTagId k_ShaderTagId = new ShaderTagId("TransparentShadow"); 74 | private static readonly ShaderTagId k_AlphaSumShaderTagId = new ShaderTagId("TransparentAlphaSum"); 75 | private static int s_TransparentShadowMapId = Shader.PropertyToID("_TransparentShadowMap"); 76 | private static int s_TransparentAlphaSumId = Shader.PropertyToID("_TransparentAlphaSum"); 77 | private static int s_ShadowMapSize = Shader.PropertyToID("_CharTransparentShadowmapSize"); 78 | private static int s_ShadowMapIndex = Shader.PropertyToID("_CharShadowmapIndex"); 79 | private static int[] s_TextureSize = new int[2] { 1, 1 }; 80 | 81 | 82 | /* Member Variables */ 83 | private RTHandle m_TransparentShadowRT; 84 | private RTHandle m_TransparentAlphaSumRT; 85 | private ProfilingSampler m_ProfilingSampler; 86 | private PassData m_PassData; 87 | private FilteringSettings m_FilteringSettings; 88 | 89 | public TransparentShadowPass(RenderPassEvent evt, RenderQueueRange renderQueueRange) 90 | { 91 | m_PassData = new PassData(); 92 | m_FilteringSettings = new FilteringSettings(renderQueueRange); 93 | renderPassEvent = evt; 94 | } 95 | 96 | public void Dispose() 97 | { 98 | m_TransparentShadowRT?.Release(); 99 | m_TransparentAlphaSumRT?.Release(); 100 | } 101 | 102 | public void Setup(string featureName, in RenderingData renderingData, CharacterShadowConfig config) 103 | { 104 | m_ProfilingSampler = new ProfilingSampler(featureName); 105 | var scale = (int)config.transparentTextureScale; 106 | s_TextureSize[0] = 1024 * scale; 107 | s_TextureSize[1] = 1024 * scale; 108 | m_PassData.precision = (int)config.precision; 109 | } 110 | 111 | public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) 112 | { 113 | // Depth 114 | var descriptor = new RenderTextureDescriptor(s_TextureSize[0], s_TextureSize[1], (RenderTextureFormat)m_PassData.precision, 0); 115 | descriptor.dimension = TextureDimension.Tex2D; 116 | descriptor.sRGB = false; 117 | 118 | RenderingUtils.ReAllocateIfNeeded(ref m_TransparentShadowRT, descriptor, FilterMode.Bilinear, name:"TransparentShadowMap"); 119 | cmd.SetGlobalTexture(s_TransparentShadowMapId, m_TransparentShadowRT); 120 | 121 | // Alpha Sum 122 | descriptor.graphicsFormat = GraphicsFormat.R16_SFloat; 123 | RenderingUtils.ReAllocateIfNeeded(ref m_TransparentAlphaSumRT, descriptor, FilterMode.Bilinear, name:"TransparentAlphaSum"); 124 | cmd.SetGlobalTexture(s_TransparentAlphaSumId, m_TransparentAlphaSumRT); 125 | 126 | m_PassData.target = m_TransparentShadowRT; 127 | m_PassData.alphaSumTarget = m_TransparentAlphaSumRT; 128 | 129 | // Set global properties 130 | float invShadowMapWidth = 1.0f / s_TextureSize[0]; 131 | float invShadowMapHeight = 1.0f / s_TextureSize[1]; 132 | 133 | cmd.SetGlobalVector(s_ShadowMapSize, new Vector4(invShadowMapWidth, invShadowMapHeight, s_TextureSize[0], s_TextureSize[1])); 134 | } 135 | 136 | // Cleanup any allocated resources that were created during the execution of this render pass. 137 | public override void OnCameraCleanup(CommandBuffer cmd) 138 | { 139 | 140 | } 141 | 142 | public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) 143 | { 144 | m_PassData.filteringSettings = m_FilteringSettings; 145 | m_PassData.profilingSampler = m_ProfilingSampler; 146 | 147 | ExecuteTransparentShadowPass(context, m_PassData, ref renderingData); 148 | } 149 | 150 | private static void ExecuteTransparentShadowPass(ScriptableRenderContext context, PassData passData, ref RenderingData renderingData) 151 | { 152 | var cmd = CommandBufferPool.Get(); 153 | var filteringSettings = passData.filteringSettings; 154 | 155 | using (new ProfilingScope(cmd, passData.profilingSampler)) 156 | { 157 | cmd.SetGlobalFloat(s_ShadowMapIndex, 0); 158 | CoreUtils.SetRenderTarget(cmd, passData.target, ClearFlag.Color, 0, CubemapFace.Unknown, 0); 159 | context.ExecuteCommandBuffer(cmd); 160 | cmd.Clear(); 161 | 162 | // Depth & Alpha Sum 163 | var drawSettings = RenderingUtils.CreateDrawingSettings(k_ShaderTagId, ref renderingData, SortingCriteria.CommonTransparent); 164 | context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filteringSettings); 165 | 166 | CoreUtils.SetRenderTarget(cmd, passData.alphaSumTarget, ClearFlag.Color, 0, CubemapFace.Unknown, 0); 167 | context.ExecuteCommandBuffer(cmd); 168 | cmd.Clear(); 169 | 170 | var alphaDrawSettings = RenderingUtils.CreateDrawingSettings(k_AlphaSumShaderTagId, ref renderingData, SortingCriteria.CommonTransparent); 171 | context.DrawRenderers(renderingData.cullResults, ref alphaDrawSettings, ref filteringSettings); 172 | } 173 | 174 | context.ExecuteCommandBuffer(cmd); 175 | CommandBufferPool.Release(cmd); 176 | } 177 | 178 | private class PassData 179 | { 180 | public FilteringSettings filteringSettings; 181 | public ProfilingSampler profilingSampler; 182 | public RTHandle target; 183 | public RTHandle alphaSumTarget; 184 | public int precision; 185 | } 186 | } 187 | } -------------------------------------------------------------------------------- /Scripts/TransparentShadowPass.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 56fb3014fa68c424ebc5cec3c4b71490 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Shaders.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bbbc539793c0ad34888712c4c48b33cc 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Shaders/CharacterShadowDepthPass.hlsl: -------------------------------------------------------------------------------- 1 | #ifndef CHARACTER_SHADOW_DEPTH_PASS_INCLUDED 2 | #define CHARACTER_SHADOW_DEPTH_PASS_INCLUDED 3 | 4 | #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" 5 | #include "CharacterShadowTransforms.hlsl" 6 | 7 | // Below material properties must be declared in seperate shader input to make compatible with SRP Batcher. 8 | // CBUFFER_START(UnityPerMaterial) 9 | // float4 _ClippingMask_ST; 10 | // CBUFFER_END 11 | // TEXTURE2D(_ClippingMask); 12 | 13 | SAMPLER(sampler_ClippingMask); 14 | 15 | struct Attributes 16 | { 17 | float4 position : POSITION; 18 | float2 texcoord : TEXCOORD0; 19 | float3 normal : NORMAL; 20 | // UNITY_VERTEX_INPUT_INSTANCE_ID 21 | }; 22 | 23 | struct Varyings 24 | { 25 | float2 uv : TEXCOORD0; 26 | float3 positionOS : TEXCOORD1; 27 | float4 positionCS : SV_POSITION; 28 | // UNITY_VERTEX_INPUT_INSTANCE_ID 29 | // UNITY_VERTEX_OUTPUT_STEREO 30 | }; 31 | 32 | Varyings CharShadowVertex(Attributes input) 33 | { 34 | Varyings output = (Varyings)0; 35 | // UNITY_SETUP_INSTANCE_ID(input); 36 | // UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); 37 | 38 | output.uv = TRANSFORM_TEX(input.texcoord, _ClippingMask); 39 | output.positionCS = CharShadowObjectToHClip(input.position.xyz, input.normal); 40 | 41 | #if UNITY_REVERSED_Z 42 | output.positionCS.z = min(output.positionCS.z, UNITY_NEAR_CLIP_VALUE); 43 | #else 44 | output.positionCS.z = max(output.positionCS.z, UNITY_NEAR_CLIP_VALUE); 45 | #endif 46 | output.positionCS.xy *= _CharShadowCascadeParams.y; 47 | 48 | output.positionOS = input.position.xyz; 49 | 50 | return output; 51 | } 52 | 53 | float CharShadowFragment(Varyings input) : SV_TARGET 54 | { 55 | // UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); 56 | 57 | float alphaClipVar = SAMPLE_TEXTURE2D(_ClippingMask, sampler_ClippingMask, input.uv).r; 58 | clip(alphaClipVar- 0.001); 59 | 60 | return input.positionCS.z; 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /Shaders/CharacterShadowDepthPass.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 04a874b20d325d847a59516d20a8dba9 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Shaders/CharacterShadowInput.hlsl: -------------------------------------------------------------------------------- 1 | #ifndef CHARACTER_SHADOW_INPUT_INCLUDED 2 | #define CHARACTER_SHADOW_INPUT_INCLUDED 3 | 4 | CBUFFER_START(CharShadow) 5 | float4 _CharShadowParams; 6 | float4x4 _CharShadowViewM; 7 | float4x4 _CharShadowProjM; 8 | float4 _CharShadowOffset0; 9 | float4 _CharShadowOffset1; 10 | float4 _CharShadowmapSize; // rcp(width), rcp(height), width, height 11 | float4 _CharTransparentShadowmapSize; // rcp(width), rcp(height), width, height 12 | float4 _CharShadowCascadeParams; // x: cascadeMaxDistance, y: cascadeResolutionScale 13 | float4 _BrightestLightDirection; 14 | uint _CharShadowLocalLightIndex; 15 | uint _UseBrightestLight; 16 | uint _char_shadow_pad00_; 17 | uint _char_shadow_pad01_; 18 | CBUFFER_END 19 | 20 | #define _CharShadowBias _CharShadowParams.xy 21 | #define _CharShadowStepSmoothness _CharShadowParams.z 22 | #define _HighSoftShadowBlurDistance _CharShadowParams.w 23 | 24 | TEXTURE2D(_CharShadowMap); 25 | SAMPLER(sampler_CharShadowMap); 26 | TEXTURE2D(_TransparentShadowMap); 27 | TEXTURE2D(_TransparentAlphaSum); 28 | 29 | #endif -------------------------------------------------------------------------------- /Shaders/CharacterShadowInput.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: df140c1c45743134a84a73b63c510d95 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Shaders/CharacterShadowTransforms.hlsl: -------------------------------------------------------------------------------- 1 | #ifndef CHARACTER_SHADOW_TRANSFORMS_INCLUDED 2 | #define CHARACTER_SHADOW_TRANSFORMS_INCLUDED 3 | 4 | #include "./CharacterShadowInput.hlsl" 5 | 6 | #define _CharShadowCullingDist -(_CharShadowCascadeParams.x - 2) // should be less than renderer feature's max cascade split value 7 | 8 | float3 ApplyCharShadowBias(float3 positionWS, float3 normalWS, float3 lightDirection) 9 | { 10 | float depthBias = _CharShadowBias.x; 11 | float normalBias = _CharShadowBias.y; 12 | 13 | // Depth Bias 14 | positionWS = lightDirection * depthBias + positionWS; 15 | 16 | // Normal Bias 17 | float invNdotL = 1.0 - saturate(dot(lightDirection, normalWS)); 18 | float scale = invNdotL * -normalBias; 19 | positionWS = normalWS * scale.xxx + positionWS; 20 | return positionWS; 21 | } 22 | 23 | float4 CharShadowWorldToView(float3 positionWS) 24 | { 25 | return mul(_CharShadowViewM, float4(positionWS, 1.0)); 26 | } 27 | float4 CharShadowViewToHClip(float4 positionVS) 28 | { 29 | return mul(_CharShadowProjM, positionVS); 30 | } 31 | float4 CharShadowWorldToHClip(float3 positionWS) 32 | { 33 | return CharShadowViewToHClip(CharShadowWorldToView(positionWS)); 34 | } 35 | float4 CharShadowObjectToHClip(float3 positionOS, float3 normalWS) 36 | { 37 | float3 positionWS = mul(UNITY_MATRIX_M, float4(positionOS, 1.0)).xyz; 38 | positionWS = ApplyCharShadowBias(positionWS, normalWS, _BrightestLightDirection.xyz); 39 | 40 | return CharShadowWorldToHClip(positionWS); 41 | } 42 | float4 CharShadowObjectToHClipWithoutBias(float3 positionOS) 43 | { 44 | float3 positionWS = mul(UNITY_MATRIX_M, float4(positionOS, 1.0)).xyz; 45 | return CharShadowWorldToHClip(positionWS); 46 | } 47 | 48 | // Skip if too far (since we don't use mipmap for charshadowmap, manually cull this calculation based on view depth.) 49 | bool IfCharShadowCulled(float viewPosZ) 50 | { 51 | return viewPosZ < _CharShadowCullingDist; 52 | } 53 | 54 | #endif -------------------------------------------------------------------------------- /Shaders/CharacterShadowTransforms.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eede975737818d2408275bb73f92937c 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Shaders/DeclareCharacterShadowTexture.hlsl: -------------------------------------------------------------------------------- 1 | #ifndef CHARACTER_SHADOW_DEPTH_INPUT_INCLUDED 2 | #define CHARACTER_SHADOW_DEPTH_INPUT_INCLUDED 3 | 4 | #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl" 5 | #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Shadow/ShadowSamplingTent.hlsl" 6 | #include "./CharacterShadowTransforms.hlsl" 7 | 8 | #define MAX_CHAR_SHADOWMAPS 1 9 | 10 | half GetLinearStep(float m, float M, float x) 11 | { 12 | return saturate((x - m) / (M - m)); 13 | } 14 | 15 | uint LocalLightIndexToShadowmapIndex(uint lightindex) 16 | { 17 | if (_UseBrightestLight > 0 && lightindex == _CharShadowLocalLightIndex) 18 | return 0; 19 | 20 | return MAX_CHAR_SHADOWMAPS; 21 | } 22 | 23 | #define ADDITIONAL_CHARSHADOW_CHECK(i, lightIndex) { \ 24 | i = LocalLightIndexToShadowmapIndex(lightIndex); \ 25 | if (i >= MAX_CHAR_SHADOWMAPS) \ 26 | return 0; } 27 | 28 | float3 TransformWorldToCharShadowCoord(float3 worldPos) 29 | { 30 | float4 clipPos = CharShadowWorldToHClip(worldPos); 31 | #if UNITY_REVERSED_Z 32 | clipPos.z = min(clipPos.z, UNITY_NEAR_CLIP_VALUE); 33 | #else 34 | clipPos.z = max(clipPos.z, UNITY_NEAR_CLIP_VALUE); 35 | #endif 36 | float3 ndc = clipPos.xyz / clipPos.w; 37 | float2 ssUV = ndc.xy * 0.5 + 0.5; 38 | #if UNITY_UV_STARTS_AT_TOP 39 | ssUV.y = 1.0 - ssUV.y; 40 | #endif 41 | return float3(ssUV, ndc.z); 42 | } 43 | 44 | void ScaleUVForCascadeCharShadow(inout float2 uv) 45 | { 46 | // Refactor below logic to MAD 47 | // uv *= _CharShadowCascadeParams.y; 48 | // uv = (1.0 - _CharShadowCascadeParams.y) * 0.5 + uv; 49 | uv = uv * _CharShadowCascadeParams.y - (_CharShadowCascadeParams.y * 0.5 + 0.5); 50 | } 51 | 52 | // Reference: UE5 SpiralBlur-Texture 53 | half SampleSpiralBlur(TEXTURE2D_PARAM(tex, samplerTex), float2 UV, float Distance, float DistanceSteps = 16, float RadialSteps = 8, float RadialOffset = 0.62, float KernelPower = 1) 54 | { 55 | half CurColor = 0; 56 | float2 NewUV = UV; 57 | int i = 0; 58 | float StepSize = Distance / (int)DistanceSteps; 59 | float CurDistance = 0; 60 | float2 CurOffset = 0; 61 | float SubOffset = 0; 62 | float accumdist = 0; 63 | 64 | if (DistanceSteps < 1) 65 | { 66 | return SAMPLE_TEXTURE2D(tex, samplerTex, UV).r; 67 | } 68 | 69 | while (i < (int)DistanceSteps) 70 | { 71 | CurDistance += StepSize; 72 | for (int j = 0; j < (int)RadialSteps; j++) 73 | { 74 | SubOffset +=1; 75 | CurOffset.x = cos(TWO_PI * (SubOffset / RadialSteps)); 76 | CurOffset.y = sin(TWO_PI * (SubOffset / RadialSteps)); 77 | NewUV.x = UV.x + CurOffset.x * CurDistance; 78 | NewUV.y = UV.y + CurOffset.y * CurDistance; 79 | float distpow = pow(CurDistance, KernelPower); 80 | CurColor += SAMPLE_TEXTURE2D(tex, samplerTex, NewUV).r * distpow; 81 | accumdist += distpow; 82 | } 83 | SubOffset += RadialOffset; 84 | i++; 85 | } 86 | CurColor = CurColor; 87 | CurColor /= accumdist; 88 | return CurColor; 89 | } 90 | 91 | half SampleCharacterShadowmap(float2 uv, float z) 92 | { 93 | // UV must be the scaled value with ScaleUVForCascadeCharShadow() 94 | float var = SAMPLE_TEXTURE2D(_CharShadowMap, sampler_CharShadowMap, uv).r; 95 | return (var - z) > _CharShadowBias.x; 96 | } 97 | 98 | half SampleCharacterShadowmapFiltered(float2 uv, float z, float biasOffset) 99 | { 100 | // UV must be the scaled value with ScaleUVForCascadeCharShadow() 101 | z += 0.00001; 102 | #ifdef _HIGH_CHAR_SOFTSHADOW 103 | float distance = _CharShadowmapSize.x * _CharShadowCascadeParams.y * _HighSoftShadowBlurDistance; 104 | float attenuation = SampleSpiralBlur(_CharShadowMap, sampler_CharShadowMap, uv, distance); 105 | #else 106 | float ow = _CharShadowmapSize.x * _CharShadowCascadeParams.y; 107 | float oh = _CharShadowmapSize.y * _CharShadowCascadeParams.y; 108 | float attenuation = SAMPLE_TEXTURE2D(_CharShadowMap, sampler_CharShadowMap, uv).r 109 | + SAMPLE_TEXTURE2D(_CharShadowMap, sampler_CharShadowMap, uv + float2(ow, ow)).r 110 | + SAMPLE_TEXTURE2D(_CharShadowMap, sampler_CharShadowMap, uv + float2(ow, -ow)).r 111 | + SAMPLE_TEXTURE2D(_CharShadowMap, sampler_CharShadowMap, uv + float2(-ow, ow)).r 112 | + SAMPLE_TEXTURE2D(_CharShadowMap, sampler_CharShadowMap, uv + float2(-ow, -ow)).r; 113 | attenuation /= 5.0f; 114 | #endif 115 | 116 | float smoothness = _CharShadowStepSmoothness; 117 | return GetLinearStep(-smoothness, smoothness, (attenuation - z) - (_CharShadowBias.x + biasOffset)); // (attenuation - z) > _CharShadowBias.x; 118 | } 119 | 120 | 121 | half SampleTransparentShadowmap(float2 uv, float z, SamplerState s) 122 | { 123 | // UV must be the scaled value with ScaleUVForCascadeCharShadow() 124 | float var = SAMPLE_TEXTURE2D(_TransparentShadowMap, s, uv).r; 125 | return (var - z) > _CharShadowBias.x; 126 | } 127 | 128 | half SampleTransparentShadowmapFiltered(float2 uv, float z, SamplerState s) 129 | { 130 | // UV must be the scaled value with ScaleUVForCascadeCharShadow() 131 | z += 0.00001; 132 | #if _HIGH_CHAR_SOFTSHADOW 133 | float distance = _CharTransparentShadowmapSize.x * _CharShadowCascadeParams.y * _HighSoftShadowBlurDistance; 134 | float attenuation = SampleSpiralBlur(_TransparentShadowMap, s, uv, distance); 135 | #else 136 | float ow = _CharTransparentShadowmapSize.x * _CharShadowCascadeParams.y; 137 | float oh = _CharTransparentShadowmapSize.y * _CharShadowCascadeParams.y; 138 | float attenuation = SAMPLE_TEXTURE2D(_TransparentShadowMap, s, uv).r 139 | + SAMPLE_TEXTURE2D(_TransparentShadowMap, s, uv + float2(ow, ow)).r 140 | + SAMPLE_TEXTURE2D(_TransparentShadowMap, s, uv + float2(ow, -ow)).r 141 | + SAMPLE_TEXTURE2D(_TransparentShadowMap, s, uv + float2(-ow, ow)).r 142 | + SAMPLE_TEXTURE2D(_TransparentShadowMap, s, uv + float2(-ow, -ow)).r; 143 | attenuation /= 5.0f; 144 | #endif 145 | 146 | float smoothness = _CharShadowStepSmoothness; 147 | return GetLinearStep(-smoothness, smoothness, (attenuation - z) - _CharShadowBias.x); 148 | } 149 | 150 | half TransparentAttenuation(float2 uv, float opacity) 151 | { 152 | // UV must be the scaled value with ScaleUVForCascadeCharShadow() 153 | // Saturate since texture could have value more than 1 154 | return saturate(SAMPLE_TEXTURE2D(_TransparentAlphaSum, sampler_CharShadowMap, uv).r - opacity); // Total alpha sum - current pixel's alpha 155 | } 156 | 157 | half GetTransparentShadow(float2 uv, float z, float opacity) 158 | { 159 | // UV must be the scaled value with ScaleUVForCascadeCharShadow() 160 | half hidden = SampleTransparentShadowmapFiltered(uv, z, sampler_CharShadowMap); 161 | half atten = TransparentAttenuation(uv, opacity); 162 | return min(hidden, atten); 163 | } 164 | 165 | half CharacterAndTransparentShadowmap(float2 uv, float z, float opacity, float biasOffset = 0) 166 | { 167 | // Scale uv first for cascade char shadow map 168 | ScaleUVForCascadeCharShadow(uv); 169 | return max(SampleCharacterShadowmapFiltered(uv, z, biasOffset), GetTransparentShadow(uv, z, opacity)); 170 | } 171 | 172 | half SampleCharacterAndTransparentShadow(float3 worldPos, float opacity, float biasOffset = 0) 173 | { 174 | if (dot(_MainLightPosition.xyz, _BrightestLightDirection.xyz) < 0.9999) 175 | return 0; 176 | 177 | if (IfCharShadowCulled(TransformWorldToView(worldPos).z)) 178 | return 0; 179 | 180 | float3 coord = TransformWorldToCharShadowCoord(worldPos); 181 | return CharacterAndTransparentShadowmap(coord.xy, coord.z, opacity, biasOffset); 182 | } 183 | 184 | half SampleAdditionalCharacterAndTransparentShadow(float3 worldPos, float opacity, uint lightIndex = 0, float biasOffset = 0) 185 | { 186 | #ifndef USE_FORWARD_PLUS 187 | return 0; 188 | #endif 189 | uint i; 190 | ADDITIONAL_CHARSHADOW_CHECK(i, lightIndex) 191 | 192 | if (IfCharShadowCulled(TransformWorldToView(worldPos).z)) 193 | return 0; 194 | 195 | float3 coord = TransformWorldToCharShadowCoord(worldPos); 196 | return CharacterAndTransparentShadowmap(coord.xy, coord.z, opacity, biasOffset); 197 | } 198 | 199 | #endif -------------------------------------------------------------------------------- /Shaders/DeclareCharacterShadowTexture.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3bcf42630096525429c9df2de1fb174b 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Shaders/TransparentShadowPass.hlsl: -------------------------------------------------------------------------------- 1 | #ifndef TRANSPARENT_SHADOW_PASS_INCLUDED 2 | #define TRANSPARENT_SHADOW_PASS_INCLUDED 3 | 4 | #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" 5 | #include "DeclareCharacterShadowTexture.hlsl" 6 | 7 | // Below material properties must be declared in seperate shader input to make compatible with SRP Batcher. 8 | // CBUFFER_START(UnityPerMaterial) 9 | // float4 _BaseColor; 10 | // float4 _MainTex_ST; 11 | // float4 _ClippingMask_ST; 12 | // CBUFFER_END 13 | // TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); 14 | // TEXTURE2D(_ClippingMask); 15 | 16 | struct Attributes 17 | { 18 | float4 position : POSITION; 19 | float2 texcoord : TEXCOORD0; 20 | }; 21 | 22 | struct ShadowVaryings 23 | { 24 | float4 positionCS : SV_POSITION; 25 | float2 uv : TEXCOORD0; 26 | float3 positionOS : TEXCOORD1; 27 | }; 28 | 29 | struct AlphaSumVaryings 30 | { 31 | float4 positionCS : SV_POSITION; 32 | float2 uv : TEXCOORD; 33 | float3 positionWS : TEXCOORD1; 34 | float3 positionOS : TEXCOORD2; 35 | }; 36 | 37 | ShadowVaryings TransparentShadowVert(Attributes input) 38 | { 39 | ShadowVaryings output = (ShadowVaryings)0; 40 | output.uv = input.texcoord; 41 | output.positionCS = CharShadowObjectToHClipWithoutBias(input.position.xyz); 42 | #if UNITY_REVERSED_Z 43 | output.positionCS.z = min(output.positionCS.z, UNITY_NEAR_CLIP_VALUE); 44 | #else 45 | output.positionCS.z = max(output.positionCS.z, UNITY_NEAR_CLIP_VALUE); 46 | #endif 47 | output.positionCS.xy *= _CharShadowCascadeParams.y; 48 | 49 | output.positionOS = input.position.xyz; 50 | 51 | return output; 52 | } 53 | 54 | AlphaSumVaryings TransparentAlphaSumVert(Attributes input) 55 | { 56 | AlphaSumVaryings output = (AlphaSumVaryings)0; 57 | output.uv = input.texcoord; 58 | output.positionCS = CharShadowObjectToHClipWithoutBias(input.position.xyz); 59 | #if UNITY_REVERSED_Z 60 | output.positionCS.z = min(output.positionCS.z, UNITY_NEAR_CLIP_VALUE); 61 | #else 62 | output.positionCS.z = max(output.positionCS.z, UNITY_NEAR_CLIP_VALUE); 63 | #endif 64 | output.positionCS.xy *= _CharShadowCascadeParams.y; 65 | output.positionWS = TransformObjectToWorld(input.position.xyz); 66 | 67 | output.positionOS = input.position.xyz; 68 | 69 | return output; 70 | } 71 | 72 | float TransparentShadowFragment(ShadowVaryings input) : SV_Target 73 | { 74 | // Use A Channel for alpha sum 75 | float alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, TRANSFORM_TEX(input.uv, _MainTex)).a * _BaseColor.a; 76 | alpha *= SAMPLE_TEXTURE2D(_ClippingMask, sampler_MainTex, TRANSFORM_TEX(input.uv, _ClippingMask)).r; 77 | clip(alpha - 0.001); 78 | 79 | return input.positionCS.z; // Depth 80 | } 81 | 82 | 83 | float TransparentAlphaSumFragment(AlphaSumVaryings input) : SV_Target 84 | { 85 | // Use A Channel for alpha sum 86 | float alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, TRANSFORM_TEX(input.uv, _MainTex)).a * _BaseColor.a; 87 | alpha *= SAMPLE_TEXTURE2D(_ClippingMask, sampler_MainTex, TRANSFORM_TEX(input.uv, _ClippingMask)).r; 88 | clip(alpha - 0.001); 89 | 90 | float4 clipPos = CharShadowWorldToHClip(input.positionWS); 91 | clipPos.xy *= _CharShadowCascadeParams.y; 92 | clipPos.z = 1.0; 93 | float3 ndc = clipPos.xyz / clipPos.w; 94 | float2 ssUV = ndc.xy * 0.5 + 0.5; 95 | #if UNITY_UV_STARTS_AT_TOP 96 | ssUV.y = 1.0 - ssUV.y; 97 | #endif 98 | 99 | // Discard behind fragment 100 | return lerp(alpha, 0, SampleCharacterShadowmap(ssUV, ndc.z)); 101 | } 102 | #endif 103 | -------------------------------------------------------------------------------- /Shaders/TransparentShadowPass.hlsl.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: feb95ab24622efa418a20612b68a671e 3 | ShaderIncludeImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /ToonCharacterShadow.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ToonCharacterShadow", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:c579267770062bf448e75eb160330b7f", 6 | "GUID:15fc0a57446b3144c949da3e2b9737a9", 7 | "GUID:b4517ec124862cb4bb3b8b27d72843a6", 8 | "GUID:ab67fb10353d84448ac887a7367cbda8", 9 | "GUID:3eae0364be2026648bf74846acb8a731", 10 | "GUID:df380645f10b7bc4b97d4f5eb6303d95", 11 | "GUID:46a67ded66a63de48b9329c593fc08de" 12 | ], 13 | "includePlatforms": [], 14 | "excludePlatforms": [], 15 | "allowUnsafeCode": false, 16 | "overrideReferences": false, 17 | "precompiledReferences": [], 18 | "autoReferenced": true, 19 | "defineConstraints": [], 20 | "versionDefines": [], 21 | "noEngineReferences": false 22 | } -------------------------------------------------------------------------------- /ToonCharacterShadow.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9327e2e532616f344af6c9e02bd5335b 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.unity.tooncharactershadow", 3 | "displayName":"Toon Chracter Shadow", 4 | "version": "0.1.0", 5 | "unity": "2022.3", 6 | "description": "Toon Chracter Shadow Package for URP Forward rendering.", 7 | "dependencies": 8 | { 9 | "com.unity.render-pipelines.core": "14.0.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6bd4a26f2c9982a4a90bceda0c481c63 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------