2016-09-01 5 views
0

Я хочу нарисовать гладкие * и случайные пути, по которым мои объекты будут следовать, и я решил пойти с квадратичными кривыми Безье (но я открыт для других идей).Рисунок случайных путей с квадратичными кривыми Безье

Мой код перемещает мои объекты в случайном, но негладком * пути.

Preview: https://youtu.be/Eg9PEKuH4zA

Мой вопрос: как я могу сделать изменения направления гладко? Должен ли я полностью отказаться от решения Безье или есть способ, которым я мог бы отполировать свой код, чтобы добиться того, чего хочу?

* гладкие == не крутая направление не меняется

Мой код:

using UnityEngine; 
using System.Collections; 
using System.Collections.Generic; 

public class Lights : MonoBehaviour { 
    public float paintHeight = -90.0f; 
    public static int NUMBER_OF_LIGHTS = 3; 
    private static int BEZIER_PATH_POINTS = 100; 
    private float GOLDEN_COLOR_RATIO = 0.618033988749895f; 
    private Light[] lights = new Light[NUMBER_OF_LIGHTS]; 

    Vector3 RandomPoint() { 
     float obj_width = gameObject.GetComponent<RectTransform>().rect.width; 
     float screenX = Random.Range(-obj_width/2, obj_width/2); 

     float obj_height = gameObject.GetComponent<RectTransform>().rect.height; 
     float screenY = Random.Range(-obj_height/2, obj_height/2); 

     return new Vector3(screenX, screenY, -paintHeight); 
    } 


    Vector3 QuadraticBezierPoint(Vector3 startPoint, Vector3 endPoint, Vector3 vertexPoint, float t) { 
     /* 
     *   vertex 
     *  /╲ 
     *  / ╲ 
     * /p ╲ 
     * /. . ╲ 
     * /.  · ╲ 
     * /·   · ╲ 
     * start   · end 
     * 
     * 0 < t < 1 
     * 
     * B(t) = (1 - t)^2 * P0 + 2 * (1-t) * t * P1 + t^2 * P2 
     * 
     */ 
     return Mathf.Pow((1 - t), 2) * startPoint + 2 * (1 - t) * t * vertexPoint + Mathf.Pow(t, 2) * endPoint; 
    } 

    Color RandomColor() { 
     float h = Random.Range(0.0f, 1.0f) + GOLDEN_COLOR_RATIO; 
     h %= 1; 
     return Color.HSVToRGB(h, 0.99f, 0.99f); 
    } 

    void Start() { 
     for (int i = 0; i < NUMBER_OF_LIGHTS; i++) { 
      GameObject light_obj = new GameObject(); 
      Light light = light_obj.AddComponent<Light>(); 
      light.type = LightType.Point; 
      light.range = 10.0f; 
      light.intensity = 3.5f; 
      light.renderMode = LightRenderMode.ForcePixel; 
      light.name = "Light" + i; 
      light.transform.parent = gameObject.transform; 
      lights[i] = light; 
     } 

     StartCoroutine("Move"); 
    } 

