近期热门
粉丝49
关注 2
获赞 165
投射阴影,解决手游材质不支持阴影问题。面片阴影又。。

[U3D] 投射阴影,解决手游材质不支持阴影问题。面片阴影又。。

[复制链接]
3474 11 0 7 5年前 举报
本帖最后由 zsz98781 于 2018-11-9 08:41 编辑

{:6_220:},发一个 投射阴影脚本,解决手游材质不支持阴影问题。面片阴影又在斜坡地方穿帮,是不是很头痛呢?这个帮你解决问题!阴影的颜色,清晰度都可以调!如果不会,叫你们的程序大大来看看,根据公司具体情况稍微做修改!便可以使用。
找u3d工作 :QQ9888657, 翻下我的相关帖子,看的中的的带走。

1,需要建立一个场景烘培阴影的主光源方向的太阳光(主光),取消强度值,用来指定阴影方向。
2,创建一个灯光对场景人物补光,这个灯光上挂Projector_Shadow的脚本,
3, 如果想灯准确打到人物身上,请给人物一个box的碰撞体。
4,将脚本的maincamera指定到场景主摄像机
5,将脚本的sun mianlight指定到场景的太阳光(主光)。7,人物放到 EntityMainPlayer (公司项目设定的主角layer层内),在Projector_Shadow脚本里面修改这个对应的名字.
6,点击运行。

说明:本脚本可以自动匹配 投影光源的位置为太阳光到人物的线段之间的方向,
位置等于相机出发的射线撞击到地面的坐标,如果想定位到人身上,请给人物一个box的碰撞体。
阴影贴图的分辨率等于1080的两倍。
影子可以在阴影材质上调节模糊度和色彩及透明度。
另外还有投射阴影的光源的位置偏移和投射区域长度偏移。
只有在区域内的,EntityMainPlayer层的人物才能产生影子。
修复bug方法,在阳光和人物之间遮挡住人物的树木和房子,请给到SceneBuilding图层;


操作是复杂点,但是的确是切实可行的。我用这个脚本完成过好几个手游视频制作。但如果是游戏开发用,那估计得酬情对待。这样吧,分辨率设低点,叫程序帮忙改下关联,相机距离角色远,投射的那个灯就也距离远点,影子模糊点。近的话,也就近点,尺寸小点,影子清晰点。






手游投影插件Projector_Shadow.zip 已购买

113.1 KB 售价: 5 张CG券
下载
0
点赞
0
打赏
7
添加到收藏夹

0

点击复制链接

使用微信扫码分享
一次扣10个券
全部评论11
您需要登录后才可以回帖 登录 | 立即注册

6239657639 发表于 2018-11-21 11:05
我是指定到了这个角色上,但是运行后没有反应

有啥报错没?这个东西的使用,是要先设置些前提条件的。不然会报错
5年前
回复

使用道具 举报

有啥报错没?
5年前
回复

使用道具 举报

6239657639 发表于 2018-11-21 10:56
这么设置了 啥都没有,main player指定到哪里啊?

我是指定到了这个角色上,但是运行后没有反应
5年前
回复

使用道具 举报

本帖最后由 6239657639 于 2018-11-21 11:14 编辑
zsz98781 发表于 2018-11-8 12:31
大家在使用过程中应该会遇到些问题,但稍安勿躁,看报错,根据报错,再看说明,解决正确运行需要的条件。
...

TIM截图20181121105447.png TIM截图20181121105546.png

这么设置了 啥都没有,main player指定到哪里啊?

NullReferenceException: Object reference not set to an instance of an object
ShadowProjector.Start () (at Assets/Projector  Shadow/ShadowProjector.cs:71)

5年前
回复

使用道具 举报

好顶赞~下载学习一下
5年前
回复

使用道具 举报

虽然是老技术,但是支持一下,这也是手游能解决阴影的唯一解决方法。不过以前有点耗资源,所以也没放到项目里。现在手机性能上升了,也不知道会不会流畅一点
这个东西还可以用在特效上,一些地面特效可以根据地形来凹凸其平面
5年前
回复

使用道具 举报

本帖最后由 zsz98781 于 2018-11-8 13:01 编辑

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

// Upgrade NOTE: replaced '_Projector' with 'unity_Projector'

