Unity | Shader基础知识(第五集:案例<小彩球>)

目录

一、本节介绍

[1 上集回顾](#1 上集回顾)

[2 本节介绍](#2 本节介绍)

二、原理分析

[1 现实中出现彩色的原因](#1 现实中出现彩色的原因)

[2 软件里的彩色的原理](#2 软件里的彩色的原理)

[3 方案](#3 方案)

[三、 实现数字由【-1,1】映射为【0,1】](#三、 实现数字由【-1,1】映射为【0,1】)

[1 结论](#1 结论)

[2 原理](#2 原理)

四、代码实现

[1 注意事项](#1 注意事项)

[2 详解结构体appdata_base](#2 详解结构体appdata_base)

[3 接收数据](#3 接收数据)

[4 映射数据](#4 映射数据)

[5 输出给SV_TARGET](#5 输出给SV_TARGET)

五、全部代码

六、下集介绍


一、本节介绍

1 上集回顾

上节课我们学到,Shader的结构体。

2 本节介绍

这节课我们要根据之前所学的所有语法,制作一个彩色的小球(如图一所示)。
图1 彩色的小球

二、原理分析

1 现实中出现彩色的原因

这种颜色我们经常会在彩虹身上发现,原因就是光的折射(初中物理知识),换句话说,就是光的方向不同,不同方向的光射入到人的眼睛里组合成了不同的颜色。

2 软件里的彩色的原理

我们只需要输出不同的连续数据的颜色就可以了。

3 方案

光射到物体上会被反射(如图2所示),在光线中间的位置,画一条线,我们叫它法线。
图2 反射光线和法线

当光线照射在球体上时(如图3所示):

图3 球体上的法线方向各不相同

结论:球体上的法线刚好是连续的从向量(-1,-1,-1)到(1,1,1)的值。

我们输出的颜色的值,是0到1之间,那我们只需要让-1到1,等比变成0到1就可以了。

例:

如果是-1,输出0

如果是0,输出0.5

如果是1,输出1

以此类推。

这个关系叫做映射

三、 实现数字由【-1,1】映射为【0,1】

1 结论

我们只需要先除以2,再加0.5,就可以实现映射

2 原理

a. 因为【-1,1】的距离是2,【0,1】的距离是1,所以如果我们拿到【-1,1】中的其中一个数,先除以2,就可以让他们比例相同。

b. 【-1,1】除以2,就会变成【-0.5,0.5】

c. 这时,我们给【-0.5,0.5】都加上0.5,范围就会变成【0,1】

四、代码实现

代码接着上集写的。

1 注意事项

之前是最后传了一个颜色,不管哪个点,都显示一个颜色,这次是每个顶点需要不同的颜色。

2 详解结构体appdata_base

结构体预览:

cs 复制代码
struct appdata_base {
    float4 vertex : POSITION;       //顶点坐标
    float3 normal : NORMAL;         //法线
    float4 texcoord : TEXCOORD0;    //第一纹理坐标
    UNITY_VERTEX_INPUT_INSTANCE_ID  //ID信息
};

如果我们声明了这个结构体,这个结构体会自带值,这个值就是后面的语义里所带的值。

cs 复制代码
appdata_base vert(appdata_base v)
            {
            }

如果我们改变了这个结构体,在把它return出去,改变的值就会自己输出到后面的语义里,进行下一轮计算。

cs 复制代码
appdata_base vert(appdata_base v)
            {
            //我们在这里把顶点坐标改成了屏幕坐标,传回了appdata_base里
            v.vertex =UnityObjectToClipPos(v.vertex);

            //因为最后return了,所以v.vertex会被语义POSITION接收
            return v;
            }

到此,我们的顶点计算就完成了,也输出给了POSITION。

3 接收数据

改完顶点坐标,我们又进入了片元着色器。

因为我们在顶点着色器里修改的值,实际上是储存在语义里了,我们再次声明也是从语义里接收数据,所以我们只需要再次声明appdata_base,我们就可以接收到顶点着色器中修改过的数据。

4 映射数据
  • 声明float3用来接收数学修改过的数据。
cs 复制代码
 float4 frag(appdata_base v):SV_TARGET
            {
            float3 n;
            }
  • 按照之前的数学知识,把法线映射成【0,1】的数据,存在上面的代码n中
cs 复制代码
 float4 frag(appdata_base v):SV_TARGET
            {
                                    //因为你是一组数,不是一个数,所以不能直接加0.5
            float3 n = v.normal/2+float3(0.5,0.5,0.5);
            }
5 输出给SV_TARGET

此时,我们每一个顶点,对应着一个法线,

每一个法线值,会映射成不同的【0,1】之间的值,

我们把这个值输出出去。

由于,我们SV_TARGET是float4,我们需要补一个值

备注:在CG语言中,补一个值就直接括号后面加一个值就可以

cs 复制代码
 float4 frag(appdata_base v):SV_TARGET
            {
                                    //因为你是一组数,不是一个数,所以不能直接加0.5
            float3 n = v.normal/2+float3(0.5,0.5,0.5);
            
                        //n是float3,但返回的是float4,所以后面补一个1
            return float4(n,1);
            }

最后,保存,上材质,我们就得到一个彩色的球啦。

五、全部代码

cs 复制代码
Shader "Custom/001"
{
SubShader
    {
        pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include"UnityCG.cginc"

            appdata_base vert(appdata_base v)
            {
            v.vertex =UnityObjectToClipPos(v.vertex);
            return v;
            }

            float4 frag(appdata_base v):SV_TARGET
            {
                                    //因为你是一组数,不是一个数,所以不能直接加0.5
            float3 n = v.normal/2+float3(0.5,0.5,0.5);

            return float4(n,1);
            }

            ENDCG
        }
    }
}

六、下集介绍

本集讲了如何制作一个小彩球。

下集讲语法,如何加入外部资源。

相关推荐
June bug8 小时前
【领域知识】休闲游戏一次发版全流程:Google Play + Apple App Store
unity
星夜泊客11 小时前
C# 基础:为什么类可以在静态方法中创建自己的实例?
开发语言·经验分享·笔记·unity·c#·游戏引擎
dzj202112 小时前
PointerEnter、PointerExit、PointerDown、PointerUp——鼠标点击物体,则开始旋转,鼠标离开或者松开物体,则停止旋转
unity·pointerdown·pointerup
心前阳光13 小时前
Unity 模拟父子关系
android·unity·游戏引擎
在路上看风景16 小时前
26. Mipmap
unity
咸鱼永不翻身18 小时前
Unity视频资源压缩详解
unity·游戏引擎·音视频
在路上看风景18 小时前
4.2 OverDraw
unity
在路上看风景19 小时前
1.10 CDN缓存
unity
ellis19701 天前
Unity插件SafeArea Helper适配异形屏详解
unity
nnsix1 天前
Unity Physics.Raycast的 QueryTriggerInteraction枚举作用
unity·游戏引擎