首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于材质球中渲染光照一些理解

关于材质球中渲染光照一些理解

作者头像
孙寅
发布2020-06-02 14:44:04
6970
发布2020-06-02 14:44:04
举报
文章被收录于专栏:宜达数字宜达数字宜达数字

材质球

Specular Highlights:镜面光 Reflection: 遮罩反射 一个Cubemap 一个texture来描述我们对象的那些部分是可以反射的,而哪些不可以。记住,黑色表示没有任何反射性,而白色表示可以完全反射。下面的图片是我们将会用到的texture

Shader "Custom/MaskedReflection" {  
    Properties {  
        _MainTex ("Base (RGB)", 2D) = "white" {}  
        _MainTint ("Diffuse Tint", Color) = (1,1,1,1)  
        _ReflAmount ("Reflection Amount", Range(0, 1)) = 1  
        _Cubemap ("Cubemap", CUBE) = ""{}  
        _ReflMask ("Reflection Mask", 2D) = ""{}  
    }  
    SubShader {  
        Tags { "RenderType"="Opaque" }  
        LOD 200  
          
        CGPROGRAM  
        #pragma surface surf Lambert  
  
        sampler2D _MainTex;  
        sampler2D _ReflMask;  
        samplerCUBE _Cubemap;  
        float4 _MainTint;  
        float _ReflAmount;  
  
        struct Input {  
            float2 uv_MainTex;  
            float3 worldRefl;  
        };  
  
        void surf (Input IN, inout SurfaceOutput o) {  
            half4 c = tex2D (_MainTex, IN.uv_MainTex);  
            float3 reflection = texCUBE(_Cubemap, IN.worldRefl).rgb;  
            float4 reflMask = tex2D(_ReflMask, IN.uv_MainTex);  
      
            o.Albedo = c.rgb * _MainTint;  
            o.Emission = (reflection * reflMask.r) * _ReflAmount;  
            o.Alpha = c.a;  
        }  
        ENDCG  
    }   
    FallBack "Diffuse"  
}  
Shader "Custom/AlphaMask" {  
       Properties  
        {  
        _Color ("Main Color", Color) = (1,1,1,1)  
        _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}  
        _MaskTex ("Mask (A)", 2D) = "white" {}  
        _Progress ("Progress", Range(0,1)) = 0.5  
        }  
        Category  
        {  
            Lighting Off  
            ZWrite Off  
            Cull back  
            Fog { Mode Off }  
            Tags {"Queue"="Transparent" "IgnoreProjector"="True"}  
            Blend SrcAlpha OneMinusSrcAlpha  
            SubShader  
            {  
                Pass  
                {  
                    CGPROGRAM  
                    #pragma vertex vert  
                    #pragma fragment frag  
                    sampler2D _MainTex;  
                    sampler2D _MaskTex;  
                    fixed4 _Color;  
                    float _Progress;  
                    struct appdata  
                    {  
                        float4 vertex : POSITION;  
                        float4 texcoord : TEXCOORD0;  
                    };  
                    struct v2f  
                    {  
                        float4 pos : SV_POSITION;  
                        float2 uv : TEXCOORD0;  
                    };  
                    v2f vert (appdata v)  
                    {  
                        v2f o;  
                        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
                        o.uv = v.texcoord.xy;  
                        return o;  
                }  
                    half4 frag(v2f i) : COLOR  
                    {  
                        fixed4 c = _Color * tex2D(_MainTex, i.uv);  
                        fixed ca = tex2D(_MaskTex, i.uv).a;  
                        c.a *= ca >= _Progress ? 0f : 1f;  
                        return c;  
                    }  
                    ENDCG  
                }  
            }  
            SubShader  
            {            
                 AlphaTest LEqual [_Progress]    
                  Pass    
                  {    
                     SetTexture [_MaskTex] {combine texture}    
                     SetTexture [_MainTex] {combine texture, previous}    
                  }    
            }  
              
        }  
        Fallback "Transparent/VertexLit"  
    }  
