Hi, nice to meet you!

Rust 基础 | 所有权

什么是所有权

Rust 的所有权,是 Rust 语言的一个核心概念。可以简单理解为,一种内存管理的方式。用现实中的东西举例,当你从图书管借了一本书时,这本书的所有权暂时归你所有,而当你把书给你的朋友时,此刻,书的所有权归你的朋友所有,而当你的朋友把书归还图书馆时,此时没有人拥有书的所有权,相当于内存释放。

在使用有自动垃圾回收(GC)的编程语言时,我们并不需要考虑内存的释放问题,因为GC会帮我们释放。Rust是无GC的语言,一个变量占用的内存什么时候释放,由它的所有权决定,简单来说,当所有权所在的作用域结束时,内存将被释放。

Rust 基础 | 所有权

Rust 基础 | 基本语法

1. 变量和可变性

Rust 定义一个变量默认是不可变的,这一点与其他编程语言不同。

let x = 10;
x = 11; // 这里会编译出错,

如果要定义可变量,需要使用 mut

let mut x = 10;
x = 11;

用 let 先定义一个变量,再次用 let 定义一个变量,会将之前的变量覆盖,虽然同名,但也不是原来的变量了,这叫做 Shadowing

let x = 10;
let x = "Hello";

常量的定义使用 const,常量是永远不会变的量,常量必须在定义的时候注明数据类型

const MAX_SCORE: i32 = 10000;
Rust 基础 | 基本语法

Unity Shader | 半兰伯特、高光反射、BlinnPhone

写 Shader,到底是在做什么?Shader 就像一个拥有魔法的黑箱,我们最终从它那里得到的,是像素的颜色。而得到的是什么样的像素颜色,则取决于我们丢进黑箱里的是什么东西,以及使用的魔法咒语是什么。丢进同样的东西,使用不同的魔法咒语,得到的像素颜色也是不一样的。输入顶点的坐标,光线方向,以及自定义的颜色,使用不同的计算方式,得到的像素颜色是不一样的。使用同样的计算方式,丢进一个纯色颜色值,和丢进一张纹理,得到的像素,也是不一样的。

如果把整个 Shader 比作一个函数,那么顶点位置,自定义的颜色值,纹理,灯光等这些就相当于函数的输入参数,而 Shader 中写的各种计算,用的各种算法,都是对输入的那些参数进行操作,而最终生成的,就是颜色值,也就是相当于函数的返回值。把 Shader 想的简单一点,就是输入需要的东西,进行计算,得到像素值。

这篇博客,还是关于光照模型的,接下来我们首先总结一下常用的光照模型。

Unity Shader | 半兰伯特、高光反射、BlinnPhone

Unity Shader | 光照模型和漫反射

在之前的文章中写的Shader,呈现出来的物体样子是一个平面2D的状态,即使物体是3D的,那是因为,我们还没有将灯光加入到Shader的运算中。现在,我们将介绍灯光相关的东西,最后呈现出和 Unity Diffuse Shader 一样的效果。

什么是光照模型

光照模型,简单理解就是一种运算,或者说一个公式,计算的结果,决定了一个点受到光照时,所表现出来的效果。例如,光照在木板上,和照在一面镜子上,我们所看到的效果是不一样的,照在镜子上,很大一部分光会被镜子反射,而木板,却不会反射那么多光。

Unity Shader | 光照模型和漫反射

Unity UGUI RGB通道分离抖动

今天我们要在 UGUI 上实现图片RGB通道分离抖动效果,先看最终效果图

Unity UGUI RGB通道分离抖动

Unity Shader | 使用Struct传递数据

上一篇博客 说了在 CGPROGRAM 中写代码、顶点处理函数、片元处理函数、以及在两个函数之间传递简单的数据、从 ShaderLab 属性到CG数据类型之间的联系等。这一篇博将稍详细一点说一下 Shader 的基本知识,以及在顶点和片元函数之间传递更多的数据。

Shader的基本理解

简单来说,Shader 决定了一个模型最终呈现在屏幕上的样子。一个模型由很多顶点构成,而每一个顶点,都会经过 Shader 中的顶点处理函数,这个过程,就是从应用将数据传递到顶点处理函数,顶点函数需要将顶点从模型空间转换到屏幕空间,或者说是裁剪空间,也可以简单理解为从 3 维空间转换到屏幕上的 2 维空间。在这个过程中,还可以做一些其他对顶点的操作。

顶点数据经过顶点处理函数处理后,接下来就返回,然后传给片元处理函数,到了这一步,面对的,就是像素,也就是每一个像素的颜色值。在这里,可以根据自己的需求,对每一个像素做处理,例如做高斯模糊,RGB通道分离,等等,各种各样的效果。

Unity Shader | 使用Struct传递数据

Unity Shader | 属性、顶点与片元函数

上一篇博客 介绍了Shader的基本结构,这里我们继续来说Shader的编写,也就是要在 CGPROGRAM 中写代码。首先我们把之前的Shader结构代码复制过来。

Shader "iMoeGirl/MyShader" {  // Shader 名字

// 这里定义一些属性,可以显示在UI面板上用于调节
Properties {
// 属性名("Inspector面板上显示出来的属性名", 属性类型) = 默认值
_Color("颜色类型", Color) = (1,1,1,1)
_Vector("向量类型", Vector) = (1, 2, 3, 4)
_Int("整型", Int) = 11111
_Float("浮点型", Float) = 12.11
_Range("范围类型", Range(100, 1000)) = 128
_Tex2D("贴图类型", 2D) = "white"{}
_Cube("立方体贴图类型", Cube) = "white"{}
_Tex3D("3D纹理", 3D) = "white"{}
}

// 子 Shader,可以写多个,显卡运行时,
// 从第一个SubShader开始,如果第一个里面的效果都支持,则使用第一个,
// 如果发现这个SubShader里面某些效果不支持,则自动运行下一个SubShader
SubShader {

// 至少有一个Pass,相当于一个方法
Pass {
// 在Pass块里写Shader代码

CGPROGRAM
// 使用 CG语言编写Shader
ENDCG
}
}

// 如果发现所有的SubShader都不支持,则使用Fallback,相当于后备方案
Fallback "VertexLit"
}

怎样使用 Properties 中定义的属性

Unity3D定义Shader属性所使用的语法,和CG所使用的说法是不一样的,所以我们要在一个Pass中使用Properties中定义的属性,需要在Pass中再以CG的语法再写一遍,其实就是变量名相同,而数据类型不同,在Shader在编译的时候,就会自动将两个变量关联起来。看下面的代码

Unity Shader | 属性、顶点与片元函数