Shader "UnityEffects/ShadowProjector" {
        Properties {
                _ShadowTex ("ShadowTex", 2D) = "gray" {}
                _bulerWidth ("BulerWidth", float) = 1  //这里可以调节这个模糊强度。
                _shadowfactor ("Shadowfactor", Range(0,1)) = 0.5
                _ShadowMask ("ShadowMask",2D) = "white"{}
        }
        SubShader {
                Tags { "Queue"="AlphaTest+1" }
                Pass {
                        ZWrite Off
                        ColorMask RGB
                        Blend DstColor Zero
                        Offset -1, -1

                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        #include "UnityCG.cginc"

                        struct v2f {
                                float4 pos:POSITION;
                                float4 sproj:TEXCOORD0;
                        };

                        float4x4 unity_Projector;
                        sampler2D _ShadowTex;
                        sampler2D _ShadowMask;
                        uniform half4 _ShadowTex_TexelSize;
                        float _bulerWidth;
                        float _shadowfactor;

                        v2f vert(float4 vertex:POSITION){
                                v2f o;
                                o.pos = UnityObjectToClipPos(vertex);
                                o.sproj = mul(unity_Projector, vertex);
                                return o;
                        }

                        float4 frag(v2f i):COLOR{
                                
                                half4 shadowCol = tex2Dproj(_ShadowTex, UNITY_PROJ_COORD(i.sproj));
                                half maskCol = tex2Dproj(_ShadowMask, UNITY_PROJ_COORD(i.sproj)).r;
                                half a = (shadowCol * maskCol).a;
                                float4 uv4= UNITY_PROJ_COORD(i.sproj);
                                float2 uv = uv4.xy / uv4.w ;

                                //阴影模糊采样,想多精细就复制多几次。
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(1,0)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(0,1)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(-1,0)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(0,-1)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(2,0)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(0,2)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(-2,0)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(0,-2)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(3,0)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(0,3)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(-3,0)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(0,-3)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(4,0)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(0,4)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(-4,0)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(0,-4)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(5,0)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(0,5)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(-5,0)).a;
                                a += tex2D(_ShadowTex, uv + _ShadowTex_TexelSize.xy * _bulerWidth * float2(0,-5)).a;

                                a = a/5;
                                if(a > 0)
                                {
                                        return  float4(1,1,1,1) * (1 - _shadowfactor * a);
                                }
                                else
                                {
                                        return float4(1,1,1,1) ;
                                }
                        }

                        ENDCG
                }
        }
        FallBack "Diffuse"
}
5年前
回复

使用道具 举报

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "UnityEffects/ShadowMapUnlit"
{
        //RenderType 为ShadowMap 的无光照shader,为了展示RenderType 为ShadowMap 的物体才会被渲染到深度图
        Properties
        {
                _MainTex ("Texture", 2D) = "white" {}
        }
        SubShader
        {
                Tags { "RenderType"="ShadowMap" }
                LOD 100

                Pass
                {
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                       
                        #include "UnityCG.cginc"

                        struct appdata
                        {
                                float4 vertex : POSITION;
                                float2 uv : TEXCOORD0;
                        };

                        struct v2f
                        {
                                float2 uv : TEXCOORD0;
                                float4 vertex : SV_POSITION;
                        };

                        sampler2D _MainTex;
                        float4 _MainTex_ST;
                       
                        v2f vert (appdata v)
                        {
                                v2f o;
                                o.vertex = UnityObjectToClipPos(v.vertex);
                                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                                return o;
                        }
                       
                        fixed4 frag (v2f i) : SV_Target
                        {
                                fixed4 col = tex2D(_MainTex, i.uv);
                                return col;
                        }
                        ENDCG
                }
        }
        FallBack "Diffuse"
}
5年前
回复

