2011-09-01 26 views
5

Thực ra tôi có một số câu hỏi liên quan đến chủ đề được đưa ra trong tiêu đề chủ đề.Sử dụng nhiễu Perlin để tạo ra sét?

Tôi đã sử dụng chức năng Perlin để tạo tia sét trong ứng dụng của mình, nhưng tôi không hoàn toàn hài lòng với việc triển khai của mình.

Các câu hỏi sau đây dựa trên việc triển khai tiếng ồn Perlin ban đầu và cải tiến. Để đơn giản hóa vấn đề, giả sử tôi tạo một sét 2D đơn giản bằng cách điều chỉnh chiều cao của đường ngang bao gồm N nút tại các nút này bằng cách sử dụng hàm 1D Perlin.

  1. Theo như tôi đã hiểu, hai giá trị tiếp theo được chuyển đến hàm Perlin phải khác nhau ít nhất một hoặc hai giá trị kết quả sẽ giống hệt nhau. Đó là bởi vì việc triển khai Perlin đơn giản, hàm Random làm việc với đối số int và trong các giá trị triển khai được cải tiến được ánh xạ tới [0..255] và sau đó được sử dụng làm chỉ mục vào một mảng chứa các giá trị [0..255 ] trong phân phối ngẫu nhiên. Có đúng không?

  2. Làm cách nào để đạt được giá trị bù đầu tiên và cuối cùng (tức là đối với các nút 0 và N-1) được hàm Perlin trả về luôn bằng 0 (không)? Ngay bây giờ tôi đang điều chế một hàm sin (0 .. Pi) với hàm Perlin của tôi để đạt được điều đó, nhưng đó không thực sự là điều tôi muốn. Chỉ cần đặt chúng về 0 không phải là những gì tôi muốn, vì tôi muốn có một con đường sét đẹp đẽo w/o jaggies ở đầu của nó.

  3. Làm cách nào để thay đổi chức năng Perlin (để tôi có hai đường dẫn khác nhau mà tôi có thể sử dụng làm khung hình bắt đầu và kết thúc hoạt ảnh cho tia chớp)? Tôi có thể tất nhiên thêm một bù đắp ngẫu nhiên cố định cho mỗi phép tính đường dẫn cho mỗi giá trị nút, hoặc sử dụng một bảng hoán vị thiết lập khác nhau để cải thiện tiếng ồn Perlin, nhưng có lựa chọn tốt hơn?

+1

Câu hỏi này rất tuyệt. – sharptooth

+0

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

Trả lời

2
  1. Điều đó phụ thuộc vào cách bạn thực hiện nó và mẫu từ nó. Sử dụng nhiều octaves giúp truy cập số nguyên khá một chút.

    Các quãng tám và phép nội suy/lấy mẫu bổ sung được thực hiện cho từng cung cấp nhiều nhiễu trong nhiễu perlin. Về lý thuyết, bạn không cần phải sử dụng các vị trí số nguyên khác nhau; bạn sẽ có thể lấy mẫu tại bất kỳ thời điểm nào và nó sẽ tương tự (nhưng không phải lúc nào cũng giống hệt nhau) với các giá trị lân cận.

  2. Tôi khuyên bạn nên sử dụng perlin làm hệ số nhân thay vì chỉ đơn giản là phụ gia và sử dụng đường cong trong quá trình chớp. Ví dụ, có perlin trong phạm vi [-1,5, 1,5] và một đường cong bình thường trên tia chớp (0 ở cả hai đầu, 1 ở giữa), lightning + (perlin * curve) sẽ giữ cho điểm kết thúc của bạn vẫn còn. Tùy thuộc vào cách bạn đã thực hiện phát tiếng ồn Perlin của bạn, bạn có thể cần một cái gì đó như:

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

    nếu perlin lợi nhuận [0,1] hoặc

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

    nếu nó trả về [0 , 255]. Giả sử lightning.x bắt đầu bằng một giá trị nhất định, có thể là 0, có thể cho một đường hơi bị răng cưa vẫn đáp ứng được điểm bắt đầu và điểm kết thúc ban đầu.

  3. Thêm thứ nguyên cho tiếng ồn cho mọi tham số bạn thêm vào tia chớp.Nếu bạn đang sửa đổi sét trong một chiều (ngang bịt răng), bạn cần 1D nhiễu perlin. Nếu bạn muốn tạo hiệu ứng động, bạn cần 2D. Nếu bạn muốn sét bị lởm chởm trên hai trục và hoạt hình, bạn sẽ cần nhiễu 3D, v.v.