Forward Rendering

Forward Rendering是绝大数引擎都含有的一种渲染方式。要使用Forward Rendering,一般在Vertex Shader或Fragment Shader阶段对每个顶点或每个像素进行光照计算,并且是对每个光源进行计算产生最终结果。正向渲染一个基于着色器的渲染路径。在Unity中它支持逐像素计算光照(包括法线贴图和灯光Cookies)和来自一个平行光的实时阴影。在默认设置中,少数最亮的灯光在逐像素计算光照模式下渲染。其余的灯光计算对象顶点的光照。 下面是Forward Rendering的核心伪代码。

For each light:
  For each object affected by the light:
    framebuffer += object * light

在Unity3D 引擎中,对于下图中的圆圈(表示一个Geometry),进行Forward Rendering处理。

将得到下面的处理结果

也就是说,对于ABCD四个光源我们在Fragment Shader中我们对每个pixel处理光照,对于DEFG光源我们在Vertex Shader中对每个vertex处理光照,而对于GH光源,我们采用球调和(SH)函数进行处理。 Forward Rendering优缺点

很明显,对于Forward Rendering,光源数量对计算复杂度影响巨大,所以比较适合户外这种光源较少的场景(一般只有太阳光)。

但是对于多光源,我们使用Forward Rendering的效率会极其低下。因为如果在vertex shader中计算光照,其复杂度将是 ,而如果在fragment shader中计算光照,其复杂度为 。可见光源数目和复杂度是成线性增长的。

对此,我们需要进行必要的优化。比如

  • 1.多在vertex shader中进行光照处理,因为有一个几何体有10000个顶点,那么对于n个光源,至少要在vertex shader中计算10000n次。而对于在fragment shader中进行处理,这种消耗会更多,因为对于一个普通的1024x768屏幕,将近有8百万的像素要处理。所以如果顶点数小于像素个数的话,尽量在vertex shader中进行光照。
  • 2.如果要在fragment shader中处理光照,我们大可不必对每个光源进行计算时,把所有像素都对该光源进行处理一次。因为每个光源都有其自己的作用区域。比如点光源的作用区域是一个球体,而平行光的作用区域就是整个空间了。对于不在此光照作用区域的像素就不进行处理。但是这样做的话,CPU端的负担将加重,因为要计算作用区域。
  • 3.对于某个几何体,光源对其作用的程度是不同,所以有些作用程度特别小的光源可以不进行考虑。典型的例子就是Unity中只考虑重要程度最大的4个光源。

自发光

Global Illumination 全局光照设置

  • 自发光效果 很多人都会奇怪,为什么我选了自发光的颜色,强度也调整的很大,为什么出不来效果呢,其实可能是少了一步操作。 首先我们需要先把这个自发光物体,选中LightMap静态,然后再把周围物体也都选中LightMap静态,再进行烘焙即可。很简单的,但遗了一步就会没有任何效果。
  • 镜面 在模拟一个diffuse surface时,使用的是光滑,无光泽的object。这种方法,对于场景中的大部分objects都是合适的,而且很多光照模型都基于此种方法。但是,有时也要模拟闪光的模型表面,比如抛光的金属或者大理石地板的表面。Specular highlights就是用于模拟这些带有光泽的object表面。 有两种方法可以模拟镜面反射。第一种是Phong反射模型中的镜面反射部分,Phong模型以它的发明者,来自Utah大学的Bui Tuong Phong命名。与diffuse shading不同的是,镜面光与观察者(即camera)相对于表面的位置有关。只要看向一个发光的object,就自己观察到这一点,注意观察从不同的方向看向object时,该object的光泽如何改变。Phong模型指出,镜面光由观察方向和光的反射向量之间的夹角确定。公式为:

其中,R为反射向量,V表示观察方向,s表示亮点(照亮的区域)的大小。Specular exponent(镜面指数)越大,产生的亮点越小。反射向量可以使用如下的公式计算:

R = 2*(N • L)*N-L
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Forward Rendering
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档