[Unity 学习] - 进阶篇 - 基础渲染系列(二)游戏开发的画笔——着色器

[Unity 学习] - 进阶篇 - 基础渲染系列(二)游戏开发的画笔——着色器

本文并非原创,只是本人的学习记录,原文是由放牛的星星老师翻译Catlike系列教程
链接: https://zhuanlan.zhihu.com/p/138230081

1 构建场景

创建一个默认场景,自带一个相机和一个定向光,创建一个Sphere,放置远点,摄像机放置前方。
在这里插入图片描述
这个简单的场景已经发生了许多复杂的渲染,我们需要将其一步步剥离出来

1.1 剥离

剥离前我们需要知道这个场景中有哪些东西
在这里插入图片描述
在Hierarchy栏中我们可以看到场景中有一个主摄像机(Main Camera), 一个环境光(Derectional Light),还有我们刚刚创建的球体(Sphere)。
事实上还有没有在Hierarchy中显示出的东西,比如说天空盒(Skybox)
打开场景的照明设置我们可以看到场景中有一个默认的Skybox
在这里插入图片描述
当我们使用天空盒时,会将天空盒作用于场景背景,环境照明和反射。我们将它删掉。因为它对灯光的影响很大。
没有的天空盒时,我们会在Scene中看到背景变为灰色,Sphere颜色会变得更暗,这是因为没有环境光反射了。但神奇的是我们在Game窗口中会看到背景变为蓝色,原因是摄像机自定义了背景色,默认情况下回渲染天空盒,但是当我们把天空盒删除后就会渲染原色。
在这里插入图片描述
PS: 这里拍的alpha的值是5,但是事实上作为背景色没有任何影响,在不同的版本也不同,我所用Unity 2019.3.0版本的默认背景色alpha == 0,
现在我们关掉灯光,看一下在全黑的情况的,物体是什么样子的。
在这里插入图片描述

2 从物体到图像

创建一个Shader
在这里插入图片描述
这里偷个懒,将整个Shader所有内容都写到一个脚本里面了

Shader "Unlit/UnlitS"
{
    // Shader 语法结构
    // Propertise 定义我们传入的数据
    Properties
    {
        // [变量名]("监视面板名",类型)=值
        
        // 四个值
        _Color ("Color",Color) = (1,1,1,1) // r,g,b,a
        _Vector ("Vector",Vector) = (0,0,0,0) // x,y,z,w
        // 贴图类型
        _MainTex ("Texture", 2D) = "white" {}
        _BumpTex ("Bump", 2D) = "bump" {} // bump为法线贴图为空的特殊默认值
        _CubeTex ("Cube", Cube) = "white" {} // Cub类型,常用来做环境球,采样值是三维向量
        // 浮点类型
        _Value ("value",float ) = 0.5
        _RangeValue("RangeValue",Range(0,1)) = 0.5

    }
    // SubShader 是给GPU运行的程序
    // 一个Shader中可以有多个SubShader,但是只执行第一个Shader
    SubShader
    {
        // 定义该次渲染类型和队列位置
        Tags { "RenderType"="Opaque" }
        LOD 100 // 你的贴图在这个距离外开始启用LOD

        // 可以编写多个Pass,但每个都会被依次执行
        // 比如灯光编写一个Pass,阴影编写一个Pass
        Pass
        {
            CGPROGRAM // CGPROGRAM ENDCG 在这个范围内编写CG语言
            
            // 定义两个函数:顶点函数,片元函数
            // 可以理解为有两个入口函数
            // 顶点函数,Mesh需要渲染的每个像素执行一次
            #pragma vertex vert 
            #pragma fragment frag
            // make fog work
            // Unity内置宏,方便我们生成雾色
            #pragma multi_compile_fog

            // 引用外部文件
            #include "UnityCG.cginc" 

            // 将Properties中定义的变量进行绑定,这样GPU才会找到对应的数据
            sampler2D _MainTex;
            float4 _MainTex_ST;

            // appdata为传递给顶点函数的结构体(a2v)
            // appdata中定义的属性来源为Mesh网格信息
            // appdata中的所有属性都是针对当前渲染的顶点
            struct appdata
            {
                // 定义方式: [类型名][变量名]:[标识符]
                float4 vertex : POSITION; //vertex对应的位置信息
                float3 normal : NORMAL; // normal对应法线信息
                fixed4 color : Color; // color对应顶点颜色
                float2 uv : TEXCOORD0; // uv对应uv信息
            };

            // v2f为顶点函数的返回类型
            // 顶点函数执行完以后会将返回值传入到片元函数
            // 这里的值需要定义,在订点函数中间进行赋值
            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            // 顶点函数
            v2f vert (appdata v)
            {
                v2f o;
                // 对顶点进行空间变换,转移到摄像机的投影空间中
                o.vertex = UnityObjectToClipPos(v.vertex);
                // 对uv进行运算和赋值
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                //之前定义的雾的宏方法
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            // 片元函数 传入v2f,即顶点函数返回的值,像素函数
            // 返回值是一个fixed4,说明我们返回的是一个颜色值,也就是一个像素
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                // 定义一个像素,通过tex2D对贴图对应位置进行采样
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                // 雾定义的宏方法对颜色进行加工并返回
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col; // 将这个像素返回到屏幕
            }
            ENDCG
        }
    }
}

需要注意的是在Properties设置的属性可以在着色器检查器中查看属性
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43617207/article/details/129746638
今日推荐