+0

Câu trả lời của bạn cho (1.) và (3.) thực sự hữu ích. (2.) là chính xác những gì tôi làm, nhưng không muốn làm. Tuy nhiên, cảm ơn rất nhiều, điều này đã giúp tôi tiếp tục. – karx11erx

+0

Tôi không chắc chắn có cách nào tốt hơn cho 2 người; chắc chắn không có gì tôi có thể đưa ra, mà không nhận được thực sự phức tạp. Bạn có thể nhận được kết quả tốt hơn bằng cách chơi với đường cong bạn sử dụng, nếu đó là một vấn đề. – ssube

+0

Tôi làm cách nào để tạo hiệu ứng đường dẫn sét 1D bằng cách sử dụng tiếng ồn 2D? Tôi không thể hình dung được điều đó. Liệu y có phải là thời gian trôi qua (trong khung hình, tính từ 0 đến -1) không? – karx11erx

1

Sau khi đọc câu trả lời của Peachykeen và thực hiện một số nghiên cứu riêng (trên) trên internet, tôi đã tìm thấy giải pháp sau đây để làm việc cho tôi.

  1. Với thực hiện của tôi Perlin tiếng ồn, sử dụng một phạm vi giá trị của [0,0 .. 1,0] cho sét nút con đường hiệu quả nhất, đi qua các giá trị (double) M/(double) N cho nút M đến Perlin chức năng tiếng ồn.

  2. Để có hàm tiếng ồn F 'trả về cùng giá trị cho nút 0 và nút N-1, công thức sau có thể được áp dụng: F' (M) = ((M - N) * F (N) + N * F (N - M))/M. Để có các đường tắt tia chớp bắt đầu và kết thúc bằng 0, bạn chỉ cần trừ F '(0) khỏi tất cả các đường tắt tia chớp sau khi tính toán đường đi. Để ngẫu nhiên con đường sét, trước khi tính toán bù trừ cho mỗi nút đường dẫn, một R bù ngẫu nhiên có thể được tính toán và thêm vào các giá trị được chuyển đến hàm nhiễu, sao cho bù đắp của nút O = F '(N + R). Để tạo hiệu ứng cho một tia chớp, cần phải tính hai đường dẫn sét (khung bắt đầu và kết thúc), và sau đó mỗi đỉnh đường dẫn phải được lerped giữa vị trí bắt đầu và kết thúc của nó. Khi đã đạt đến khung kết thúc, khung kết thúc sẽ trở thành khung bắt đầu và một khung kết thúc mới được tính toán. Đối với một đường dẫn 3D, cho mỗi nút đường dẫn N hai vector bù có thể được tính vuông góc với đường dẫn tại nút N và mỗi khác, và có thể được chia tỷ lệ với hai giá trị tạp âm 1D Perlin để lerp vị trí nút từ vị trí khung đầu đến cuối . Điều đó có thể rẻ hơn so với làm nhiễu 3D Perlin và hoạt động khá tốt trong ứng dụng của tôi.

Đây là triển khai thực hiện của tôi về tiêu chuẩn tiếng ồn 1D Perlin như một tài liệu tham khảo (một số nội dung là ảo bởi vì tôi đang sử dụng này như là cơ sở cho việc cải thiện tiếng ồn Perlin, cho phép sử dụng tiêu chuẩn hoặc được cải thiện tiếng ồn Perlin trong một ứng dụng mô hình chiến lược. mã này đã được đơn giản hóa phần nào cũng như để làm cho nó ngắn gọn hơn cho xuất bản nó ở đây):

header file:

#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 

thực hiệ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; 
    } 
Các vấn đề liên quan