笔记 - Basics02 - Building a Graph - Visualizing Math

原文链接

1 Creating a Line of Cubes

新建一个 Cube,将其做成 prefab。

新建脚本 Graph.cs,附在空物体 Graph 上。代码如下:

using UnityEngine;
public class Graph : MonoBehaviour
{
    [SerializeField] // 在编辑器中拖动 prefab 为其赋值
    Transform pointPrefab = default; 

    void Awake ()
    {
        var position = Vector3.zero;
        var scale = Vector3.one / 5f;
        for (int i = 0; i < 10; ++i)
        {
            Transform point = Instantiate(pointPrefab);
            position.x = (i + 0.5f) / 5f - 1f;      // 控制10个方块在x方向上填满x轴上 [-1, 1] 的空间
            position.y = position.x * position.x;   // y 关于 x 的函数
            point.localPosition = position;
            point.localScale = scale;
        }
    }
}

2 Creating More Cubes

修改代码,使得方块数量在编辑器中可调整,而不是固定 10 个。

知识点:

  • [Range(10, 100)]

  • Transform.SetParent

    public void SetParent (Transform p);

    public void SetParent (Transform parent, bool worldPositionStays);

Graph.cs 代码如下:

using UnityEngine;
public class Graph : MonoBehaviour
{
    [SerializeField] // 在编辑器中拖动 prefab 为其赋值
    Transform pointPrefab = default;

    // Range 属性使得该变量在编辑器中变成滑条,并且可以控制范围
    // 注意该范围只是限制了编辑器中的修改,除此之外对其大小不做限制
    [SerializeField, Range(10, 100)]
    int resolution = 10;

    void Awake ()
    {
        float step = 2f / resolution;   // 方块的边长
        var position = Vector3.zero;
        var scale = Vector3.one * step;
        for (int i = 0; i < resolution; ++i)
        {
            Transform point = Instantiate(pointPrefab);
            position.x = (i + 0.5f) * step - 1f;    // 控制方块在x方向上填满x轴上 [-1, 1] 的空间
            position.y = position.x * position.x;   // y 关于 x 的函数
            point.localPosition = position;
            point.localScale = scale;
            // 将新实例化的方块作为 Graph 的子物体
            // 第 2 个参数决定是否保持与子物体之前相同的世界空间位置、旋转和缩放
            point.SetParent(transform, false);
        }
    }
}

3 Coloring the Graph

创建一个自定义 shader:

Create one via Assets / Create / Shader / Standard Surface Shader and name it Point Surface.

shader 的代码如下:

Shader "Graph/Point Surface"
{
    Properties{
        // 让 Smoothness 出现在编辑器的 Material 中
        _Smoothness("Smoothness", Range(0,1)) = 0.5
    }

    SubShader
    {
        CGPROGRAM
        #pragma surface ConfigureSurface Standard fullforwardshadows
        #pragma target 3.0

        struct Input
        {
            float3 worldPos;
        };
        
        float _Smoothness;
        
        void ConfigureSurface(Input input, inout SurfaceOutputStandard surface)
        {
            // 颜色中的 r g 由世界坐标确定
            surface.Albedo.rg = input.worldPos.xy * 0.5 + 0.5;
            // 光滑度
            surface.Smoothness = _Smoothness;
        }
        ENDCG
    }

    Fallback "Diffuse"
}

3.3 Universal Render Pipeline

上面的 shader 适用于 default render pipeline

导入 Universal RP 包即可使用 URP。We first have to create an asset for it, via Assets / Create / Rendering / Universal Render Pipeline / Pipeline Asset (Forward Renderer).This will also automatically create another asset for a renderer, in my case named URP_Renderer.

Next, go to the Graphics section of the project settings and assign the URP asset to the Scriptable Renderer Pipeline Settings field.

新建 shader graph:via Assets / Create / Shader / PBR Graph and name it Point URP. PBR stands for physically-based rendering.

在 shader graph 中通过构造节点可以达到与上一节的 shader 代码类似的效果,具体操作参考原文。

4 Animating the Graph

修改 Graph.cs,使得方块展示一条随时间移动的正弦曲线。

知识点:

  • 数组的声明与实例化

代码如下:

using UnityEngine;
public class Graph : MonoBehaviour
{
    [SerializeField] // 在编辑器中拖动 prefab 为其赋值
    Transform pointPrefab = default;

    // Range 属性使得该变量在编辑器中变成滑条,并且可以控制范围
    // 注意该范围只是限制了编辑器中的修改,除此之外对其大小不做限制
    [SerializeField, Range(10, 100)]
    int resolution = 10;

    Transform[] points; // 声明数组

    private void Awake ()
    {
        float step = 2f / resolution;   // 方块的边长
        var position = Vector3.zero;
        var scale = Vector3.one * step;
        points = new Transform[resolution]; // 实例化数组
        for (int i = 0; i < points.Length; ++i)
        {
            Transform point = Instantiate(pointPrefab);
            position.x = (i + 0.5f) * step - 1f;    // 控制方块在x方向上填满x轴上 [-1, 1] 的空间
            point.localPosition = position;
            point.localScale = scale;
            // 将新实例化的方块作为 Graph 的子物体
            // 第 2 个参数决定是否保持与子物体之前相同的世界空间位置、旋转和缩放
            point.SetParent(transform, false);
            points[i] = point;  // 把方块放进数组
        }
    }

    private void Update()
    {
        float time = Time.time; // 优化代码,防止每一轮循环都调用一次
        for (int i = 0; i < points.Length; ++i)
        {
            Transform point = points[i];
            Vector3 position = point.localPosition;
            position.y = Mathf.Sin(Mathf.PI * (position.x + time));   // y 关于 x 的函数
            point.localPosition = position;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值