Shader入门学习

Shader学习笔记
相关博客http://www.cnblogs.com/polobymulberry/p/4314147.html
相关视频 Siki Shader着色器

什么是OpenGL、DirectX
CPU不直接与GPU交互,需要通过一些接口来进行交互
shader可以认为是一种渲染命令 ,由opengl 或者dx进行解析,来控制渲染丰富多彩的图形。

编写Shader语言
OpenGL 使用GLSL 编写shader
DirectX 使用HSSL 编写shader
英伟达 CG 编写shader(跨平台) 使用
使用ShaderLab来编写Unity中Shader
ShaderLab是CG的封装

Unity Shader 分类
1. 表面着色器 Surface Shader
2. 顶点/片元着色器 Vertex/Fragment Shader(功能强大,但是相对比较上一个编写较复杂)
3. 固定函数着色器 Fixed Function Shader(已弃用)
当光源比较多的时候,推荐使用表面着色器

Properties属性值简介

属性值(property)定义的形式:

_Name(“Displayed Name”,type) = default value[{options}]

  • _Name 属性值的名称,是在shader代码内部使用的,区别于下面的Displayed Name,后者是在Inspector 面板上显示的,作为外界(用户)的输入提示。
  • Displayed Name 呈现在材质编辑器中的属性值名称,在Inspector面板上显示。
  • type 属性值的类型,包括:
    Color – 表示纯色,使用了RGBA表示法
    2D – 代表尺寸为2的幂次的纹理(如2,4,8,16…256,512)
    Rect – 代表纹理(texture),不同于上面的纹理,此处纹理的大小不一定是2的幂次。
    Cube – 用于3d中的cube map,经常提到的天空盒就是使用了cube map。
    Range(min, max) – 在min和max之间的一个值,在面板中可用滑动条改变其值大小。
    Float – 任意一浮点数。
    Vector – 4维向量值,本质就是4个浮点数组成的类型。
  • default value 属性值的初始值,就相当于你的变量初始化的那个值。
    Color – (red,green,blue,alpha) 使用了RGBA这种格式的颜色,alpha指的是透明度– 比如 (1,1,1,1)
    2D/Rect/Cube – 纹理的类型,上面已经介绍过了。初始化值可以使一个空字符串,或者”white”, “black”, “gray”, “bump”(说明此纹理是一个凹凸纹理)
    Float/Range – 这个没啥说的,跟浮点数初始化一样一样的
    Vector – 4维向量,其中4个数均为浮点数 (x,y,z,w)

标签(Tags)

  • Background – 在所有其他物体渲染之前渲染,被用于天空盒或类似的背景效果。
  • Geometry(默认tags为geometry) – 适用于大多数物体。非透明物体使用这种渲染顺序。
  • AlphaTest – 进行alpha测试的像素(alpha-test是指当前像素的alpha小于一定的值就舍弃该像素)应该使用该渲染顺序。单独设置该渲染顺序是因为当在渲染完所有实体过后,渲染alpha测试的物体将更有效率。
  • Transparent – 该渲染标签所属的物体将在标签为Geometry和AlphaTest之后的物体渲染,并且这些贴着Transparent的所有物体本身是从后往前依次渲染的。任何经过alpha-blended的物体都应该使用该标签(译者注:alpha-blended是指使用当前像素的alpha作为混合因子,来混合之前写入到缓存中像素值,注意此时shader是不能写入深度缓存的,因为关闭了写入深度缓存的功能,如果不关闭写入深度缓存,那么在进行深度检测的时候,它背后的物体本来我们是可以透过它被我们看到的,但由于深度检测时,小于它的深度就被剔除了,从而我们就看不到它后面的物体了),玻璃和粒子效果比较适合该渲染标签。
  • Overlay – 该渲染标签适合覆盖效果,任何最后渲染的效果都可以使用该标签,比如透镜光晕。
    有趣的是你可以给这些基本的渲染标签进行加加减减。这些预定义的值本质上是一组定义整数,Background = 1000, Geometry = 2000, AlphaTest = 2450, Transparent = 3000,最后Overlay = 4000。(译者注:从此处我们也可以一窥究竟,貌似数值大的后渲染。)这些预设值这对透明物体有很大影响,比如一个湖水的平面覆盖了你用广告牌制作的树,你可以对你的树使用“Queue”=”Transparent-102”,这样你的树就会绘制在湖水前面了。

Shader的整体结构

Shader "Holo/Diffuser Texture"
{
    Properties{
        _MainTex("Texture",2D) = "white"{}
    }
        SubShader
    {
        Pass{

        Tags{"RenderType" = "Opaque"}
        CGPROGRAM
#pragma suiface surf Lambert
        struct Input {  //结构体
            float2 uv_MainTex;
        };
        sampler2D _MainTex;
        void surf(Input IN, inout Surfaceutput o)
        {
            o.Albedo = tex2D(_MainTex, IN.uv_MainTex.rgb);
        }
        ENDCG
            }
    }
        Fallback "Diffuse"
}
//tex2d的作用是利用IN.uv_MainTex所代表的uv坐标(注意我们上面指定了uv坐标产生的方式,所以此处的IN.uv_MainTex是自动生成的)对纹理_MainTex进行采样。此处,对于o.Albedo我们只取颜色分量中的rgb三分量,其中alpha值(透明度)目前不需要,至少对于非透明物体alpha值得作用不大。
//顶点函数  完成顶点坐标到模型空间到剪裁空间的转换(从游戏环境到相机视野上)
//片元函数  返回模型对应屏幕上的每一个像素的颜色值
//POSITION 传入系统顶点坐标
//SV_POSITION  返回值是剪裁空间的顶点坐标

