• 友链

  • 首页

  • 文章归档
h u a n b l o g
h u a n b l o g

欢

HI,Friend

01月
14
Unity
Shader

Unity中自定义的三种Shader

发表于 2022-01-14 • 字数统计 8896 • 被 1,591 人看爆

固定功能管线着色器(Fixed Function Shaders)

一般用于不支持高级着色器特性的旧硬件。采用ShaderLab编写
所有硬件平台都可支持,针对硬件能够执行的基本命令的Shader,当然,功能有限,但是,速度最快。
没有Pass通道

示例

Shader "MyShader" {
	Properties{		//属性定义
		_Color("Main Color", Color) = (1, 1, 1, 0.5)
		_SpecColor("Spec Color", Color) = (1, 1, 1, 1)
		_Emission("Emmisive Color", Color) = (0, 0, 0, 0)
		_Shininess("Shininess", Range(0.01, 1)) = 0.7
		_MainTex("Base (RGB)", 2D) = "white" {}
	}

	SubShader{
		Pass{	//Pass定义
			Material {	//设置光照所需的材质参数
				//漫反射 必须依照光照,与灯光配合,将光打到物体表面反射光,我们才能看到物体
				Diffuse [_Color]		//漫反射命令,要想受光照影响,必须启用光照		Lighting On
				Ambient [_Color]		//环境光
				Shininess [_Shininess]		//滑动条高反射系数,配合启用高光的命令		SeparateSpecular On
				Specular [_SpecColor]		//高光
				Emission [_Emission]		//自发光
			}
			
			Lighting On				//开启灯光
					SeparateSpecular On		//启用高光颜色
			SetTexture [_MainTex] {			//设置纹理
				constantColor [_Color]		//设置一个常量
				combine texture * primary DOUBLE, texture * constant		//混合命令		与材质混合  double 是图片高亮的表现
			}
		}
	}
	
}

效果如下
UnityCustomShader01.png

表面着色器(Surface Shaders)

在Unity中,用Cg/HLSL语言编写,嵌入ShaderLab中。采用面向组件的方式,只需要写出关键的表面函数,其余部分由Unity自动生成,包括各种光源类型、渲染实时阴影等

编写规则

1.实现代码位置

实现代码要放置在CGPROGRAM...ENDCG代码块中,而不是放在Pass结构中,会自己编译到Pass

2.使用命令来指明这个是个表面着色器

命令为:#pragma surface...

格式为

#pragma surface 表面函数 光照模型 [可选参数]
表面函数:
用来指明哪个Cg函数包含有表面着色器代码
如:void surf(Input IN, inout SurfaceOutput o)

上面函数作用

“表面函数”的作用是接收输入的UV或者附加数据,然后进行处理,最后将结果填充到输出结构体SurfaceOutput中。
输入结构体lnput一般包含着色器所需的纹理坐标,纹理坐标的命名规则为uv加纹理名称(当使用第二张纹理时使用uv2加纹理名称)。另外还可以在输入结构中设置一些附加数据,如下图
SurfaceOutput描述表面的各种参数,结构标准为下

附加数据
UnityCustomShader02.png

SurfaceOutput结构标准

struct SurfaceOutput{
    half3 Albedo;       //反射光
    half3 Normal;       //法线
    half3 Emission;     //自发光
    half Specular;      //高光
    half Gloss;         //光泽度
    half Alpha;         //透明度
}
光照模型:
可以是内置的Lambert和BlinnPhong,或者是自定义的光照模型

