持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情。
你可以简单浏览一下目录,有需要的阅读,写文章不易,阅读之前请给我点个赞吧~
本文为Mathematical Surfaces的译文,添加个人理解与创作,逐步带你实战 Unity shader。
这个部分主要讲述下面的内容:
其中上篇讲述
- 为曲线着色
- 让曲线动起来
- 创建一个函数库。
中篇讲述
- 使用委托(delegate)和枚举(enumeration)类型。
下篇讲述
- 用网格(grid)显示 2D 函数。
- 在 3D 空间中定义曲面。
这是关于学习使用Unity的基础知识的系列教程的第三个教程。这是构建舞动的曲线教程的延续,所以我们不会开始一个新的项目,在上一个项目上继续开发。这一次,我们将使显示多个更复杂的函数成为可能。
我们先接着上回说到的继续。
为了使光滑度这个配置选项出现在编辑器中,向上面我们必须在着色器的顶部,子着色器的上方添加一个Properties 块。在这里写入 _Smoothness,后面跟着("Smoothness", Range(0,1)) = 0.5。这赋予它Smoothness标签,将其作为一个范围为 0-1 的滑块,并将其默认值设置为0.5。
Shader "Graph/Point Surface" {
Properties {
_Smoothness ("Smoothness", Range(0,1)) = 0.5
}
SubShader {
…
}
}
让我们的立方体预制(prefab)资产使用这种材料,而不是默认的一个,这会使点变黑。
一、基于世界坐标的着色
为了调整点的颜色,我们必须修改 surface.Albedo。由于反照率(Albedo)和世界坐标都有三个组成部分,我们可以直接使用位置来表示反照率。其中 Albedo 在拉丁语中的意思是白色。这是一种测量光被表面漫反射的量的方法。如果反照率不是完全白色,那么部分光能被吸收而不是被反射。
void ConfigureSurface (Input input, inout SurfaceOutputStandard surface) {
surface.Albedo = input.worldPos;
surface.Smoothness = _Smoothness;
}
现在世界 X 坐标控制着点的红色成分,Y 坐标控制着绿色成分,Z 坐标控制着蓝色成分。但是我们的图的 X 域是[−1,1],负颜色分量没有意义。所以我们必须将位置减半,然后加上 1/2 ,使颜色符合定义域。我们可以同时对这三个维度做这个。
surface.Albedo = input.worldPos * 0.5 + 0.5;
我们记录一下之前的笑脸代码,因为之后要绘制其他曲线了
using UnityEngine;
public class Graph : MonoBehaviour
{
[SerializeField]
Transform pointPrefab;
[SerializeField, Range(10, 100)]
int resolution = 10;
//笑脸
void Awake()
{
var position = Vector3.zero;
var position2 = Vector3.zero;
var position3 = Vector3.zero;
float step = 2f / resolution;
var scale = Vector3.one * step;
for (int i = 0; i < resolution; i++)
{
Transform point = Instantiate(pointPrefab);
position.x = (i + 0.5f) * step - 1f;
position.y = position.x * position.x;
point.localPosition = position;
point.localScale = scale;
Transform point2 = Instantiate(pointPrefab);
position2.x = (i + 0.5f) * step - 2f;
position2.y = -1 * position2.x * position2.x - 2 * position2.x + 1;
point2.localPosition = position2;
point2.localScale = scale;
Transform point3 = Instantiate(pointPrefab);
position3.x = (i + 0.5f) * step;
position3.y = -1 * position3.x * position3.x + 2 * position3.x + 1;
point3.localPosition = position3;
point3.localScale = scale;
point.SetParent(transform);
point2.SetParent(transform);
point3.SetParent(transform);
}
}
}
为了更好地了解颜色是否正确,让我们更改 Graph.Awake。所以我们展示函数 这使得Y 也从 −1 到 1。
position.y = position.x * position.x * position.x;
结果是浅蓝色的,因为所有立方体面的 Z 坐标都接近零,这使得它们的蓝色分量接近 0.5。在设置反照率时,我们可以通过只包括红色和绿色通道来消除蓝色。这可以在着色器中通过只分配给 surface.Albedo.rg,并且只使用 input.worldPos.xy。这样蓝色分量就保持为零。
下面是常见的颜色对应的 RGB 值。
| RGB成分 | |||
|---|---|---|---|
| 颜色 | Red(红色) | Green(绿色) | Blue(蓝色) |
| Black(黑) | 0 | 0 | 0 |
| White(白) | 1 | 1 | 1 |
| Red(红) | 1 | 0 | 0 |
| Green(绿) | 0 | 1 | 0 |
| Blue(蓝) | 0 | 0 | 1 |
| Yellow(黄) | 1 | 1 | 0 |
surface.Albedo.rg = input.worldPos.xy * 0.5 + 0.5;
由于红色加绿色的结果是黄色,这将使点在左下方接近黑色,也可以根据上面的表格进行颜色分析。当Y最初增长快于X时变成绿色,当X赶上时变成黄色,当X增长快时变成微橙色,最后在右上方接近亮黄色结束。