表面着色器笔记

原创 2017年10月12日 21:07:34

第二章 表面着色器和纹理映射

2.1-2.3 部分:

  1. 材质的物理属性在表面函数中进行初始化,存储在“表面输出”的结构内,表面输出(surface output)被传递给光照模型,同时根据光照信息计算出模型上每一个像素最终的颜色。

  2. unity内三种主要的表面输出结构:

    1. SurfaceOutPut
      • fixed3 Albedo 表示材质的漫反射颜色
      • fixed3 Normal 表示切面法线
      • fixed3 Emission 表示材质发射的颜色
      • fixed Alpha 表示材质的透明度
      • half Specular 表示光亮度(0,1)
      • fixed Gloss 表示光强度
    2. SurfaceOutputStandard
      • fixed Albedo 表示材质的基础颜色
      • fixed3 Normal
      • half3 Emission
      • fixed Alpha
      • half Occlusion 表示遮挡,默认为1
      • half Smoothness 表示光滑度,0表示粗糙,1表示光滑
      • half Metallic 0表示非金属,1表示金属
    3. SurfaceOutputStandardSpecular
      • fixed3 Albedo
      • fixed3 Normal
      • half3 Emission
      • fixed Alpha
      • half Occlusion
      • half Smoothness
      • fixed3 Specular 表示高光颜色,可以指定一种颜色而非单一值
  3. Cg中两种类型的变量:单一值变量包装数组。包装数组类似于结构体,一个数组包含数个单一值。
  4. Cg语言内的几种特性

    1. 调和(swizzling)
      o.Albedo=_Color.rgb;
      在本例中,作为fixed3类型的Albedo同时被rgb三个元素所赋值。同时Cg支持对元素重新排序,如_Color.bgr会将红色成分和蓝色成分进行对调。
    2. 涂抹(smearing)
      o.Albedo=0;//Black=(0,0,0);
      将单一值赋给包装数组,单一值将会填充数组的每一元素。
    3. 遮罩(masking)
      o.Albedo.rg=_Color.rg;
      调和用在表达式的左边,以重写包装数组的部分元素。
  5. 包装矩阵: float4*4表示float类型的4行4列的矩阵。通过_mRC标注访问矩阵R行C列的元素。

2-4:给着色器添加纹理

  1. 三维模型由三角形组成,三角形的每一个顶点存储着着色器可以访问的数据。
  2. uv数据:由uv两个坐标组成,取值范围(0,1),表示了++二维图像中像素映射到顶点时的xy坐标++,只是给顶点使用。
    uv数据保存在三维模型中,用建模软件才可编辑。
  3. 工作原理:

    _MainTex("Albedo(RGB)",2D)="White"{}
            //实际引用纹理的代码
        sampler2D _MainTex
            //将纹理定义为二维纹理的标准类型
        struct Input{
            float2 uv_MainTex;
        };
            //输入参数,包含三维模型需要渲染的某个特殊点的MainTex的uv值。
            fixed4 c=tex2D(_MainTex,In.uv_MainTex)*_Color;
            //用来对纹理进行采样,tex2D返回颜色值(包装数组)。```
    
  4. Filter(过滤)模式:
    • 双线性过滤(Bilinear):廉价有效的平滑纹理方式
    • 点过滤(Point):对于二维游戏,双线性插值可能会产生模糊,用点过滤来移除纹理采样过程中的插值。
  5. Aniso Level:用于减少纹理采样瑕疵。

2-5 通过修改uv值来滑动纹理

  1. 代码

    Shader "Custom/flowShader" {
        Properties {
            _MainTint("Diffuse Tint",Color)=(1,1,1,1)
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
            _ScrollXSpeed("X Scroll Speed",Range(0,10))=2
        _ScrollYSpeed("Y Scroll Speed",Range(0,10))=2
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
    
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows
    
        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0
    
        sampler2D _MainTex;
        fixed4 _MainTint;
        fixed _ScrollXSpeed;
        fixed _ScrollYSpeed;
    
        struct Input {
            float2 uv_MainTex;
        };
    
        half _Glossiness;
        half _Metallic;
        fixed4 _Color;
    
        void surf (Input IN, inout SurfaceOutputStandard o) {
            fixed2 scrolledUV=IN.uv_MainTex;
    
            fixed xScrollValue=_ScrollXSpeed*_Time;
            fixed yScrollValue=_ScrollYSpeed*_Time;
    
            scrolledUV+=fixed2(xScrollValue,yScrollValue);
    
            half4 c=tex2D(_MainTex,scrolledUV);
            o.Albedo=c.rgb*_MainTint;
            o.Alpha=c.a;
            }
        ENDCG
        }
        FallBack "Diffuse"
    }
    
  2. 工作原理

    1. 开始时先将UV值保存在scrolledUV的变量中,该变量为float2或fixed2类型。
    2. 用滑动速度变量和內建的递归时间变量_Time来对纹理进行偏移。_Time变量随着时间的推移返回一个递增的浮点数值。 关于递归时间的完整描述:https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
    3. 计算了不同时刻的偏移之后,将新计算出来的偏移量添加到原始的UV位置(+=运算符的目的),然后将新的UV值作为参数传给tex2D()作为纹理的新UV值。
    4. 实际上是通过操作UV值造成一种纹理在移动的假象。