例子

  Shader "Diffuse Simple" {
    SubShader {
      Tags { "RenderType" = "Opaque" }			//告诉系统要渲染的对象
      CGPROGRAM				//表面着色器的实现代码
	  //指明着色器类型,表面函数和光照模型
      #pragma surface surf Lambert			
      struct Input {			//输入数据结构体
          float4 color : COLOR;
      };
      void surf (Input IN, inout SurfaceOutput o) {			//表面函数
          o.Albedo = 1;
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

效果如下
UnityCustomShader03.png

添加纹理

Shader "Diffuse Texture" {
    Properties {		//添加纹理
      _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {		//数据结构体
          float2 uv_MainTex;
      };
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {		
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

效果如下
UnityCustomShader04.png

添加法线贴图

  Shader "Diffuse Bump" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _BumpMap ("Bumpmap", 2D) = "bump" {}		//法线贴图属性
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
        float2 uv_MainTex;
        float2 uv_BumpMap;
      };
      sampler2D _MainTex;
      sampler2D _BumpMap;		//发现贴图
      void surf (Input IN, inout SurfaceOutput o) {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
        o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

法线贴图
UnityCustomShader06.png

效果如下
UnityCustomShader05.png

添加立体反光

  Shader "WorldRefl" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _Cube ("Cubemap", CUBE) = "" {}		//立方体贴图属性
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
          float3 worldRefl;			//输入反射参数
      };
      sampler2D _MainTex;
      samplerCUBE _Cube;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * 0.5;
          o.Emission = texCUBE (_Cube, IN.worldRefl).rgb;		//将反射颜色设置为自发光
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

效果如下
UnityCustomShader07.png

顶点着色器(Vertex and Fragment Shaders)

运行于具有可编程渲染管线的硬件上,包含:顶点程序(Vertex Programs)和片段程序(Fragment Programs)
使用顶点着色器进行渲染时,图形硬件的固定功能管线将会关闭,用顶点程序替换掉固定功能管线中标准的3D变换、光照等功能,片段程序会替换掉SetTexture命令中的纹理混合模式
也是用Cg/HLSL编程语言来实现
可用于生成动画和沿法线移动顶点等,后面示例

结构

代码用CGPROGRAM ENDCG语言包围起来,放在ShaderLab中Pass命令中

示例

...
Pass {
    //通道设置
    CGPROGRAM
    //本段Cg代码的编译指令
    #pragma vertex vert
    #pragma fragment frag
    //Cg代码
    ENDCG
}

编译指令

可用的编译指令
UnityCustomShader08.png

编译目标

对应不同版本的着色器模型。可设置为#pragma target2.0、#pragma target3.0、#pragma target4.0、#pragma target5.0

渲染平台

支持的平台

  • d3d9即Direct3D 9。
  • d3d11即Direct3D 11。
  • opengl即OpenGL。
  • gles 即OpenGL ES 2.0。
  • gles3即OpenGL ES 3.0。
  • metal 即iOS Metal。
  • d3d11_9x即Direct3D 11 9.x feature level。
  • xbox360即Xbox360。
  • xbox one即Xbox One
  • ps3即PlayStation3。
  • ps4即PlayStation4。
  • psp2即PlavStation Vita

例子

下面是顶点片段着色器的例子。在顶点着色器中可以使用顶点Shader程序修改顶点数据。该方法可用于生成动画和沿法线移动顶点等。通过在表面着色器中书写一个顶点程序函数来实现它,需要把appdata_full结构作为参数传递到方法中。

沿着法线方向移动顶点

  Shader "Normal Extrusion" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _Amount ("Extrusion Amount", Range(-1,1)) = 0.5		//人物变胖大小
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }			//渲染类型为不透明
      CGPROGRAM
		//定义表面和顶点函数
      #pragma surface surf Lambert vertex:vert		
      struct Input {
          float2 uv_MainTex;			//MainTex的Uv坐标
      };
      float _Amount;
      void vert (inout appdata_full v) {		//输入结构作为参数
          v.vertex.xyz += v.normal * _Amount;		//修改顶点位置
      }
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;		//输出漫反射颜色
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

效果如下,原样可参看上面
通过沿法线移动顶点使人物变胖了
UnityCustomShader09.png

根据法线方向设置模型表面颜色


Shader "Display Normals" {
SubShader {
    Pass {
CGPROGRAM
//Cg代码块开始
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {		//顶点数据结构体
    float4 pos : SV_POSITION;
    float3 color : COLOR0;
};
v2f vert (appdata_base v)		//顶点程序代码,计算位置和颜色
{
    v2f o;
    o.pos = UnityObjectToClipPos (v.vertex);
    o.color = v.normal * 0.5 + 0.5;
    return o;
}
half4 frag (v2f i) : COLOR			//片段程序代码,直接把输入的颜色返回,并把透明度设置为1
{
    return half4 (i.color, 1);
}
ENDCG
    }
}
Fallback "VertexLit"
} 

效果如下图
UnityCustomShader10.png

根据切线方向设置模型表面颜色


Shader "Tangents" {
SubShader {
    Pass {
        Fog { Mode Off }
        CGPROGRAM

        #pragma vertex vert
        #pragma fragment frag

        // 输入位置和切线数据
        struct appdata {
            float4 vertex : POSITION;
            float4 tangent : TANGENT;
        };

        struct v2f {		//定义顶点数据结构体
            float4 pos : SV_POSITION;
            fixed4 color : COLOR;
        };
        
        v2f vert (appdata v) {		//顶点程序函数
            v2f o;
            o.pos = UnityObjectToClipPos( v.vertex );		//计算顶点位置
            o.color = v.tangent * 0.5 + 0.5;		//计算顶点颜色
            return o;
        }
        
        fixed4 frag (v2f i) : COLOR0 { return i.color; }		//片段程序,直接返回顶点颜色
        ENDCG
    }
}
}

材质效果图
UnityCustomShader12.png

人物效果图
UnityCustomShader11.png

参考

  • 奋斗的菇凉-Unity中的三种自定义Shader
  • 官网-编写表面着色器
分享到:
死锁(一)
UnityShaderLab语法
  • 文章目录
  • 站点概览
欢

网红 欢

你能抓到我么?

Email RSS
看爆 Top5
  • mac系统版本与Xcode版本有冲突 4,269次看爆
  • JAVA_HOME环境配置问题 3,927次看爆
  • AssetBundle使用 3,644次看爆
  • VSCode配置C++开发环境 3,415次看爆
  • Lua反射 3,255次看爆

Copyright © 2025 欢 粤ICP备2020105803号-1

由 Halo 强力驱动 · Theme by Sagiri · 站点地图