ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Unity_Shader,作用流程入门程精讲

2021-01-19 13:05:24  阅读:239  来源: 互联网

标签:渲染 精讲 绑定 shader Shader Unity 片元 顶点 着色器


Unity_Shader

写在前面

  • 虽说已经入门(至少我觉得入门了?)shader有些时间了,不过由于慢慢的对入门级的东西有了新的感悟,再者组织要喊我给学弟学妹们培训一手,遂准备记下这篇内容作为教材。
  • 在我入门shader那会,啃过学长给的书,摸过siki老师的课,看过知乎大佬的专栏,无一例外,大家都是底层开篇,上手开始GPU渲染流程,渲染流水线。很专业的开篇,但对于没有底层基础和图形学基础的人来说,可能有点难以接受,更难融会贯通真正的用上。
  • 所以今天我写的这篇入门呢,主要是给没什么底层基础,图形学基础的小白入门参考。
  • 本文主要讲述图形渲染流水线大概是个什么样子(参考知乎大佬王子饼干的shader魔法书专栏),shader在这个流水线中怎样作用,CPU和GPU在后台工作时的区别,用shader处理图像和用c#处理图像有什么区别,一个最简单的shader。
  • 注意:本篇涉及到的绝大部分思维上的例子,举例所用的数字,纯属个人理解上的虚构,并非真正的底层知识,所以只能做一个领进门的作用,底层,还是要找专业的资料好好学一学的。
  • 哦对了,这篇文章实践性内容不多,所以可能会很枯燥,但如果你学的下去,小白入门进度会快很多。

渲染流水线

什么是渲染流水线

  • 大概就是说,你做游戏的时候这个游戏物体,本身也是一堆数据,他要经过“渲染”,这才会出现在屏幕上。而渲染流水线,就是将一团数据层层包装迭代筛选,最终呈现在屏幕上的过程。

渲染流水线的各大阶段

渲染流水线主要有三个阶段,应用阶段,几何阶段,光栅化阶段。

  • 应用阶段:在这个阶段,程序会拿到之后所用到的很多很多信息,诸如:场景中的物体模型,场景中的光源信息,以及我们所为其输入的一些数据。在这个阶段最后,会输出渲染所需要的几何信息到下一个工位。
  • 几何阶段:该阶段通常处理的是几何空间下的很多事情,诸如对模型的顶点信息进行空间变换,去取到一些信息来决定要绘制的图像,最后呢,这个阶段会将顶点信息输出到二维屏幕坐标下,然后传递给下一个工位。
  • 光栅化阶段:该阶段是讲之前的内容拿过来,并合并计算一个像素点的信息,最终决定屏幕上显示内容的部分。
  • 接下来看一张图,其中我只写入了本节需要我们关注的三部分,这三部分我会详细说一说。其他部分全部省略了,日后需要自行找找资料详细学习,其底层流程。
    在这里插入图片描述

应用阶段_程序与数据的读入

  • 首先关于这部分呢,是系统要做的事,而不是我们要做的,但需要简单知道系统做了什么,知道在什么情况下做什么东西用c#做什么东西用shader。
  • Shader代码是执行在GPU上的,和我们通常写的C#代码不同,其仅仅支持一些简单的逻辑操作。下面看一张图来了解下这俩个执行在CPU与GPU上的程序各自的优缺点。
    在这里插入图片描述
  • 如上图,蓝色部分是存储单元,其为CPU和GPU提供了直接访问权限,故而将信息读入这些存储单元再进行使用将会提升速度,这就是执行前读入数据的过程。
  • 而红色部分是今天的重点,其是运算单元,CPU的运算单元更加强大,但量少,强大在其可以执行很复杂的逻辑运算,但量少导致其面对大量简单问题时显得乏力。而GPU的运算单元数量很庞大,但本身能力较弱,不支持很复杂的逻辑,但其数量决定了其可以快速处理海量的简单问题。曾见过一个网友举例:CPU就像几个大学生,你让他算什么都可以,但你让他算一万个二位数加法,他得算几个小时。而GPU像一万个小学生,你让他们一起算一个微积分,他们算不得,但你给他们分配下去一万个俩位数加分,在一人一题的情况下,不出一分钟就解决了。
  • 也正是这种特点,CPU更适合我们后台的逻辑脚本,GPU更适合做渲染显示方面的工作。拿一张图的后处理来说,这张图有1万个像素点,你要把所有点都变深一点,用CPU可以用循环做很多很多次遍历,最终遍历完整张图,而GPU可以直接给每一个运算单元分配一块像素,各自开工,瞬间解决。
  • 也正是因为GPU和CPU的这种区别,使得我们写的shader代码中诸如顶点着色器,片元着色器效率能很高,顶点着色器会分给很多个运算单元各自计算各自负责的顶点,片元着色器分给很多个运算单元各自计算各自负责的片元。