2-6法线映射

  1. 每一个三维物体都是由三角形的面组成的,每一个三角形都有着其朝向,由三角形中心的法线方向决定,该++中心点++法线决定整个面的朝向。当相隔很近但朝向不同的三角形反射光时,由于朝向不同,着色方向会大不一样,对于弧形表面效果很差。
  2. 因此引入法线方向的概念,在处理弧形表面的光照效果时,使用其法线方向。 在顶点存储的数据中,法线方向是仅次于UV值的一个非常重要的参数。 法线方向是一个单位向量,表示顶点面朝的方向,然而,与面朝方向不同,三角形中的每一个点都有着其独有的法线方向(一个刺猬(基于顶点法线方向线性插值)。
  3. 作用:用一些低精度模型制作高精度的几何体。
  4. 法线映射(bump):通常用一些RGB图像来存贮法线方向(R,G,B)->(X,Y,Z)。unity内使用UnpackNormals()向表面着色器添加法线映射。
  5. 代码
/*null*/

2-7创建透明材质

  1. 在渲染实心物体之前,Unity按照各个物体距离镜头的距离(z排序)对它们进行排列,然后跳过所有没有朝着镜头的三角形(剔除)。
  2. 代码:

    Shader "Custom/Transparent" {
        Properties {
            _Color ("Color", Color) = (1,1,1,1)
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
            _Glossiness ("Smoothness", Range(0,1)) = 0.5
            _Metallic ("Metallic", Range(0,1)) = 0.0
        }
    SubShader {
        Tags {  "Queue"="Transparent"//通道混合的对象(不写入深度缓存的shader)使用该队列,例如玻璃和粒子。
        "IgnoreProjector"="True"//确保该物体不受Unity的投影影响
        "RenderType"="Transparent"//着色器置换
        }
        LOD 200
        Cull Back//
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard alpha:fade
    
        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0
        sampler2D _MainTex;
    
        struct Input {
            float2 uv_MainTex;
    };
        fixed4 _Color;
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_CBUFFER_START(Props)
        // put more per-instance properties here
        UNITY_INSTANCING_CBUFFER_END
    
        void surf (Input IN, inout SurfaceOutputStandard o) {
            float4 c=tex2D(_MainTex,IN.uv_MainTex)*_Color;
            o.Albedo=c.rgb;
            o.Alpha=c.a;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }
    
  3. 一些参数

    1. Tags参数详解:https://docs.unity3d.com/Manual/SL-SubShaderTags.html
    2. Unity提供了默认的 渲染序列(Queue):

      渲染队列 渲染队列描述 渲染队列值
      Background 这个队列被最先渲染。它被用于skyboxes等。 1000
      Geometry 这是默认的渲染队列。它被用于绝大多数对象。不透明几何体使用该队列。 2000
      AlphaTest 通道检查的几何体使用该队列。它和Geometry队列不同,对于在所有立体物体绘制后渲染的通道检查的对象,它更有效。 2450
      Transparent 该渲染队列在Geometry和AlphaTest队列后被渲染。任何通道混合的(也就是说,那些不写入深度缓存的Shaders)对象使用该队列,例如玻璃和粒子效果。 3000
      Overlay 该渲染队列是为覆盖物效果服务的。任何最后被渲染的对象使用该队列,例如镜头光晕。 4000
    3. 事实上透明序列会在几何序列后被渲染,详情搜索:ZBuffing
    4. alpha:fade 这种材质上的每一个像素需要与屏幕上之前的颜色根据其alpha值进行混色。

2-8创建全息着色器

  1. 简介:一种适合于创造未来科技感的着色技术。可以通过噪声,动画扫描线,以及震动来创造特效。
  2. 代码:

    Shader "Custom/Silhouette" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
            //用_DotProduct来判断点积多么接近于0时才将三角形视为轮廓。
        _DotProduct("Rim effect",Range(-1,1))=0.25
    }
    SubShader {
        Tags { "RenderType"="Transparent"
                "Queue"="Transparent"
                "IgnoreProtector"="True"
        }
        LOD 200
        CGPROGRAM
    
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Lambert alpha:fade nolighting
        //朗伯(Lambertian reflectance)反射,廉价光照模型,nolighting用来禁止光照
        sampler2D _MainTex;
    
        struct Input {
            float2 uv_MainTex;
            float3 worldNormal;
            float3 viewDir;
        };
    
        fixed4 _Color;
        float _DotProduct;
    
        void surf (Input IN, inout SurfaceOutput o) {
            // Albedo comes from a texture tinted by color
            float4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            float border=1-(abs(dot(IN.viewDir,IN.worldNormal)));
            //点积,判断两个向量是否正交(点积为0),根据几何将法线与视线点积为0的三角形视为轮廓
            float alpha=(border*(1-_DotProduct)+_DotProduct);
            //线性插值,模型的边与_DotProduct之间的渐变褪色,由线性插值完成
            o.Alpha = c.a*alpha;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }
    

2-9 打包和混合纹理

  1. 纹理的作用
    • 存储像素颜色数据
    • 存储x,y方向的像素集合,RGBA通道
    • 将图像打包成一个RGBA纹理,再提取单独的组件作为单独的纹理(节省空间)
    • 将数种纹理混合涂在一个表面上(地形等)
  2. 代码:

    Shader "Custom/battleGround" {
    Properties {
        _MainTint("Diffuse Tint",Color)=(1,1,1,1)
        _ColorA("Terrain Color A",Color)=(1,1,1,1)
        _ColorB("Terrain Color B",Color)=(1,1,1,1)
        _RTexture("Red Channel Texture",2D)=""{}
        _GTexture("Green Channel Texture",2D)=""{}
        _BTexture("Blue Channel Texture",2D)=""{}
        _ATexture("Alpha Channel Texture",2D)=""{}
        _BlendTex("Blend Texture",2D)=""{}
    }
    
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Lambert
        #pragma target 4.0
        float4 _MainTint;
        float4 _ColorA;
        float4 _ColorB;
        sampler2D _RTexture;
        sampler2D _GTexture;
        sampler2D _BTexture;
        sampler2D _ATexture;
        sampler2D _BlendTex;
    
        struct Input {
            float2 uv_RTexture;
            float2 uv_GTexture;
            float2 uv_BTexture;
            float2 uv_Atexture;
            float2 uv_BlendTex;
    };
    
        void surf (Input IN, inout SurfaceOutput o) {
            float4 blendData=tex2D(_BlendTex,IN.uv_BlendTex);
            float4 rTexData=tex2D(_RTexture,IN.uv_RTexture);
            float4 gTexData=tex2D(_GTexture,IN.uv_GTexture);
            float4 bTexData=tex2D(_BTexture,IN.uv_BTexture);
            float4 aTexData=tex2D(_ATexture,IN.uv_Atexture);
            float4 finalColor;
    
        finalColor=lerp(rTexData,gTexData,blendData.g);//r=g
        finalColor=lerp(finalColor,bTexData,blendData.b);//g=b
                                                                        finalColor=lerp(finalColor,aTexData,blendData.a);//b=a
            finalColor.a=1.0;
    
            float4 terrainLayers=lerp(_ColorA,_ColorB,blendData.r);
            finalColor *= terrainLayers;
            finalColor =saturate(finalColor);
    
            o.Albedo=finalColor.rgb * _MainTint.rgb;
            o.Alpha=finalColor.a;
        }
        ENDCG
        }
    FallBack "Diffuse"
    }
    
  3. 工作原理:
    混合纹理通过內建的lerp()函数,将第一个参数和第二个参数按照第三个参数指定的比例进行混合。
    该着色器取纹理的不同纹理进行混合。

2-10 在地形周围创建圆环

  1. 这个案例展示了用着色器画一个圆环,++这个着色器附在的材质将赋给所要画的地形,而不是跟随的物体++。
  2. 代码:
Shader "Custom/RadiusShader" {
    Properties {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Center("Center",Vector)=(0,0,0,0)//圆心
        _Radius("Radius",Float)=0.5//半径
        _RadiusColor("Radius color",Color)=(1,0,0,1)
        _RadiusWidth("Radius Width",Float)=2
    }

    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        float3 _Center;
        float _Radius;
        fixed4 _RadiusColor;
        float _RadiusWidth;
        sampler2D _MainTex;
        struct Input {
            float2 uv_MainTex;
            float3 worldPos;//请求当前绘制的像素在世界坐标中的位置
        };

        void surf (Input IN, inout SurfaceOutputStandard o) {
            float d=distance(_Center,IN.worldPos);
            //绘制部分,如果在圆环内采用选定颜色,不在的话使用纹理采样的颜色
            if(d>_Radius&&d<_Radius+ _RadiusWidth)
                o.Albedo=_RadiusColor;
            else
                o.Albedo=tex2D(_MainTex,IN.uv_MainTex).rgb;
        }
        ENDCG
    }
    FallBack "Diffuse"
}
//跟随角色的代码,在Update里根据自身position设置在地图绘画的圆心位置。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Radius : MonoBehaviour {

    public Material radiusMaterial;
    public float radius = 1;
    public Color color = Color.white;
    // Update is called once per frame
    void Update () {
        radiusMaterial.SetVector("_Center", transform.position);
        radiusMaterial.SetFloat("_Radius", radius);
        radiusMaterial.SetColor("_RadiusColor", color);
    }
}

