[Unity] Shader(着色器)输入输出和语义

在Unity5.x后, 已经支持了基于物理的光照模型,也就是常说的次时代引擎所必须具备的功能。

如果在Properties使用2D,CG里要用sampler2D,代表使用的是2维纹理
如果在Properties使用color, CG里要用fixed4
如果在Properties使用Range, CG里要用half,实际上描述的是一个float
struct Input  用于描述UV坐标的结构体。在 Input 中, 变量名必须是 uv_ 开始, 变量名必须是官方文档中已经指定的名称(也就是说不可以随意设定)
CGPROGRAM ... ENDCG  代码块,表示从这一句下面开始直到EndCG,表示我们是使用了CG语言编写的代码
#pragma 编译指令:  #pargma 关键词 函数名 光照模型 [其它选项] 

函数名在cginc中,实际上会在前部加上 Lighting ,如 LightingStandard , 我们用的时候只取后部分 , 也就是 Standard
#pragma target 3.0  使用model 3.0 可以得到一个更好的光照效果, 默认是2.0
#pragma surface surf Standard fullforwardshadows  表示当前是一个 surface 着色器, 函数名是 surf, 使用 Standard 基于物理系统光照模式, 有一个完整的向前的阴影 (Standard 必须是Unity 5.x后才有)

#pragma surface surf Lambert addshadow  表示当前是一个 surfac 着色器, 函数名是 surf, 使用 Lambert 兰伯特光照模型, addshadow 表示给物体添加一个阴影

示例代码:
Shader "Sbin/sf" {
    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
    }

    // 在surfaceShader不需要有Pass通道,否则会报错
    SubShader {
        // 渲染类型,是一个不透明物体
        //Tags { "RenderType"="Opaque" }
        Tags { "RenderType"="Opaque" "Queue" = "Transparent" }
        // 层级细节
        LOD 200

        // 代码块,表示从这一句下面开始直到EndCG,表示我们是使用了CG语言编写的代码
        CGPROGRAM

        // #pragma 编译指令
        // 格式:
        // #pragma surface surfaceFunction lightModel [optionalparams]
        // #pargma 关键词 函数名 光照模型 [其它选项]

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

        // 使用model 3.0 可以得到一个更好的光照效果, 默认是2.0
        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        // 如果在Properties使用2D,CG里要用sampler2D,代表使用的是2维纹理
        // 如果在Properties使用color, CG里要用fixed4
        // 如果在Properties使用Range, CG里要用half,实际上描述的是一个float
        sampler2D _MainTex;

        // 输入结构体用于模述UV的坐标。
        struct Input {
            // 变量必须是uv_开头,_号后面的_MainTex自动对应Properties中的_MainTex和sampler2D
            // _MainTex 也是不能变的。
            float2 uv_MainTex;
        };

//        half _Glossiness;
//        half _Metallic;
//        fixed4 _Color;

        // in 参数是输入的
        // out 参数是输出的
        // inout 参数即是输入,又是输出
        // SurfaceOutputStandard 可以使用基于物理的光照模型(次时代)
        //void surf (Input IN, inout SurfaceOutputStandard o) {
        void surf (Input IN, inout SurfaceOutput o) {
            // Albedo comes from a texture tinted by color
            // 从纹理中进行采样
            //fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb; // 基本的漫反射
            // Metallic and smoothness come from slider variables
            //o.Metallic = _Metallic;
            //o.Smoothness = _Glossiness;
            o.Alpha = c.a; // 透明度
        }
        ENDCG
    }
    // FallBack 当我们的surfaceshader编译后没有一个阴影通道时,会自动添加一个阴影通道
    //FallBack "Diffuse"
}

在 SurfaceShader 中, 不可以有 Pass 通道, 否则会报错。

以上内容只是笔记, 有错误请指正。

官方示例

我们将开始用一个非常简单的着色,并建立在。这里的一个着色,只设置表面颜色“白”。它使用内置的Lambert(扩散)照明模型。

Shader "Example/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"
  }

Texture 使用纹理

An all-white object is quite boring, so let’s add a texture. We’ll add a Properties block to the shader, so we get a texture selector in our Material. Other changes are in bold below.

所有的白色物体都很无聊,所以让我们添加一个纹理。我们将添加一个属性块到着色,所以我们得到一个纹理选择器在我们的材料。其他变化是在大胆下面。

Shader "Example/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"
  }

Normal mapping  法线贴图

Let’s add some normal mapping:

让我们添加一些法线贴图:

Shader "Example/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"
  }

Rim Lighting  边缘照明

Now, try to add some Rim Lighting to highlight the edges of an object. We’ll add some emissive light based on angle between surface normal and view direction. For that, we’ll use viewDir built-in surface shader variable.

现在,尝试添加一些边缘照明,以突出对象的边缘。我们将添加一些散射光基于表面法线和视图方向的夹角。这样,我们将使用viewdir内置表面着色器变量。

Shader "Example/Rim" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _BumpMap ("Bumpmap", 2D) = "bump" {}
      _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)
      _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
          float2 uv_BumpMap;
          float3 viewDir;
      };
      sampler2D _MainTex;
      sampler2D _BumpMap;
      float4 _RimColor;
      float _RimPower;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
          o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
          half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
          o.Emission = _RimColor.rgb * pow (rim, _RimPower);
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

