2011-09-01 2 views
5

사실 주제 제목과 관련된 몇 가지 질문이 있습니다.Perlin 노이즈를 사용하여 번개를 만드시겠습니까?

나는 이미 응용 프로그램에서 번개를 만드는 데 Perlin 함수를 사용하고 있지만 구현에 대해서는 완전히 만족하지 않습니다.

다음 질문은 초기 및 향상된 Perlin 노이즈 구현을 기반으로합니다.

문제를 단순화하기 위해 1D Perlin 함수를 사용하여 노드에서 N 노드로 구성된 수평선의 높이를 변조하여 간단한 2D 번개를 작성한다고 가정 해 보겠습니다.

  1. 필자가 이해하는 한, Perlin 함수에 전달 된 두 개의 후속 값은 적어도 하나 이상 달라야하며, 결과 두 값은 동일합니다. 이는 단순한 Perlin 구현에서 Random 함수가 int 인수로 작동하고 향상된 구현 값이 [0..255]에 매핑되고 [0..255] 값을 포함하는 배열의 인덱스로 사용되기 때문입니다 ]를 무작위로 배분합니다. 그게 맞습니까?

  2. Perlin 함수에 의해 반환 된 첫 번째 및 마지막 오프셋 값 (즉, 노드 0 및 N-1)이 항상 0 (영)이라는 것을 어떻게 달성 할 수 있습니까? 지금은 그것을 달성하기 위해 필자의 Perlin 함수로 사인 함수 (0 .. Pi)를 변조했지만 실제로는 내가 원하는 바가 아닙니다. 그냥 0으로 설정하는 것은 내가 원하는 것이 아니기 때문에 끝 부분에 들쭉날쭉 한 멋진 번개 경로가 있기를 원하기 때문입니다.

  3. 번개의 애니메이션 시작과 끝 프레임으로 사용할 수있는 두 개의 다른 경로를 얻으려면 어떻게해야합니까? 물론 경로 계산 당 고정 된 임의의 오프셋을 각 노드 값에 추가하거나 개선 된 Perlin 노이즈를 위해 설치 순열 테이블을 다르게 사용할 수 있지만 더 좋은 옵션이 있습니까? 당신이 그것에서 샘플을 구현하는 방법에 따라 달라집니다

+1

이 질문은 위대한 내용입니다. – sharptooth

+0

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

답변

2
  1. . 여러 옥타브를 사용하면 정수에 꽤 많은 도움이됩니다.

    각 옥타브와 추가 보간/샘플링은 perlin 노이즈의 많은 노이즈를 제공합니다. 이론 상으로는 서로 다른 정수 위치를 사용할 필요가 없습니다. 언제든지 샘플링 할 수 있어야하며 가까운 값과 유사 할 수도 있지만 항상 동일하지는 않습니다.

  2. 필자는 단순히 덧셈 대신 승수로 페린을 사용하고 번개를 따라 곡선을 사용하는 것이 좋습니다. 예를 들어, perlin이 [-1.5, 1.5]의 범위에 있고 번개에 대한 정상 곡선 (양 끝점이 0, 가운데가 1)을 갖는 경우 lightning + (perlin * curve)은 끝점을 계속 유지합니다. 당신이 당신의 펄린 노이즈 발생기를 구현 한 방법에 따라, 당신은 뭔가를해야 할 수 있습니다

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

    경우 perlin 반환 [0,1] 또는

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

    가 반환하는 경우

    [0 , 255]. 주어진 값, 아마도 0으로 시작한 lightning.x을 가정하면 원래의 시작점과 끝점을 여전히 충족시키는 다소 들쭉날쭉 한 선이 생깁니다.

  3. 번개에 추가하는 모든 치수에 대한 노이즈에 치수를 추가하십시오.한 차원의 번개를 수정하는 경우 (수평 방향으로 들쭉날쭉 함) 1D perlin 노이즈가 필요합니다. 애니메이션을 적용하려면 2D가 필요합니다. 번개가 두 축에서 들쭉날쭉하게 움직이고 애니메이션이 필요하다면 3D 노이즈 등이 필요합니다.
+0

(1) 및 (3)에 대한 귀하의 답장은 정말로 도움이되었습니다. (2.) 정확히 내가하는 일이지만,하고 싶지는 않습니다. 그래도 고마워. – karx11erx

+0

2를위한 더 좋은 방법이 있는지 확신하지 못합니다. 확실히 아무도 나는 정말로 복잡하지 않고, 생각해 낼 수 없다. 커브를 가지고 노는 것이 더 좋은 결과를 얻을 수 있습니다. – ssube

+0

2D 노이즈를 사용하여 1D 번개 경로에 애니메이션을 적용하려면 어떻게해야합니까? 나는 그것을 정말로 알 수 없다. y는 경과 시간 (프레임 수, 0에서 <애니메이션 프레임 수> -1까지 계산)입니까? – karx11erx

1

peachykeen의 대답을 읽고 인터넷에서 자신의 연구를 수행 한 결과 다음과 같은 해결책을 찾았습니다. 값의 범위를 사용 Perlin 노이즈 내 구현

  1. [0.0 ... 1.0] 경로 노드가 가장 적합한 번개 값 통과 (더블) M/(더블) N받는 노드 M 대 펄린 노이즈 기능. 노드 N과 노드 N-1에 대해 동일한 값을 반환하려면 다음 식을 적용하면됩니다. F '(M) = ((M-N) * F (N) + 번개 경로 오프셋을 0에서 시작하고 끝내려면 경로를 계산 한 후 모든 번개 경로 오프셋에서 F '(0)을 뺄 필요가 있습니다.

  2. 각 경로 노드에 대한 오프셋을 계산하기 전에 낙뢰 오프셋 R을 계산하여 잡음 함수로 전달 된 값에 더할 수 있으므로 노드의 오프셋 O = F '(N + 아르 자형). 번개를 움직이게하려면 두 번개 경로를 계산해야합니다 (시작 프레임과 끝 프레임). 그런 다음 각 경로 정점을 시작 위치와 끝 위치 사이에서 찾아야합니다. 끝 프레임에 도달하면 끝 프레임이 시작 프레임이되고 새 끝 프레임이 계산됩니다. 3D 경로의 경우 각 경로 노드 N에 대해 두 개의 오프셋 벡터가 계산 될 수 있으며 두 개의 1D Perlin 노이즈 값으로 스케일되어 노드 위치가 시작에서 끝 프레임 위치까지 lerp됩니다 . 3D Perlin 노이즈를 처리하는 것보다 비용이 적게 들고 응용 프로그램에서 상당히 잘 작동합니다.

여기 참조 표준 1D 펄린 노이즈 (I는 전략 패턴 응용 프로그램에서 표준 또는 개선 펄린 노이즈를 사용할 수 있도록 개선 펄린 노이즈 기지로이를 사용하고 있기 때문에 몇 가지 물건 가상입니다 내 구현입니다.

헤더 파일 :

#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 

구현 :

를 코드뿐만 아니라) 여기를 게시하기위한 더 간결하게 다소 단순화 된
#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; 
    } 
관련 문제