几何阶段_顶点着色器

  • 这个阶段就是我们需要编写进shader中的第一个阶段了,主要负责从应用阶段拿到我们需要的一些参数,然后根据这些东西计算出剪裁空间下的顶点坐标,然后传给后面的工位(当然你也可以做一些其他的事情)。
  • 取参数:到这里就不得不提一下shader中参数从何而来,在系统渲染时会自动调用我们写好的顶点着色器,并按照我们规定自动传入参数,所以我们需要告诉系统,我们需要哪些参数,这个告知方式固然不是自己想怎么说就怎么说,要使用和系统约好的“暗号”,专业点的术语叫做语义绑定。
    下面举个小例子:
struct VertexInput
            {
                float4 Pos:POSITION;            //语义绑定
                float2 uv:TEXCOORD0;         //语义绑定
            };
  • 如上定义了一个结构体其中包含的参数都绑定了语义,这些语义做什么用的参照Unity_Shader中一些常用变量和函数的集合,这样一来将这个结构体作为定点函数的参数传递过去即可。
  • 函数绑定和取参数一样,都是需要指明哪个函数是顶点函数,这样系统才不会调用错。
    举例如下
#pragma vertex _Vert
  • 如上绑定了顶点函数,名字为_Vert。 #pragma为绑定函数的关键词,vertex为指明绑定的函数为顶点函数。

光栅化阶段_片元着色器

  • 这个阶段与顶点着色器基础思想山很相似,不过作用主体是光栅化后的片元,什么是片元,你可以直接理解成一块块的像素点,详细的可以自己搜索下。而其最终需要返回一个颜色值,就是当前片元的颜色了。
  • 取参数:与之前顶点着色器很相似,都是定义一个结构体,然后让这个结构体内的参数绑定语义,在当做参数传进去。不过需要注意的是,其中涉及到需要顶点着色器传给片元着色器的参数,因此顶点着色器需要返回一个这样的结构体,以便后面片元着色器直接取到这些参数。
    举例如下:
            struct VertexOutput
            {
                float4 Pos:SV_POSITION;
                float2 uv:TEXCOORD0;
            };
  • 函数绑定这部分与顶点部分差不多,只是vertex换成了fragment
#pragma fragment Pixel
  • 如上便绑定了片元着色器函数,函数名为Pixel

简单例子

  • 举个最简单的渲染例子,我们写一个shader封装成材质给胶囊体上色。
  • 右键资源管理器,create->shader->Standard Surface Shader 创建一个新的表面着色器。
  • 删除其中内容开始写,首先是整体结构搭好如下:
Shader "Custom/test"          //指明其为shader代码,后面的字符串是其在材质选择渲染器时的路径
{
    Properties                        //公开型变量,在材质的属性面板可以修改
    {
    }
    SubShader                      //语法之一写就完事了,之后在理解。
    {

    }
    FallBack "Diffuse"            //默认声明,表示如果我们写的SubShader在当前设备上不支持,就用默认渲染
}

  • 然后向变量区写入一个color类型的,表示最终渲染成什么颜色。
    Properties                        //公开型变量,在材质的属性面板可以修改
    {
    	        _Color ("Color", Color) = (1,1,1,1)
    }
  • 接着在SubShader中写入一个新的pass块(相互独立,按序执行渲染的具体渲染块),在其中写入CG语法应用范围(使用CGPROGRAM关键词表示开始应用cg语法,使用ENDCG关键词表示结束),并在范围内写入头文件声明,函数绑定。
    SubShader
    {
        pass
        {
                CGPROGRAM
                #pragma vertex _Vert
                #pragma fragment Pixel
                #include "UnityCG.cginc"
                ENDCG
        }
    }
  • 接着定义输入输入结构体,声明要用到的变量(当声明变量名字和Properties块中一样的时候,就表示你这个变量是那个外界可以调的)。
                struct VertexInput
                {
                    float4 Pos:POSITION;
                };
                struct VertexOutput
                {
                    float4 Pos:SV_POSITION;
                };
                fixed4 _Color;
  • 然后是顶点着色器和偏远着色器的编写
                VertexOutput _Vert(VertexInput v)
                {
                    VertexOutput r;
                    //将顶点转换到剪裁空间
                    r.Pos = UnityObjectToClipPos(v.Pos);
                    return r;
                }
                fixed4 Pixel(VertexOutput v):SV_Target
                {
                    //直接将定义好的颜色返回为该片元的颜色
				    return _Color;
                }
  • 到这里就编写完了,完整代码如下:
Shader "Custom/test"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        pass
        {
                CGPROGRAM
                #pragma vertex _Vert
                #pragma fragment Pixel
                #include "UnityCG.cginc"
                struct VertexInput
                {
                    float4 Pos:POSITION;
                };
                struct VertexOutput
                {
                    float4 Pos:SV_POSITION;
                };
                fixed4 _Color;
                VertexOutput _Vert(VertexInput v)
                {
                    VertexOutput r;
                    //将顶点转换到剪裁空间
                    r.Pos = UnityObjectToClipPos(v.Pos);
                    return r;
                }
                fixed4 Pixel(VertexOutput v):SV_Target
                {
                    //直接将定义好的颜色返回为该片元的颜色
				    return _Color;
                }
                ENDCG
        }
    }
    FallBack "Diffuse"
}

标签:渲染,精讲,绑定,shader,Shader,Unity,片元,顶点,着色器
来源: https://blog.csdn.net/weixin_44579240/article/details/112741146

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有