Unity Shader 学习笔记(29) 表面着色器(Surface Shader)

Unity Shader 学习笔记(29) 表面着色器(Surface Shader)基本结构 参考书籍:《Unity Shader 入门精要》 官网API:Writing Surface ...

Unity3d 表面着色器学习笔记

一. Unity中三种着色器书写格式 surface shaders 表面着色器 vertex and fragment shaders and 顶点和片段着色器 fixed function sha...

【Unity Shaders】学习笔记之表面着色器(三)

一、表面着色器    1.1 简介   表面着色器代码直接在SubShader中编写,不需要使用Pass,编译器会将代码编译到合适的Pass中    1.2 标签    硬件将通过判...

Unity Shader入门精要学习笔记 - 第17章 Unity的表面着色器探秘

2010年的Unity 3 中,Surface Shader 出现了。 表面着色器的一个例子。 我们先做如下准备工作。 1)新建一个场景,去掉天空盒子 2)新建一个材质,新建一个Shader,赋给材质...

【Unity Shader学习笔记】(一)在表面着色器中控制顶点变换

通常境况下,我们可以方便地使用表面着色器对材质进行简单的金属光泽、平滑度等设置。但是如果要想对顶点进行控制,就需要使用顶点片段着色器。然而,在顶点片段着色器中,连最基本的漫反射、高光等都需要手动去写,...
  • zzlyw
  • zzlyw
  • 2016年12月18日 09:40
  • 1793