你将会遇到half(半精度)和double(双精度)类型,half(一般16bit)即正常float(一般32bit)的一半精度,double(一般64bit)是正常float的两倍精度(此处的倍数衡量的方式不是指表示的范围,而是表示可以使用的bit位数)。使用half经常是出于性能考虑的原因。还有一种区别于浮点数的定点数fixed,精度更低。

当你想将颜色值规范到0~1之间时,你可能会想到使用saturate函数(saturate(x)的作用是如果x取值小于0,则返回值为0。如果x取值大于1,则返回值为1。若x在0到1之间,则直接返回x的值.),当然saturate也可以使用变量的swizzled版本,比如saturate(somecolor.rgb);

使用结构体

Shader "Holo/03UseStruct"
{
    SubShader{
        Pass{

        CGPROGRAM
#pragma vertex vert
#pragma fragment frag

        struct a2v
        {
            float4 vertex:POSITION;  //把模型空间下的顶点坐标填充给vertex
            float4 normal:NORMAL;  //把模型空间下的法线方向填充给normal
            float4 texcoord :TEXCOORD0;  //把第一套纹理坐标填充给texcoord
        };

        //结构体的变量必须有语义定义
        struct v2f
        {
            float4 position:SV_POSITION;  //SV_POSITION语义告诉Unity,pos里包含了顶点在裁剪空间的位置信息
            float3 temp:COLOR0;
        };

        v2f vert(a2v v)  //返回值是v2f
        {
            v2f f;
            f.position = UnityObjectToClipPos(v.vertex);
            f.temp = v.normal;
            return f;
        }

        fixed4 frag(v2f f) :SV_Target  //将颜色显示在屏幕上,SV_Tagrget表示把输出的数据当作颜色存储到渲染目标中。
        {
            return fixed4(f.temp,1);
        }

        ENDCG
    }
    }
        Fallback "VertexLit"
}

语义集合

从应用程序传递到顶点函数的语义有哪些a2v
POSITION 顶点坐标(模型空间下的)
NORMAL 法线( 模型空间下)
TANGENT 切线(模型空间)
TEXCOORD0 ~n 纹理坐标
COLOR 顶点颜色

从顶点函数传递给片元函数的时候可以使用的语义
SV_POSITION 剪裁空间中的顶点坐标(一般是系统直接使用)
COLOR0 可以传递一组值 4个
COLOR1 可以传递一组值 4个
TEXCOORD0~7 传递纹理坐标

片元函数传递给系统
SV_Target 颜色值,显示到屏幕上的颜色

光照模型

光照模型就是一个公式,使用这个公式来计算某个点的光照效果。

  • 自发光 每个点反射的强度都都一样
  • 高光反射 Specular 镜子
    计算公式:直射光*pow(max(cosθ,0)) θ是反射光线和视野光线方向的夹脚
  • 漫反射 Diffuse 粗糙的物体
    计算公式:直射光*pow(max(cosθ,0)) θ是法线和x的夹脚 x是平行光和视野方向的平分线
  • 环境光

Tags{ “LightMode”=”ForwardBase” }
只有定义了正确的LightMode才能得到一些Unity的内置光照变量

include “Lighting.cginc”
包含unity的内置的文件,才可以使用unity内置的一些变量

逐顶点漫反射的实现

Shader "Holo/04_Diffuse Vertex"
{
    Properties{
        _Diffuse("Diffuse Color",Color) = (1,1,1,1)  //在属性面板上显示
    }
        SubShader{
            Pass{
            Tags{"LightMode" = "ForwardBase"}

            CGPROGRAM
    #include "Lighting.cginc"  //获取第一个直射光的颜色,_LightColor0 获取第一个直射光的位置_WorldSpaceLightPos0
    #pragma vertex vert
    #pragma fragment frag
            fixed4 _Diffuse;  //再次声明变量

        struct a2v
        {
            float4 vertex:POSITION;  //把模型空间下的顶点坐标填充给vertex
            float3 normal:NORMAL;  //把模型空间下的法线方向填充给normal
        };

        //结构体的变量必须有语义定义
        struct v2f
        {
            float4 position:SV_POSITION;  //SV_POSITION语义告诉Unity,pos里包含了顶点在裁剪空间的位置信息
            float3 color:COLOR;
        };

        v2f vert(a2v v)  //返回值是v2f
        {
            v2f f;
            f.position = UnityObjectToClipPos(v.vertex);

            fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;  //取得环境光

            //直射光颜色 * max(0,cos夹角(光和法线的夹角) )  cosθ = 光方向· 法线方向环境光
            fixed3 normalDir = normalize(mul(v.normal, (float3x3)_World2Object));  //将模型空间的向量转换位世界空间
            fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);  //对于每个顶点来说,因为是平行光源,所以光的位置就是光的方向
            fixed3 diffuse = _LightColor0.rgb*max(dot(normalDir, lightDir), 0) * _Diffuse.rgb ;  //dot用来取得两个向量的点积

            f.color = diffuse+ambient;
            return f;
        }

        fixed4 frag(v2f f) :SV_Target  //将颜色显示在屏幕上,SV_Tagrget表示把输出的数据当作颜色存储到渲染目标中。
        {
            return fixed4(f.color,1);  //测试在屏幕上输出COLOR0
        }

        ENDCG
    }
    }
        Fallback "VertexLit"
}

//颜色之间的融合 需要使用 *
//颜色的叠加就使用  +
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值