半透明オブジェクトはどのようにしてシャドウ効果を実現しますか？

今回の主な話題：半透明オブジェクトがシャドウ効果を受ける方法、Lightmapを手動で設定したがShadowmaskが失われる問題の解決策、カスタムInspectorで同時に複数オブジェクトの位置プロパティを変更する方法。

---
###レンダリング
Q1: “RenderType” = “Transparent”の場合、シャドウを受ける方法がないようです。モデルと表面の間の継ぎ目を覆うために、シーンに半透過性の地表を作成する必要があるので、シャドウを表示する必要があります。皆さんは何かより良い方法ありませんか？なぜデフォルトで半透明オブジェクトはシャドウを受け入れられませんか？

①
>Unityエンジンを別にして、本質的に、半透明オブジェクトはシャドウを間違いなく受け入れられます。前に「地表に一枚のガラス素材があり、それがガラスとその下の物オブジェクトにシャドウを落とす」効果を実現しました。したがって、自分が書いたShaderの場合、シャドウを受け入れたいなら、Shadowmapをサンプリングしてシャドウ計算プロセスを実行するだけで済みます。
Unityエンジンの場合、試した結果、確かにTransparentを選択したRenderTypeにシャドウはありませんでした。これに対して、Shaderに自分でShadowmapプロセスを強制的に実行したら解決できるかどうかがわかりませんので、問題主は自分でやってみてください。

>但し、注意すべきなのは、半透明オブジェクトがシャドウを受ける場合、特に問題主が解決したい表面の間の状況に対して、最後に生成されるシャドウは比較的に重くなます。これ原因は、半透明部分の下のオブジェクトもシャドウがあるし、半透明部分のシャドウはAlphaの影響で薄くなりますが、重ねると暗くなります。もちろん、Transparent部分はシャドウを受け入れません。つまり、Alpha Blend後にシャドウ効果は薄くなります。


②
>この問題は以前にいくつかの試みがありました。前述のように、デフォルトのTransparentはシャドウを受け入れませんが、カスタムShaderでShadowmapを強制運行することができます。 参照コードは次のとおりです。

>```ruby:
Shader "Transparent/Diffuse With Shadows"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Alpha ("Alpha", float) = 1
    }
    SubShader
    {
        Pass
        {
            Tags {"LightMode"="ForwardBase" "RenderType"="Transparent"}
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            ColorMask RGB
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
            #include "AutoLight.cginc"
            struct v2f
            {
                float2 uv : TEXCOORD0;
                SHADOW_COORDS(1)
                fixed3 diff : COLOR0;
                fixed3 ambient : COLOR1;
                float4 pos : SV_POSITION;
            };
            v2f vert (appdata_base v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord;
                half3 worldNormal = UnityObjectToWorldNormal(v.normal);
                half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
                o.diff = nl * _LightColor0.rgb;
                o.ambient = ShadeSH9(half4(worldNormal,1));
                TRANSFER_SHADOW(o)
                return o;
            }
            sampler2D _MainTex;
            float _Alpha;
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                fixed shadow = SHADOW_ATTENUATION(i);
                fixed3 lighting = i.diff * shadow + i.ambient;
                col.rgb *= lighting;
                col.a *= _Alpha;
                return col;
            }
            ENDCG
        }
    }
}
```

>しかし、このシェーダーを直接使用しても効果はありません…

>[ドキュメント](https://docs.unity3d.com/Manual/ShadowPerformance.html)にこの文があり、太字はキーです。

>**Only opaque objects cast and receive shadows so objects using the built-in Transparent or Particle shaders will neither cast nor receive. Generally, you can use the Transparent Cutout shaders instead for objects with “gaps” such as fences, vegetation, etc. Custom Shaders must be pixel-lit and use the Geometry render queue.**

>したがって、Render Queueを2500に調整する必要があります。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/72b9789c-a3d5-5e45-e480-5185e487cee2.png)
そうすると効果が出てきます：
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/b5731208-ab5f-d888-edb9-210b46ffe19c.png)

---
###Lightmap
Q2：ShadowMaskモードを使用してシーンをベイクし、LightcolorとShadowMaskを含む正しいLightmapを生成しました。その後、シーンのオブジェクトとライトマップなどの情報を自分の形式で保存して、ゲームが起動する時にシーン全体を再構築します。

ただし、Lightmapが正しく設定された後、SHADOWS_SHADOWMASKマクロは開かれず、Light ColorのSamplerのみがShaderに検出され、ShadowMaskのSamplerは検出されません。

1）どうすればSHADOWS_SHADOWMASKのkeywordを有効にさせられ、テクスチャをShaderに正しく入力できますか？（マテリアルで手動的にkeywordを開けません、入力されたテクスチャはデフォルトの白です。）

2）さらに、前にシーンオブジェクトは静的に設定されているため、ライトマップをベイクした後、シャドウを生成すること又は受け入れることはできませんが、Prefabから作成したオブジェクトはシャドウを生成して受け入れます。これはロードする後のみにRendererでこの二つのオプションを閉じられますか？ または、何か統一設定はありますか？
>一番目の問題に対して、問題主の説明から見ると、シーン全体を再構築する時に、当時に混合照明をベイクしているあのライトも一緒に再構築されましたか？もしそうなら、確かにShadowMaskは使用できなくなります。こちらのやり方は、シーンに混合光をベイクしているライトを保留することです。これでShadowMaskは有効になり、2つの間に特定の関係があります。シーンにあるオブジェクトはPrefabとして保存でき、ロードする後にLightmap Indexを手動で復元すれば良いです。ベイク用ライトはシーンに保留し、削除しないでください。

