2011-09-01 17 views
5

En realidad, estoy teniendo varias preguntas relacionadas con el tema dado en el título del tema.¿Usar ruido Perlin para crear un rayo?

Ya estoy usando las funciones de Perlin para crear un rayo en mi aplicación, pero no estoy muy contento con mi implementación.

Las siguientes preguntas se basan en las implementaciones iniciales y mejoradas de Perlin noise.

Para simplificar el problema, supongamos que estoy creando un rayo 2D simple al modular la altura de una línea horizontal que consta de N nodos en estos nodos usando una función 1D Perlin.

  1. Por lo que he entendido, dos valores posteriores pasados ​​a la función Perlin deben diferir en al menos uno, o los dos valores resultantes serán idénticos. Esto se debe a que con la simple implementación de Perlin, la función Random funciona con un argumento int, y en la implementación mejorada los valores se asignan a [0..255] y luego se utilizan como índice en una matriz que contiene los valores [0..255 ] en una distribución aleatoria. ¿Está bien?

  2. ¿Cómo logro que el primer y el último valor de desplazamiento (es decir, para los nodos 0 y N-1) devueltos por la función Perlin siempre sea 0 (cero)? En este momento estoy modulando una función seno (0 .. Pi) con mi función Perlin para lograr eso, pero eso no es realmente lo que quiero. Simplemente ponerlos a cero no es lo que quiero, ya que quiero un buen camino de rayos sin jaggies en sus extremos.

  3. ¿Cómo varío la función Perlin (de modo que obtendría dos caminos diferentes que podría usar como marcos de inicio y final de animación para el rayo)? Por supuesto, podría agregar un desplazamiento fijo aleatorio por cálculo de ruta a cada valor de nodo, o usar una tabla de permutación de configuración diferente para mejorar el ruido de Perlin, pero ¿hay mejores opciones?

+1

Esta pregunta es genial. – sharptooth

+0

http://www.noisemachine.com/talk1/23.html –

Respuesta

2
  1. Eso depende de cómo ponerlo en práctica y la muestra de ella. Usar múltiples octavas ayuda a contrarrestar números enteros bastante.

    Las octavas y la interpolación/muestreo adicionales realizados para cada uno proporcionan gran parte del ruido en el ruido perlin. En teoría, no debería necesitar usar diferentes posiciones enteras; Debería poder muestrear en cualquier punto y será similar (pero no siempre idéntico) a los valores cercanos.

  2. Sugeriría usar el perlin como un multiplicador en lugar de simplemente aditivo, y usar una curva en el transcurso del rayo. Por ejemplo, si tiene perlin en el rango [-1.5, 1.5] y una curva normal sobre el rayo (0 en ambos extremos, 1 en el centro), lightning + (perlin * curve) mantendrá sus puntos finales inmóviles. Dependiendo de cómo se ha implementado el generador de ruido Perlin, es posible que tenga algo como:

    lightning.x += ((perlin(lightning.y, octaves) * 2.0) - 0.5) * curve(lightning.y);

    si perlin vuelve [0,1] o

    lightning.x += (perlin(lightning.y, octaves)/128.0) * curve(lightning.y);

    si devuelve [0 , 255]. Suponiendo que lightning.x comenzara con un valor dado, tal vez 0, eso daría una línea un tanto irregular que aún cumple con los puntos iniciales y finales originales.

  3. Agregue una dimensión al ruido para cada dimensión que agregue al rayo.Si está modificando el rayo en una dimensión (horizontal irregular), necesita 1D ruido perlin. Si quieres animarlo, necesitas 2D. Si quisieras un rayo que fuera irregular en dos ejes y animado, necesitarías ruido 3D, y así sucesivamente.
+0

Sus respuestas a (1.) y (3.) fueron realmente útiles. (2.) es exactamente lo que hago, pero no quiero hacer. Aún así, muchas gracias, esto me llevó más lejos. – karx11erx

+0

No estoy seguro de que haya una mejor manera para 2; ciertamente ninguno que se me ocurra, sin llegar a ser realmente complicado. Puede obtener mejores resultados jugando con la curva que usa, si eso es un problema. – ssube

+0

¿Cómo animaría una trayectoria de rayos 1D usando ruido 2D? No puedo entender eso. ¿Sería y el tiempo transcurrido (en cuadros, contando de 0 a -1)? – karx11erx

1