使用道具 举报

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace Assets.Script.Utils
{
    public static class ShadowUtils
    {
        private static List<Vector4> _vList = new List<Vector4>();

        /// <summary>
        /// 根据主相机,设置光照相机
        /// </summary>
        /// <param name="mainCamera"></param>
        /// <param name="lightCamera"></param>
        public static void SetLightCamera(Camera mainCamera, Camera lightCamera)
        {
            //1、        求视锥8顶点 (主相机空间中) n平面(aspect * y, tan(r/2)* n,n)  f平面(aspect*y, tan(r/2) * f, f)
            float r = (mainCamera.fieldOfView / 180f) * Mathf.PI;
            //n平面
            Vector4 nLeftUp = new Vector4(-mainCamera.aspect * Mathf.Tan(r / 2) * mainCamera.nearClipPlane, Mathf.Tan(r / 2) * mainCamera.nearClipPlane, mainCamera.nearClipPlane, 1);
            Vector4 nRightUp = new Vector4(mainCamera.aspect * Mathf.Tan(r / 2) * mainCamera.nearClipPlane, Mathf.Tan(r / 2) * mainCamera.nearClipPlane, mainCamera.nearClipPlane, 1);
            Vector4 nLeftDonw = new Vector4(-mainCamera.aspect * Mathf.Tan(r / 2) * mainCamera.nearClipPlane, -Mathf.Tan(r / 2) * mainCamera.nearClipPlane, mainCamera.nearClipPlane, 1);
            Vector4 nRightDonw = new Vector4(mainCamera.aspect * Mathf.Tan(r / 2) * mainCamera.nearClipPlane, -Mathf.Tan(r / 2) * mainCamera.nearClipPlane, mainCamera.nearClipPlane, 1);

            //f平面
            Vector4 fLeftUp = new Vector4(-mainCamera.aspect * Mathf.Tan(r / 2) * mainCamera.farClipPlane, Mathf.Tan(r / 2) * mainCamera.farClipPlane, mainCamera.farClipPlane, 1);
            Vector4 fRightUp = new Vector4(mainCamera.aspect * Mathf.Tan(r / 2) * mainCamera.farClipPlane, Mathf.Tan(r / 2) * mainCamera.farClipPlane, mainCamera.farClipPlane, 1);
            Vector4 fLeftDonw = new Vector4(-mainCamera.aspect * Mathf.Tan(r / 2) * mainCamera.farClipPlane, -Mathf.Tan(r / 2) * mainCamera.farClipPlane, mainCamera.farClipPlane, 1);
            Vector4 fRightDonw = new Vector4(mainCamera.aspect * Mathf.Tan(r / 2) * mainCamera.farClipPlane, -Mathf.Tan(r / 2) * mainCamera.farClipPlane, mainCamera.farClipPlane, 1);

            //2、将8个顶点变换到世界空间

            Matrix4x4 mainv2w = mainCamera.transform.localToWorldMatrix;//本来这里的矩阵使用mainCamera.cameraToWorldMatrix,但是请看:http://docs.unity3d.com/ScriptRe ... aToWorldMatrix.html   cameraToWorldMatrix返回的是GL风格的camera空间的矩阵,z是负的,跟untiy编辑器中的不对应,(也是坑爹的很,就不能统一吗),所以我们直接使用localToWorldMatrix
            Vector4 wnLeftUp = mainv2w * nLeftUp;
            Vector4 wnRightUp = mainv2w * nRightUp;
            Vector4 wnLeftDonw = mainv2w * nLeftDonw;
            Vector4 wnRightDonw = mainv2w * nRightDonw;
            //
            Vector4 wfLeftUp = mainv2w * fLeftUp;
            Vector4 wfRightUp = mainv2w * fRightUp;
            Vector4 wfLeftDonw = mainv2w * fLeftDonw;
            Vector4 wfRightDonw = mainv2w * fRightDonw;

            //将灯光相机设置在mainCamera视锥中心
            Vector4 nCenter = (wnLeftUp + wnRightUp + wnLeftDonw + wnRightDonw) / 4f;
            Vector4 fCenter = (wfLeftUp + wfRightUp + wfLeftDonw + wfRightDonw) / 4f;

            lightCamera.transform.position = (nCenter + fCenter) / 2f;
            //3、        求光view矩阵
            Matrix4x4 lgihtw2v = lightCamera.transform.worldToLocalMatrix;//本来这里使用lightCamera.worldToCameraMatrix,但是同上面不使用mainCamera.cameraToWorldMatrix的原因一样,我们直接使用worldToLocalMatrix
            //4、        把顶点从世界空间变换到光view空间
            Vector4 vnLeftUp = lgihtw2v * wnLeftUp;
            Vector4 vnRightUp = lgihtw2v * wnRightUp;
            Vector4 vnLeftDonw = lgihtw2v * wnLeftDonw;
            Vector4 vnRightDonw = lgihtw2v * wnLeftDonw;
            //
            Vector4 vfLeftUp = lgihtw2v * wfLeftUp;
            Vector4 vfRightUp = lgihtw2v * wfRightUp;
            Vector4 vfLeftDonw = lgihtw2v * wfLeftDonw;
            Vector4 vfRightDonw = lgihtw2v * wfRightDonw;

            _vList.Clear();
            _vList.Add(vnLeftUp);
            _vList.Add(vnRightUp);
            _vList.Add(vnLeftDonw);
            _vList.Add(vnRightDonw);

            _vList.Add(vfLeftUp);
            _vList.Add(vfRightUp);
            _vList.Add(vfLeftDonw);
            _vList.Add(vfRightDonw);
            //5、        求包围盒 (由于光锥xy轴的对称性,这里求最大包围盒就好,不是严格意义的AABB)
            float maxX = -float.MaxValue;
            float maxY = -float.MaxValue;
            float maxZ = -float.MaxValue;
            float minZ = float.MaxValue;
            for (int i = 0; i < _vList.Count; i++)
            {
                Vector4 v = _vList;
                if (Mathf.Abs(v.x) > maxX)
                {
                    maxX = Mathf.Abs(v.x);
                }
                if (Mathf.Abs(v.y) > maxY)
                {
                    maxY = Mathf.Abs(v.y);
                }
                if (v.z > maxZ)
                {
                    maxZ = v.z;
                }
                else if (v.z < minZ)
                {
                    minZ = v.z;
                }
            }
            //5.5 优化,如果8个顶点在光锥view空间中的z<0,那么如果n=0,就可能出现应该被渲染depthmap的物体被光锥近裁面剪裁掉的情况,所以z < 0 的情况下要延光照负方向移动光源位置以避免这种情况
            if (minZ < 0)
            {
                lightCamera.transform.position += -lightCamera.transform.forward.normalized * Mathf.Abs(minZ);
                maxZ = maxZ - minZ;
            }

            //6、        根据包围盒确定投影矩阵 包围盒的最大z就是f,Camera.orthographicSize由y max决定 ,还要设置Camera.aspect
            lightCamera.orthographic = true;
            lightCamera.aspect = maxX / maxY;
            lightCamera.orthographicSize = maxY;
            lightCamera.nearClipPlane = 0.0f;
            lightCamera.farClipPlane = Mathf.Abs(maxZ);
        }
        /// <summary>
        /// 根据场景包围盒来设置光锥
        /// </summary>
        /// <param name="b"></param>
        /// <param name="lightCamera"></param>
        public static void SetLightCamera(Bounds b, Camera lightCamera)
        {
            //1、将lightCamera放在包围盒中心
           //lightCamera.transform.position = b.center;
            //2、        求光view矩阵
            Matrix4x4 lgihtw2v = lightCamera.transform.worldToLocalMatrix;//本来这里使用lightCamera.worldToCameraMatrix,但是同上面不使用mainCamera.cameraToWorldMatrix的原因一样,我们直接使用worldToLocalMatrix
            //3、        把顶点从世界空间变换到光view空间
            Vector4 vnLeftUp = lgihtw2v * new Vector3(b.max.x, b.max.y, b.max.z);
            Vector4 vnRightUp = lgihtw2v * new Vector3(b.max.x, b.min.y, b.max.z);
            Vector4 vnLeftDonw = lgihtw2v * new Vector3(b.max.x, b.max.y, b.min.z);
            Vector4 vnRightDonw = lgihtw2v * new Vector3(b.min.x, b.max.y, b.max.z);
            //
            Vector4 vfLeftUp = lgihtw2v * new Vector3(b.min.x, b.min.y, b.min.z); ;
            Vector4 vfRightUp = lgihtw2v * new Vector3(b.min.x, b.max.y, b.min.z); ;
            Vector4 vfLeftDonw = lgihtw2v * new Vector3(b.min.x, b.min.y, b.max.z); ;
            Vector4 vfRightDonw = lgihtw2v * new Vector3(b.max.x, b.min.y, b.min.z); ;

            _vList.Clear();
            _vList.Add(vnLeftUp);
            _vList.Add(vnRightUp);
            _vList.Add(vnLeftDonw);
            _vList.Add(vnRightDonw);

            _vList.Add(vfLeftUp);
            _vList.Add(vfRightUp);
            _vList.Add(vfLeftDonw);
            _vList.Add(vfRightDonw);
            //4、        求包围盒 (由于光锥xy轴的对称性,这里求最大包围盒就好,不是严格意义的AABB)
            float maxX = -float.MaxValue;
            float maxY = -float.MaxValue;
            float maxZ = -float.MaxValue;
            float minZ = float.MaxValue;
            for (int i = 0; i < _vList.Count; i++)
            {
                Vector4 v = _vList;
                if (Mathf.Abs(v.x) > maxX)
                {
                    maxX = Mathf.Abs(v.x);
                }
                if (Mathf.Abs(v.y) > maxY)
                {
                    maxY = Mathf.Abs(v.y);
                }
                if (v.z > maxZ)
                {
                    maxZ = v.z;
                }
                else if (v.z < minZ)
                {
                    minZ = v.z;
                }
            }
            //4.5 优化,如果8个顶点在光锥view空间中的z<0,那么如果n=0,就可能出现应该被渲染depthmap的物体被光锥近裁面剪裁掉的情况,所以z < 0 的情况下要延光照负方向移动光源位置以避免这种情况
            if (minZ < 0)
            {
               // lightCamera.transform.position += -lightCamera.transform.forward.normalized * Mathf.Abs(minZ);
                maxZ = maxZ - minZ;
            }

            //5、        根据包围盒确定投影矩阵 包围盒的最大z就是f,Camera.orthographicSize由y max决定 ,还要设置Camera.aspect
            lightCamera.orthographic = true;
            //lightCamera.aspect = maxX / maxY;
            //lightCamera.orthographicSize = maxY;
            lightCamera.nearClipPlane = 0.0f;
           // lightCamera.farClipPlane = Mathf.Abs(maxZ);
        }

    }
}
5年前
回复

使用道具 举报