[Unity 学习] - 基础篇 - 数学表面

[Unity 学习] - 基础篇 - 数学表面

放牛的星星老师的《Unity基础教程》:
原文链接: https://zhuanlan.zhihu.com/p/346943226

1 自定义一个函数库并加载到项目中

自定义一个FunctionLibrary C#脚本,这个脚本就是我们的类库,它只是一个存放数据或者是方法的脚本,不是一个组件所以不需要继承自Monobehaviour,为了表示不将该类用作对象模板,可以通过在类之前编写static关键字将其标记为static。

1.1 Library类

using UnityEngine;
public static class FunctionLibrary
{
}

1.2 功能方法

首先我们将上一章的正弦函数进行封装

public void Wave(){}

但这样是错误的,原因是因为C#类中所有默认的函数成员都是实例成员,也就是需要使用实例化的对象进行调用,但是我们的类是一个静态类,今天类是不是实例化对象的,换句话说就算你定义了他,他也永远不会的调用,当然,这个时候,你的编译器已经开始报错了。所以我们需要将这个函数定义为静态函数;

public static void Wave(){}

然后我们发现这个函数是需要返回值的,而且需要传入一些参数进行计算
完整代码:

using UnityEngine;
//静态类中不能声明静态成员
public static class FunctionLibrary
{
    //正弦波
    public static float Wave(float x, float t)
    {
        return Mathf.Sin(Mathf.PI * (x + t));
    }
}

1.3 隐式使用Type

这里提一个小技巧,当我们需要频繁提及其他类时,可以使用using static <类名> 使得该类型的所有常量以及静态成员都可用("…"表示这部分代码没改动,懒得复制了)

using UnityEngine;
using static UnityEngine.Mathf;
....
		return Sin(PI * (x + t));

1.4 一个更复杂的函数

我们将两个正弦函数叠加在一起,但是第二正弦函数的波长是原来的两倍,同时我们将该函数的结果减半(当然,这是教程中的例子,我们可以搞出更多好玩的例子,可以自己试试),由于正弦函数的max/min值是[-1,1],所以我们将总和 / 1.5f。除法运算比乘法运算需要更多的工作,但是编译器可以将常量表达式简化为一个值,所以又可以用(2f / 3f)进行优化代码。

public static float MultiWave(float x, float t)
{
    float y = Sin(PI * (x + t));
    y += Sin(2f * PI * (x + t)) * 0.5f;
    return y * (2f / 3f);
}

两个正弦波的和

1.5 在编译器下选择函数

我们使用变量function来控制Update中使用函数情况

    [Range(0, 1)]
    public int function = 0;

使用滑块控制函数
使用if-else语句控制调用函数

            if(function == 0)
            {
                position.y = FunctionLibrary.Wave(position.x, time);
            }
            else
            {
                position.y = FunctionLibrary.MultiWave(position.x, time);
            }

1.6 一个更更复杂的函数

现在我们往函数库里面添加第三个函数,这个函数可以使正选波远离远点而不是始终沿着相同方向传播。我们首先使用Mathf.Abs函数,使其左右对称,我们使用y = sin(4πd)和d = |x|,根据中学知识可以理解4π会影响的只有频率,4π就代表着将一个sin图形压缩1/4。代码中我使用的6π也是一个道理

    public static float Ripple(float x,float t)
    {
        float d = Abs(x);
        float y = Sin(PI * (6f * d ));
        return y;
    }

这时我们会发现Y值的变换很大,我们可以使博人随距离而减小,最后加上减去时间πt

    public static float Ripple(float x,float t)
    {
        float d = Abs(x);
        float y = Sin(PI * (6f * d - t));
        return y/(1f + 10f * d);
    }

请添加图片描述

2 管理方法

使用委托数组将函数统一管理,使用枚举将所有函数名罗列出来


    public enum FunctionName { Wave,MultiWave,Ripple }

    //函数库中的数据很多时候都已经设计好了,使用的时候直接调用
    //在编写函数库的时候,直接将其自定义好
    static Function[] functions = { Wave, MultiWave, Ripple};

    public static Function GetFunction(FunctionName name)
    {
        return functions[(int)name];
    }
void Update()
    {
        FunctionLibrary.Function f = FunctionLibrary.GetFunction(function);
		...
            position.y = f(position.x, time);
          	...
    }

3 使用另一个维度

现在,我们将二维的空间改为三维空间进行计算

3.1 3D颜色值

在Z不再恒定的情况下,更改点Point Surface,通过从赋值中删除.rg和.xy代码来修改蓝色反照率分量。

surface.Albedo = input.worldPos * 0.5 + 0.5;

在这里插入图片描述

3.2 对三个代码进行修改,得到一些好玩的效果

 public static float Wave(float x, float z, float t)
    {
        return Sin(PI * (x + z + t));
    }
    //多个正弦波
    public static float MultiWave(float x, float z, float t)
    {
        float y = Sin(PI * (x + 0.5f * t));
        y += Sin(2f * PI * (z + t)) * 0.5f;
        y += Sin(PI * (x + z + 0.25f * t));
        // 乘法运算胜于除法运算,编译器可以将常量表达式简化为单个数字
        return y * (1f / 2.5f);
    }
    public static float Ripple(float x, float z, float t)
    {
        float d = Sqrt(x * x + z * z);
        float y = Sin(PI * (4f * d - t));
        return y/(1f + 10f * d);
    }

结尾

本章后面的就是一些数学公式了,和Unity的学习关系不大了。
这里说一些题外话吧,我写这个系列更多的希望勉励自己能够坚持将大佬的这个系列的文章学完,如果有人正好看到这几篇文章,如果你想更好的学习,可以直接去大佬的知乎或者是原网站看CatLike教程,不过个人英语不好,所以选择在放牛的星星大佬这这里看翻译好的文章。
数学部分我就不在这里记录了,会自己私下写一些笔记,毕竟这只是一个Unity的笔记(个人有些强迫症,明知道是一个东西,还是想分开写doge)。

猜你喜欢

转载自blog.csdn.net/qq_43617207/article/details/127629661
今日推荐