>二番目の問題に対して、問題主がPrefabからシーンに直接ドラッグされたオブジェクトは、LightmapIndexとUVデータを手動で復元する必要があります。そうしないと、手に入れたのはリアルタイムライトとシャドウであります。

---
###制作
Q3：私たちのゲームはアイドルマスターに似ていますが、モデルの透ける現象がより深刻です。成熟的な方案はありますか？ SpringBoneを試しましたが、効果が理想的ではありません。
>前にドレスアップゲームを制作しまして、モデルの透ける現象に対して、処理の良い競合製品を研究し、参照のために彼らの方法を説明します。
1）モデルのディザインでは、最初に各衣類のパーツの範囲を計画する必要があります。それて、プレーヤーが服を自由に選択する時に、服自身の透ける確率は低くなります。
2）同じ服の複数のモデルを作成し、必要な服のサイズに応じてそれらを交換します。ズボンを例にとると、スニーカーやサンダルなどの短い靴と組み合わせる場合は通常のモデルを使用します。長いブーツと組み合わせる場合は、ズボンの脚を短くし、底から一定の長さの範囲内の半径を小さくして、ブーツをパンツに巻き付ける効果をもたらします。

>上記は止まる時にモデルが透けることを防止する方法です。非常に役に立ちますが、アートディザインに制限が設置されたため、服の豊かさに影響があります。一般的なアクションに対して、DynamicBoneを使用し、パラメーターは慎重に調整したら、効果も良いです。
音楽とダンスのプロジェクトには大規模な動きがたくさんあり、DynamicBoneがどれほど効果的に達成できるかは明らかではありません。

---
###エディター
Q4：カスタムInspectorで複数のオブジェクトの位置プロパティを同時に変更するにはどうすればよいですか？ 複数のオブジェクトを選択する場合、Inspectorでこれらのオブジェクトの位置プロパティ（Xコンポーネントなど）を同時に変更する方法はありませんか？
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/eacd6d57-d77e-2657-6689-e6fbc2efb4a6.png)
カスタマイズエディタースクリプトで実現することを試しました、コードは下記のように：

```ruby:
using UnityEditor;
 using UnityEngine;
 using System.Collections;
 
 [CustomEditor(typeof(ChangePuzzlePosScript)), CanEditMultipleObjects]
 
 public class ChangePuzzlePosEditor : Editor {
 
     public override void OnInspectorGUI()
     {
         DrawDefaultInspector();
 
         ChangePuzzlePosScript script = (ChangePuzzlePosScript)target;
 
         if(GUILayout.Button("Change Position"))
         {
                script.ChangePosition();
         }
     }
 }
```
このスクリプトは次のスクリプトをコールします。

```ruby:
using UnityEngine;
 using System.Collections;
 
 public class ChangePuzzlePosScript : MonoBehaviour {
 
     public float posX = 9.6f;
     
     public void ChangePosition()
     {
         transform.position = new Vector3(transform.position.x + posX, transform.position.y, transform.position.y);
     }
 }
```
このスクリプトを複数のオブジェクトに掛けます。これらのオブジェクトを同時に選択し、Inspectorの位置変更をクリックすると、すべてのオブジェクトのXが変更されると予想されますが、実には1つのみのXが変更されるため、ここで何が問題ありますか？
>コードにtargetを使用しましたが、選択した複数のオブジェクトに対して、使うべきのはtargetsであります。この配列には、選択した複数のオブジェクトが格納されます。オブジェクトを1つだけ選択する場合は、targetを使って良いです。

>```ruby:
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if(GUILayout.Button("Change Position"))
{
foreach (var script in targets){
   if (script.GetComponent<ChangePuzzlePosScript>() != null) {
       script.ChangePosition();
   }
}
}
```

---
###エディター
Q5：Asset Serialization Modeでの異なるシリアル化方法は、実行時に異なりますか？「Binary」と「ForceText」はEdiotrでのみ異なりますか、それともビルドされたアプリに影響しますか？ つまり、さまざまな方法を選択すると、アプリのサイズと実行速度に影響しますか？
>「ForceText」は、Prefabs、Scenes、Meta Filesおよびその他のAssetファイルをYAMLテキスト形式で保存します。これにより、エディターで実行するとパフォーマンスが低下しますが、最大の利点は、Gitバージョン管理の衝突を処理できることです。そして、アプリを生成するとき、Unityはこれらのアセットを2値化します。「binary」と「forcetext」を別に使用してプロジェクトをビルドすると、生成されたAPPのサイズが同じであることがわかります。つまり、「forcetext」ファイルも構築過程中にバイナリに変換されます。

---
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、**パフォーマンス分析**と**最適化ソリューション**及び**コンサルティングサービス**を提供している会社でございます。

UWA公式サイト：https://jp.uwa4d.com
UWA公式ブログ：https://blog.jp.uwa4d.com