Cg语言与表面着色器编程

  • 2015年05月26日 14:41
  • 4KB
  • 下载

【Unity3D Shader编程】之七 静谧之秋篇: 表面着色器的写法(二)—— 自定义光照模式

本文主要讲解了Unity中SurfaceShader的自定义光照模式的写法。 上篇文章中我们已经说到,表面着色器将分为两次讲解,上一篇文章中介绍了表面着色器的基本概念和一些写法,用内置的兰伯特光照...
  • zhmxy555
  • zhmxy555
  • 2015年01月11日 17:03
  • 19631

【浅墨Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)

本文主要讲解了Unity中SurfaceShader的具体写法,以及几个常用的CG函数的用法。 在这里先说明一下,表面着色器将分为两次讲解,本文介绍表面着色器的基本概念和一些写法,用内置的兰伯特光照...

Unity Shader 表面着色器边缘光(Rim Lighting)一

上一节我们发现给小球加上板砖的法线贴图后,小球变暗了,我们这一节将会使小球边缘亮起来。 效果图:...

Unity Shader 表面着色器(Surface Shader)

Unity Shader分为表面着色器(Surface Shader),顶点着色器(Vertex Shader),片段着色器(Fragment Shader) 我们先来看个简单的Surface Sha...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:表面着色器笔记
举报原因:
原因补充:

(最多只允许输入30个字)