更多资料参考 Unity 官方文档: Unity/Editor/Data/Documentation/en/Manual/SL-SurfaceShaderExamples.html

时间: 2024-10-12 20:17:04

[Unity] Shader(着色器)输入输出和语义的相关文章

[Unity] Shader(着色器)之纹理贴图

在Shader中,我们除了可以设定各种光线处理外,还可以增加纹理贴图. 使用 settexture 命令可以为着色器指定纹理. 示例代码: Shader "Sbin/ff2" { // 贴图采样 properties { // 变量名("描述名",类型)=值 _Color("主体", color)=(1,1,1,1) _Ambient("环境光", color)=(0.3,0.3,0.3,0.3) _Specular(&quo

[Unity] Shader(着色器)之固定管线

在Unity中,固定管线Shader的性能是最好的. 什么是固定管线呢? 固定渲染管线 —— 这是标准的几何&光照(T&L)管线,功能是固定的,它控制着世界.视.投影变换及固定光照控制和纹理混合.T&L管线可以被渲染状态控制,矩阵,光照和采制参数. 下面是一个固定管线Shader的示例: Shader "Sbin/ff1" { // 固定管线 properties { // 变量名("描述名",类型)=值 _Color("主体&qu

【Unity Shader】--- 准确认识SubShader语义块结构、渲染状态设定、Tags标签

一[SubShader] 每个UnityShader文件可以包含多个SubShader语义块,但至少要有一个.当Unity需要加载这个UnityShader时,Unity会扫描所有的SubShader语义块,然后选择一个能够在目标平台上运行的SubShader.如果都不支持的话,Unity就会使用FallBack语义指定的UnityShader. Unity提供这种语义的原因在于,不同的显卡具有不同的能力.例如,一些旧的显卡仅能支持一定数目的操作指令,而一些高级的显卡可以支持更多的指令数,那么我

【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/41175585 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] 本文介绍了Unity中子着色器.通道和标签相关的详细概念与写法,以及纹理的设置方法,基本的纹理混合写法,写了5个Shader作为本文Shader讲解的实战内容,最后创建了一个梦幻的光之

Unity Shader 学习之旅-初探

Unity Shader 学习之旅-初探 unity shader 图形图像 美丽的梦和美丽的诗一样 都是可遇而不可求的--席慕蓉 最简单的顶点片元着色器 顶点片元着色器基本结构 Unity Shader基本结构:Shader ,Properties,SubShder,Fallback等. 结构 Shader "ShaderName"{  Properties{  //属性,暴露在inspector面板上  }  SubShader{  //针对显卡A的SubShader  Pass{

着色器编译目标等级

无论编写 表面着色器还是其他常规着色器程序时,HLSL资源可以别编译为不同的"着色器模型".更高的着色器编译器目标允许使用更多现代GPU功能,但是可能造成在老的GPU或者平台上不能正常工作. 编译器目标通过指令 #pragma target 来指定,比如: #pragma target 3.5 默认的编译器目标 默认情况下,unity将着色器编译为支持最低目标级别(2.5):在DirectX着色器2.0和3.0之间.其他一些编译指令使着色器自动被编译成更高的目标: 使用几何着色器来设置

02 传递颜色给着色器

这一节介绍给着色器程序传值的方法.我们通过js把颜色传给着色器程序,来演示具体传值的方法. 顶点坐标.顶点颜色.uv坐标等都可以使用"矩阵"把值传给着色器程序.这个"矩阵"(其实只是个数组)只是我们假想的一个矩阵,它的每一行表示一个顶点,例如:顶点坐标几行就有几个顶点,每一行是坐标xyz值:顶点颜色"矩阵"中每一行是对应顶点的颜色的rgba值(红.绿.蓝.透明度). 它们在着色器程序中,都可以使用vec3.vec4(向量)类型变量接收.虽然他们表

【OPENGL】第三章 着色器基础(一)

在这一章,我们会学习什么是着色器(Shader),什么是着色器语言(OpenGL Shading Language-GLSL),以及着色器怎么和OpenGL程序交互. 首先我们先来看看什么叫着色器. Shader(着色器)是用来实现图像渲染的,用来替代固定渲染管线的可编程程序. 着色器替代了传统的固定渲染管线,可以实现3D图形学计算中的相关计算,由于其可编程性,可以实现各种各样的图像效果而不用受显卡的固定渲染管线限制.这极大的提高了图像的画质. 在上一篇文章( http://www.cnblog

unity shader 学习 (2)Vs【顶点着色器】 和 Ps【像素着色器】

上一章我写了渲染管线,中间提到了shader的作用,我们的大shader同学主要就是负责被CPU指派到GPU中做一些如顶点转换,关照模型,光栅化等操作的. 大shader有两种类型,他们分别是Vs[顶点着色器] 和 Ps[像素着色器].. 他们可以同时存在,也可以分开存在,没有任何使用限制. 当时如果同时存在的话,必须Vs执行完成后再交给Ps处理. 他们两个家伙是配合固定流程管线而存在的.