Después de leer la respuesta de peachykeen y hacer algunas (más) investigaciones en Internet, he encontrado la siguiente solución para mí.

  1. Con mi aplicación de ruido Perlin, utilizando un intervalo de valores de [0,0 .. 1,0] para el rayo nodos ruta de trabajo mejor, pasando el valor (doble) M/(doble) N para el nodo M al Función de ruido Perlin.

  2. Para tener una función de ruido F 'devuelve el mismo valor para el nodo 0 y el nodo N-1, se puede aplicar la siguiente fórmula: F' (M) = ((M - N) * F (N) + N * F (N - M))/M. Para que las desviaciones de la trayectoria del rayo comiencen y finalicen con 0, simplemente necesita restar F '(0) de todos los desplazamientos de la trayectoria del rayo después de haber calculado la trayectoria.

  3. Para aleatorizar la trayectoria del rayo, antes de calcular los desplazamientos para cada nodo, se puede calcular y agregar una compensación aleatoria R a los valores pasados ​​a la función de ruido para que el nodo O = F '(N + R). Para animar un rayo, se deben calcular dos trayectorias de rayo (cuadro de inicio y final), y luego cada vértice de trayecto tiene que estar activado entre su posición inicial y final. Una vez que se ha alcanzado el marco final, el marco final se convierte en el marco inicial y se calcula un nuevo marco final. Para una ruta 3D, para cada nodo de ruta N se pueden calcular dos vectores de desplazamiento que son perpendiculares a la ruta en el nodo N y entre sí, y se pueden escalar con dos valores de ruido 1D Perlin para visualizar la posición del nodo desde la posición de inicio hasta el final . Eso puede ser más barato que hacer ruido 3D Perlin y funciona bastante bien en mi aplicación.

Aquí es mi implementación de ruido estándar 1D Perlin como referencia (algunas cosas es virtual porque yo estoy usando esto como base para la mejora de ruido Perlin, lo que permite utilizar el ruido estándar o mejorado Perlin en una aplicación de patrón de estrategia. el código se ha simplificado un tanto así para que sea más concisa para publicarla aquí):

archivo de cabecera:

#ifndef __PERLIN_H 
#define __PERLIN_H 

class CPerlin { 
    private: 
    int m_randomize; 

    protected: 
    double m_amplitude; 
    double m_persistence; 
    int m_octaves; 

    public: 
    virtual void Setup (double amplitude, double persistence, int octaves, int randomize = -1); 
    double ComputeNoise (double x); 

    protected: 
    double LinearInterpolate (double a, double b, double x); 
    double CosineInterpolate (double a, double b, double x); 
    double CubicInterpolate (double v0, double v1, double v2, double v3, double x); 
    double Noise (int v);  
    double SmoothedNoise (int x); 
    virtual double InterpolatedNoise (double x); 
    }; 

#endif //__PERLIN_H 

Implementación:

#include <math.h> 
#include <stdlib.h> 
#include "perlin.h" 

#define INTERPOLATION_METHOD 1 

#ifndef Pi 
# define Pi 3.141592653589793240 
#endif 

inline double CPerlin::Noise (int n) { 
    n = (n << 13)^n; 
    return 1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff)/1073741824.0;  
    } 

double CPerlin::LinearInterpolate (double a, double b, double x) { 
    return a * (1.0 - x) + b * x; 
    } 

double CPerlin::CosineInterpolate (double a, double b, double x) { 
    double f = (1.0 - cos (x * Pi)) * 0.5; 
    return a * (1.0 - f) + b * f; 
    } 

double CPerlin::CubicInterpolate (double v0, double v1, double v2, double v3, double x) { 
    double p = (v3 - v2) - (v0 - v1); 
    double x2 = x * x; 
    return v1 + (v2 - v0) * x + (v0 - v1 - p) * x2 + p * x2 * x; 
    } 

double CPerlin::SmoothedNoise (int v) { 
    return Noise (v)/2 + Noise (v-1)/4 + Noise (v+1)/4; 
    } 

int FastFloor (double v) { return (int) ((v < 0) ? v - 1 : v; } 

double CPerlin::InterpolatedNoise (double v) { 
    int i = FastFloor (v); 
    double v1 = SmoothedNoise (i); 
    double v2 = SmoothedNoise (i + 1); 
#if INTERPOLATION_METHOD == 2 
    double v0 = SmoothedNoise (i - 1); 
    double v3 = SmoothedNoise (i + 2); 
    return CubicInterpolate (v0, v1, v2, v3, v - i); 
#elif INTERPOLATION_METHOD == 1 
    return CosineInterpolate (v1, v2, v - i); 
#else 
    return LinearInterpolate (v1, v2, v - i); 
#endif 
    } 

double CPerlin::ComputeNoise (double v) { 
    double total = 0, amplitude = m_amplitude, frequency = 1.0; 
    v += m_randomize; 
    for (int i = 0; i < m_octaves; i++) { 
    total += InterpolatedNoise (v * frequency) * amplitude; 
    frequency *= 2.0; 
    amplitude *= m_persistence; 
    } 
    return total; 
    } 

void CPerlin::Setup (double amplitude, double persistence, int octaves, int randomize) { 
    m_amplitude = (amplitude > 0.0) ? amplitude : 1.0; 
    m_persistence = (persistence > 0.0) ? persistence : 2.0/3.0; 
    m_octaves = (octaves > 0) ? octaves : 6; 
    m_randomize = (randomize < 0) ? (rand() * rand()) & 0xFFFF : randomize; 
    } 
Cuestiones relacionadas