文章

UnityShade入门精要(1·unityShader基础和Debug)

之前理论章节先略过,有时间再看,从第5章实战部分开始

渲染管线简化流程:data->CPU->GPU->演示,的过程,其中我们可以更改其中的shader可编程部分,完成不同的最终演示效果

在引擎中应用shader非常方便,其它的都是unity editor中的可视化的图形,仅需要将写好的shader应用到物体材质上,这个物体的渲染就会用这个着色器,那么根据shader的不同,呈现的最终效果也不同

为obj应用shader

新建unity工程

在assest新建shader:create->shader->……有如下分类:

  • Standard Surface Shader标准表面着色器,可以实现各种物品的效果,比如石头、木材、玻璃、塑料和金属等等。
  • Unlit Shader它是最简单的着色器,由最基础的 Vertex Shader 和 Fragment Shader组成
  • Image Effect Shader主要针对实现各种屏幕后期处理着色器,一般像是泛光、调色、景深、模糊等基于最终整个屏幕画面而进行再次处理的就是后处理,
  • Compute Shader计算着色器,独立于常规渲染管线之外的,它可以直接将GPU作为并行处理器加以利用,使GPU具有运算能力。一般会在需要大量并行计算的时候使用。
  • Ray Tracing Shader光线追踪着色器,光线追踪可以轻松模拟各种光学效果,如反射、折射、散射、色散等。但由于在进行求交计算时需要知道整个场景的信息,它的计算成本也是非常高的。

为了更原始,可以在window->lighting->environment把dufault天空盒去掉

创建一个shader,简单效果通常创建unlit shader,

新建材质,将shader给它 (在材质的inspector面板上面有选择shader,搜索你的shader名称),

新建球体,把材质给它(mesh renderer组件中)

编写shader_CG

unity使用ShaderLab对shader进行了更高一层的封装

基本结构

首先看一下它的基础结构:

shader的路径“……/……”

Properties定义可以在材质编辑器中调整的属性

SubShader

  • LOD细节层次和渲染标签Tags
  • pass 渲染通道,
    • CGPROGRAM和ENDCG包裹了实际用 Cg/HLSL/GLSL 编写的顶点和像素着色器代码(本教程使用CG,类似于C语言)

Fallback指定了如果当前着色器无法正常工作时使用的备用着色器

看一下最简单的实例

将绘制白色物体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Shader "Unlit/SimpleShader"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            //哪个函数包含了顶点着色器的代码,哪个函数包含了片元着色器的代码。
            #pragma vertex vert
            #pragma fragment frag
            //逐顶点:接受顶点位置,返回裁剪空间的位置,
            float4 vert(float4 v: POSITION) : SV_POSITION {
                return mul (UNITY_MATRIX_MVP, v);
            }
            //逐像素
            fixed4 frag() : SV_Target{
                return fixed4(1.0, 1.0, 1.0, 1.0); 
            }
            ENDCG
        }
    }
}

展开

如果我们想要得到其他的模型的顶点数据怎么办呢?

输入参数和返回值不再是一个简单的数据类型,而是一个结构体,

Unity 会根据这些语义来填充这个结构体,现在这些成员都是有数据的、

Unity 支持的语义有(由MeshRender组件提供): POSITION, TANGENT, NORMAL, TEXCOORDO, TEXCOORDJ, TEXCOORD2, TEXCOORD3, COLOR 等

1
2
3
4
5
struct a2v {//application to vertex
  float4 vertex : POSITION;
  float3 normal : NORMAL;
  float4 texcoord : TEXCOORD0;
};

展开

顶点着色器和片元着色器之间如何通信?

因为顶点数据只能通过vs传给fs(不考虑uniform)

为此需要使用一个新的结构体v2f来定义顶点着色器的输出(要指定语义)

让vert函数返回v2f,frag接受v2f参数 1732980973590

属性

属性可以理解为其他图形API的uniform变量

材质和Unity Shader之间的紧密联系。材质提供给我们一个可以方便地调节Unity Shader中参数的方式, 通过这些参数, 我们可以随时调整材质的效果。而这些参数就需要写在Properties语义块中

我们想要在材质面板显示一个颜色拾取器, 从而可以直接控制模型在屏幕上显示的颜色

1
2
3
Properties {
    _Color ("Color Tint", Color) = (1, 1, 1, 1)
}

展开

在这里定义了一个属性_Color, 它的类型是Color, 初始值是(1.0,1.0, 1.0, 1.0), 对应白色

为了在CG代码中可以访问它, 我们还需要在CG代码片段中提前定义一个新的变量, 这个变量的名称和类型必须与Properties语义块中的属性定义相匹配

1731898517840

uniform关键字

uniform 关键词是 CG 中修饰变量和参数的一种修饰词,它仅仅用于提供一些关于该变量的初 始值是如何指定和存储的相关信息(这和其他一些图像编程接口中的 uniform 关键词的作用不太一样)。在Unity Shader 中, uniform 关键词是可以省略的。

uinty提供的内置文件和变量

为了方便开发者的编码过程, Unity 提供了很多内置文件,这些文件包含了很多提前定 义的函数、变量和宏等。 以使用#include 指令把这些文件(后缀是.cginc)包含进来,这样我们就可以使用 Unity 为我们提供的一些非常有用的变量和帮助函数 我们可以从Unity 的应用程序中直接找到CGincludes 文件夹,它包含了所有内置着色器包含文件 1731911513981 1731911522599 1731911527773

CG/HLSL语义

CG/HLSL提供的语义(semantics), 语义实际上就是一个赋给Shader输入和输出的额外字符串(表达了这个参数的含义)。 通俗地讲, 这些语义可以让Shader知道从哪里读取数据, 并把数据输出到哪里,

如果没有这些语义来限定输入和输出参数的话,渲染器就完全不知道用户的输入输出是什么,因此就会得到错误的效果

是系统数值语义(system-valuesemantics)以sv开头的, sv代表的含义就是系统数值(system-value), 这些语义在渲染流水线中有特殊的含义,是不可以随便赋值的, 因为流水线需要使用它们来完成特定的目的, 1732067510752 1732067517184 1732067525784

Debug

普通程序的bug通过传统debug方式解决

opengl和vualkan包含一些内置的调试工具,可以方便我们查看哪里整个渲染流程的语法/遗漏错误

shader中的语法错误,opengl会自动告诉你

还需要手动数据可视化调试,即将数据映射到0–1的范围,作为颜色输出,从而debug模型顶点数据是否正确

// 调试工具脚本:颜色拾取器 在GUI创建box(显示纹理和背景)和label文本(显示rgba) 创建BoxCollider以接收鼠标事件 当鼠标点击OnMouseDown()执行,获取鼠标位置 OnPostRender()每帧执行,渲染屏幕大小纹理,根据鼠标位置从纹理获取颜色 为box应用方形纹理(应用颜色)

本文由作者按照 CC BY 4.0 进行授权
本页总访问量