半透明物体如何实现阴影效果?

半透明物体如何实现阴影效果?

本期聚集话题:半透明物体接受阴影的方法、手动设置Lightmap成功但Shadowmask丢失的解放方法、在自定义Inspector中同时修改多个物体的位置属性...


这是第123篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)


渲染

Q1:当"RenderType" = "Transparent"的时候貌似是没有办法接受阴影的。我们需要在场景中做一层半透的地表, 来掩盖模型和地表之间的接缝,所以需要显示阴影, 请教各位大佬有什么好的方法吗?另外我想了解下为什么半透明物件默认不能接受阴影呢?

抛开Unity引擎,从本质上说,半透物体肯定是可以接受阴影的。之前就实现过地表有一块玻璃材质,会在玻璃上以及下面的物体上都有投射的阴影效果。所以如果自己编写的Shader,想要接受阴影,只需要采样Shadowmap,走一下阴影计算的过程就可以了。
对于Unity引擎,我试了一下的确选择Transparent的RenderType也就没有了阴影,这个我不是非常清楚是否可以自己在Shader中去强制走一下Shadowmap的处理过程来解决,题主可以试下。
但是题主要注意,半透物体接受阴影的情况下,尤其是题主要解决的这种覆盖接缝的情况,会导致这部分最后产生的阴影变得比较重的效果,因为半透下面的物体肯定还会有阴影产生,半透的阴影虽然可以受Alpha的影响变淡,但是叠加在一起就会出现变得更暗的问题。当然Transparent的部分不接受阴影,意味着阴影效果经过Alpha Blend之后会变得淡。

感谢贾伟昊@UWA问答社区提供了回答。

这个问题恰好之前做了些尝试,正如@贾伟昊所说,内置的Transparent是不接受阴影的,但可以尝试在自定义shader中强制走Shadowmap的。参考代码如下:

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
        }
    }
}

但直接用这个Shader也还是没有效果…
因为文档里有句话,重点是粗体:

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:
请输入图片描述
然后效果就出来了:
请输入图片描述
该问题来自UWA问答社区,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5b67b9851e88b37d34e651da


Lightmap

Q2:我使用ShadowMask模式烘焙好了场景,生成了正确的Lightmap,其中包含Lightcolor和ShadowMask。之后将场景的物体和光照图等信息用自己的格式存储,启动游戏时再重建整个场景。

但是Lightmap正确设置之后,SHADOWS_SHADOWMASK宏没有被打开,Shader中只找到了Light Color 的Sampler,并没有找到ShadowMask的Sampler。

1)如何设置才能开启SHADOWS_SHADOWMASK的keyword,并正确地将贴图传入Shader(不能手动在材质上打开keyword,传入的贴图是默认的白色)?

2)另外之前因为场景物体设置成了静态,烘焙了光照图后不产生和接受阴影,但是自己从Prefab中创建出来的物体就会产生和接受阴影,是只能加载后将Renderer上的这两个选项关闭么?还是有什么统一设置?

第一个问题,从题主的描述上来看,你们重建整个场景,是否连同当时烘焙混合光照的那盏灯光也是重建出来的?如果是,确实会导致ShadowMask无法使用,我这边的做法是保留场景中用来烘焙混合光的那盏光源,这样ShadowMask才会起作用,两者有某种关系。场景中的物件可以保存为Prefab,加载后手动恢复以下Lightmap Index即可,烘焙光源留在场景中别删。

第二个问题,题主从Prefab直接拖进场景中的物件,需要手动恢复LightmapIndex和UV数据,否则得到的是实时光照和阴影。

感谢Lujian@UWA问答社区提供回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5b63ec54339d267d357c6cb8


制作

Q3:我们游戏类似偶像大师,但是穿模比较严重,有什么成熟的方案吗?尝试了SpringBone,但是效果不理想。

之前做过换装游戏,研究过防穿帮做的比较好的竞品,说下他们的做法供参考。
1)模型设计上,首先要规划好每个服饰部位的范围,这样玩家自由搭配的时候,服饰本身穿帮的概率就降低了;
2)同一件服饰做多套模型,根据搭配服饰的size进行替换。以长裤为例:搭配运动鞋、凉鞋等短鞋时,使用正常模型;搭配长筒靴时,裤腿缩短,并且底部一定长度内的半径缩小,产生长靴包在裤子外面的效果。
上面是针对静止时穿帮的解决方法,效果是非常棒的,不过由于在美术设计上做了限制,服饰的丰富度会受到影响。对于一般性的动作,我们是使用了DynamicBone,参数仔细调的话效果也不错。
音舞项目很多大幅度的动作,DynamicBone能起到多大效果就不清楚了。

感谢Walker@UWA问答社区提供回答,欢迎大家转至社区进一步交流:
https://answer.uwa4d.com/question/5b614dc81e88b37d34e651c3


编辑器

Q4:如何在自定义Inspector中同时修改多个物体的位置属性?当我选定多个物体时,如何在Inspector中同时修改这些物体的位置属性,例如x分量:
请输入图片描述
我尝试自定义Editor脚本来实现,脚本如下:

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();
         }
     }
 }

该脚本会调用以下脚本:

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都会发生变化,但实际只有一个物体的x发生了变化,所以这里会有什么问题吗?

代码里使用了target,而对于选定的多个物体,应当使用 targets ,该数组保存了选定的多个物体,如果只选择一个物体时,则应当使用target。

public override void OnInspectorGUI()
{
DrawDefaultInspector();

if(GUILayout.Button("Change Position"))
{
foreach (var script in targets){
   if (script.GetComponent<ChangePuzzlePosScript>() != null) {
       script.ChangePosition();
   }
}
}

该回答由UWA提供,欢迎大家转至社区进一步交流:
https://answer.uwa4d.com/question/5b67a2da1e88b37d34e651d7


编辑器

Q5:Asset Serialization Mode中不同的序列化方式在运行时会有区别吗?“Binary”和“Force Text”是只会在Ediotr中有所不同,还是会影响到构建后的APP?或者说,选择不同的方式是否对APP的大小以及运行时的速度造成影响呢?

“Force Text”将Prefabs、scenes、meta files以及其他Asset文件用YAML的文本格式存储,这样虽然会在Editor中运行造成一定性能的损失,但其有一个最大的好处是,能够处理Git这类版本管理中的冲突。而在生成APP时,Unity会将这些资源都进行二进制化。分别使用“binary”和“force text”对项目进行构建会发现,生成的APP的大小是一样的,也就是说,构建过程中”force text”的文件也会转为二进制。

该回答由UWA提供,欢迎大家转至社区进一步交流:
https://answer.uwa4d.com/question/5b614dc81e88b37d34e651c3

今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
官方技术QQ群:793972859(原群已满员)