    IEnumerator Move() { 
     Dictionary<string, Vector3>[] light_points = new Dictionary<string, Vector3>[NUMBER_OF_LIGHTS]; 
     Dictionary<string, Color>[] light_colors = new Dictionary<string, Color>[NUMBER_OF_LIGHTS]; 
     for (int i = 0; i < NUMBER_OF_LIGHTS; i++) { 
      light_points[i] = new Dictionary<string, Vector3>(); 
      light_colors[i] = new Dictionary<string, Color>(); 
      //light_points[i]["startPoint"] = RandomPoint(); 
      //light_points[i]["vertexPoint"] = RandomPoint(); 
      light_points[i]["endPoint"] = RandomPoint(); 
      light_colors[i]["nextColor"] = RandomColor(); 
     } 

     while(true) { 
      for (int i = 0; i < NUMBER_OF_LIGHTS; i++) { 
       light_points[i]["startPoint"] = light_points[i]["endPoint"]; 
       light_points[i]["vertexPoint"] = RandomPoint(); 
       light_points[i]["endPoint"] = RandomPoint(); 

       light_colors[i]["currentColor"] = light_colors[i]["nextColor"]; 
       light_colors[i]["nextColor"] = RandomColor(); 
      } 

      for (int i = 0; i < BEZIER_PATH_POINTS; i++) { 
       float percent = (float)i/BEZIER_PATH_POINTS; 
       for (int j = 0; j < NUMBER_OF_LIGHTS; j++) { 
        lights[j].transform.localPosition = QuadraticBezierPoint(
         light_points[j]["startPoint"], 
         light_points[j]["endPoint"], 
         light_points[j]["vertexPoint"], 
         percent 
        ); 
        lights[j].color = Color.Lerp(light_colors[j]["currentColor"], light_colors[j]["nextColor"], percent); 
       } 
       yield return new WaitForSeconds(0.02f); 
      } 
     } 
    } 
} 
+0

Ваше видео действительно не помогает, это рассеянное освещение, движущееся на отвлекающем фоне, что делает невозможным рассказать, какой путь отслеживается. Начните с описания фактической проблемы: одиночные кривые являются гладкими, и проблема, которая идет от одной кривой к следующей, не является гладкой? Если это так, то решение гарантирует G1 или даже непрерывность G2, для которых луч более высокого порядка лучше, как кубическая кривая. И в этот момент кривые Catmul-Rom имеют еще больший смысл, поскольку они проходят через определяемые вами точки (каждый раздел на кривой тривиально преобразуется в форму Безье) –

ответ

1

Если у вас есть кривая, идущую от А к В с некоторой средней точкой, вы должны выбрать C соответственно так что угол (A, B, C) в B не слишком мал или слишком велик.

Кроме того, вам необходимо будет выбрать средние точки соответствующим образом, см., Например, https://www.particleincell.com/2012/bezier-splines/, так что изменение направления не слишком велико.

0

Вы можете пройти весь путь до использования NURBS или другого сплайна, но, вероятно, есть более простой, эквивалентный способ получить гладкие кривые, учитывая то, что вы разместили.

Каждая кривая, которую вы создаете, имеет 3 точки, в начале кода, вершине и конце. Позволяет называть их S, V и E. Кроме того, давайте посмотрим на них через время, поэтому {S0,V0,E0} сделать первую кривую, {S1,V1,E1} сделать вторую кривую и так далее.

Прямо сейчас, вы гарантируете, что S1=E0, S2=E1 и т. Д. Это означает, что ваши огни не скачкообразно скачутся, но при переключении кривых Безье движение может быть резким.

Для обеспечения плавного движения убедитесь, что S1 = E0 = 0.5 * (V0+V1). На практике это означает, что вы произвольно генерируете S0 и V0. Затем для каждой новой кривой вы создаете новый V, а средняя точка между старым V и новым V является точкой разрыва кривой.

Это эквивалентно наличию равномерной степени 2 B-сплайна.

Вот пример кода, который может быть иллюстративным.

// initialize with randomness 
// we need a previous v and a current v for the first iteration 
// So, the first start point will be halfway between these two points 
prev_v = random_point() 
v = random_point() 

while(true) 
{ 
    next_v = random_point() 
    s = 0.5 * (prev_v + v) // s is halfway between prev_v and v 
    e = 0.5 * (v + next_v) // e is halfway between v and next_v 
    yield_movement_bezier(s, v, e) 

    // prep for next iteration 
    prev_v = v 
    v = next_v 
} 
+0

Я не думаю, что это сработает. https://ibin.co/31dRdvQTxJDw.jpg – alexandernst

+0

Итак, на вашей диаграмме E0 должен находиться в середине V0 и V1. И при таком подходе вы не произвольно не генерируете никаких дополнительных значений E, а только значений V. Я добавлю псевдокод, чтобы попытаться уточнить. – tfinniga

Смежные вопросы