当前位置:网站首页 > 10B 游戏研究 > 正文

正弦等距线的应用(Unity3D)

评论:0 发布时间: 2019-01-21 浏览: 3015

等距线(正弦函数式)在Unity 3D中的应用

文章将从三个方面介绍等距线的应用。

一、什么是等距线

二、正弦函数式非等距线(Y轴平移)与等距线的差异

三、实际案例,在Unity3D中的应用

四、遇到的小问题


一、什么是等距线?

关于等距线在百度百科有如下解释。  (https://baike.baidu.com/item/%E7%AD%89%E8%B7%9D%E7%BA%BF)

等距线与等距面在CAGD的多个领域中具有应用价值。例如,在数控加工中,刀具的运动轨迹就是加工曲线或曲面的等距线或面,轮船、汽车等的内表面也是外表面的等距面。等距线在公路设计中也有重要的应用。给定平面参数

它的等距线的方程是
这里
  
为等距距离。
图1


二、正弦函数式非等距线(Y轴平移)与等距线的差异

本人在游戏开发过程中,有一个根据正弦生成路径的需求。这个需求数学化来表述一下:

已知 f(x) = ax + b,g(x) = m*sin(2π/T * x) + c;
其中,a,b,m,T,c,d为已知数,x为正整数
原曲线:P(t) = (f(x),g(x))
求P(t)的等距线 Pd(t)。


A)正弦函数式非等距线(Y轴平移)的解:

Pd1(t)= (fd1(x) = ax+b,gd1(x) = m*sin(2π/T * x) + c')

其中:

fd1(x) = ax+b还是原函数

gd1(x) = m*sin(2π/T * x) + c';  (这里的c'不是c的导数),是在Y轴向的固定距离( |c' - c | )的平移。

如下图(2)所示。

下图画的不是很好,需要解释一下。这里平移之后的曲线(Pd1(t))和原曲线(P(t))只是Y轴等距。而真正的等距是目标曲线距离原曲线中【切线的法向上】的等距。

image.png

图(2)


B)正弦函数式等距线的解:

按(一)中根据求等距线的公式,可解。(f'(x) ,g'(x) 均是相应函数的导数)

image.png

∵f(x) = ax + b;

∴f’(x) = a;

∵g(x) = m*sin(2π/T * x) + c;

∴g’(x) = 2mπ/T * cos (2π/T * x);

∵P(t) = (ax + b, m*sin(2π/T * x) + c)

image.png

可以发现,Pd(t)在X轴,Y轴方向上各有平移。


三、实际案例,在Unity3D中的应用(只有代码片段)。

以下代码主要是对roadBoundary数组的处理,该数组存放了生成路边界所需要的点的坐标。有了这个数组之后,可以通过LineRenderer之类的Unity UI组件生成连续的曲线。

    /*
     *  roadBoundary[0, 0 , n] 未定义
     *  roadBoundary[1, 0 , n] 是否放置障碍物
     *  roadBoundary[2, 0 , n] 未定义
     *  roadBoundary[0, 1 , n] 路中间  的[y]坐标
     *  roadBoundary[1, 1 , n] 路上边界的[y]坐标
     *  roadBoundary[2, 1 , n] 路下边界的[y]坐标
     *  roadBoundary[0, 2 , n] 路中间  的[x]坐标
     *  roadBoundary[1, 2 , n] 路上边界的[x]坐标
     *  roadBoundary[2, 2 , n] 路下边界的[x]坐标
     */
    private float[,,] roadBoundary; // 路的边界,数组0为路中间,1为上边界,2为路下边界
    private int T = 12 * 4;//T 为一个周期内点的个数。如12 * 4 个。T/4个周期内有12个点。
    private int totalColumn = T * 3;
    public void init()
    {
        //todo sth else
        roadBoundary = new float[3, 3, totalColumn];
    }
    
    //生成等距线上的点
    private void initRoadBoundary(int start,int _T) {
        for (int index = 0; index < _T; index++){
            int _index = (start + index) % totalColumn;
            //roadStartAt 参考物 
            float nextX = roadStartAt.X + (start + index) * xMoveUnit;
            float nextY = roadStartAT.y + Mathf.Sin(2 * Mathf.PI * index / (T * 1.0f)) * amplitude;

            //f'(x)
            float __x__ = xMoveUnit;
            //g'(x)
            float __y__ = 2 * Mathf.PI * amplitude / (T * 1.0f) * Mathf.Cos(2 * Mathf.PI * index / (T * 1.0f));
            float delta_nextX = -__y__ / Mathf.Sqrt(__x__ * __x__ + __y__ * __y__) * roadWidth; //Δx
            float delta_nextY = __x__ / Mathf.Sqrt(__x__ * __x__ + __y__ * __y__) * roadWidth;  //Δy
            
            roadBoundary[1, 1, _index] = nextY + 1 * delta_nextY;
            roadBoundary[0, 1, _index] = nextY + 0 * delta_nextY;
            roadBoundary[2, 1, _index] = nextY - 1 * delta_nextY;

            roadBoundary[1, 2, _index] = nextX + 1 * delta_nextX;
            roadBoundary[0, 2, _index] = nextX + 0 * delta_nextX;
            roadBoundary[2, 2, _index] = nextX - 1 * delta_nextX;
   
        }
    }
   
    // 渲染等距线
    private Transform[,] roadBoundaryMap;      // 边界Map
    public Transform roadBoundaryUnit;         // 需要注入
    private void initRoadBoundary()
    {
        roadBoundaryMap = new Transform[2, totalColumn];
        float iZ = roadBoundaryUnit.position.z;
        for (int j = 0; j < totalColumn; j++)
        {
            roadBoundaryMap[0, j] = Instantiate(roadBoundaryUnit);
            roadBoundaryMap[1, j] = Instantiate(roadBoundaryUnit);
            roadBoundaryMap[0, j].position = new Vector3(roadBoundary[1, 2, j], roadBoundary[1, 1, j], iZ);
            roadBoundaryMap[1, j].position = new Vector3(roadBoundary[2, 2, j], roadBoundary[2, 1, j], iZ);
        }
    }
    
    private void buildRoad(){
        //根据自己的需求调用。一个周期只能调用一次。N个周期需要调用N次。
        initRoadBoundary(startAt, T);
    }
    
    void Start () {
        init();

        buildRoad();
        
        initRoadBoundary();
    }

以下是在unity3d里面实践的一个效果。

image.png

图(3)

四、遇到的小问题。


如上图(3)所示,我们可以发现,等距线会在X轴也有平移,如果我们在该曲线(正弦曲线)前后加入其他函数的曲线,会存在不方便对接的情况。如上图前后接入直线时,存在不连续或者多个解的情况。

这个我暂时没有更好的办法解决。欢迎探讨。


TAGS:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

Copyright 52weixue.com.All Rights Reserved. 苏ICP备12000545号-4