11//! Procedural noise generation.
2+ //!
3+ //! This module implements two- and three-dimensional Perlin Noise.
24
35use super :: {
46 spline:: smoothstep,
57 vary:: lerp,
6- vec:: { splat, vec2, vec3, Vec2 , Vec3 , Vector } ,
8+ vec:: { splat, vec2, vec3, Vec2 , Vec3 } ,
9+ Vary ,
710} ;
11+ use crate :: math:: vary:: bilerp;
12+ use std:: array;
813
914/// Returns the Perlin noise value corresponding to the 2D point.
1015pub fn perlin2 ( pt : Vec2 ) -> f32 {
1116 use super :: float:: f32;
12- let f = pt - pt. map ( f32:: floor) ;
13- let [ fx, fy] = f. 0 ;
14-
17+ let fract = pt - pt. map ( f32:: floor) ;
18+ let [ fx, fy] = fract. 0 ;
1519 let [ g00, g01, g10, g11] = grads2 ( pt) ;
1620
1721 let d00 = g00. dot ( & vec2 ( fx, fy) ) ;
1822 let d01 = g01. dot ( & vec2 ( fx, fy - 1.0 ) ) ;
1923 let d10 = g10. dot ( & vec2 ( fx - 1.0 , fy) ) ;
2024 let d11 = g11. dot ( & vec2 ( fx - 1.0 , fy - 1.0 ) ) ;
2125
22- let t = f. map ( smoothstep) ;
23- let ( a, b) = lerp ( t. x ( ) , ( d00, d01) , ( d10, d11) ) ;
24- lerp ( t. y ( ) , a, b)
26+ let t = fract. map ( smoothstep) ;
27+ bilerp ( t. x ( ) , t. y ( ) , d00, d10, d01, d11)
2528}
2629
2730/// Returns the Perlin gradient vector corresponding to the 2D point.
@@ -31,58 +34,63 @@ pub fn perlin2(pt: Vec2) -> f32 {
3134pub fn perlin2v ( pt : Vec2 ) -> Vec2 {
3235 use super :: float:: f32;
3336 let fract = pt - pt. map ( f32:: floor) ;
34-
3537 let [ g00, g01, g10, g11] = grads2 ( pt) ;
36-
3738 let t = fract. map ( smoothstep) ;
38- let ( a, b) = lerp ( t. x ( ) , ( g00, g01) , ( g10, g11) ) ;
39- lerp ( t. y ( ) , a, b)
39+ bilerp ( t. x ( ) , t. y ( ) , g00, g10, g01, g11)
40+ }
41+
42+ trait ArrayExt < T > {
43+ /// Splits `self` to arrays of length `I` and `J`.
44+ fn split_to < const I : usize , const J : usize > ( & self ) -> ( & [ T ; I ] , & [ T ; J ] ) ;
45+ }
46+
47+ impl < T , const N : usize > ArrayExt < T > for [ T ; N ] {
48+ fn split_to < const I : usize , const J : usize > ( & self ) -> ( & [ T ; I ] , & [ T ; J ] ) {
49+ const {
50+ assert ! ( I + J <= N ) ;
51+ }
52+ let ( a, b) = self [ ..I + J ] . split_at ( I ) ;
53+ ( a. try_into ( ) . unwrap ( ) , b. try_into ( ) . unwrap ( ) )
54+ }
4055}
4156
4257/// Returns the Perlin noise value corresponding to the 3D point.
4358pub fn perlin3 ( pt : Vec3 ) -> f32 {
4459 use super :: float:: f32;
4560 let pt0 = pt. map ( f32:: floor) ;
46- let f = pt - pt0;
47- let i_f : Vec3 = f - splat ( 1.0 ) ;
61+ let fract = pt - pt0;
62+ let grads = grads3 ( pt0 ) ;
4863
49- let [ fx, fy, fz] = f. 0 ;
50- let [ ifx, ify, ifz] = i_f. 0 ;
64+ let [ fx, fy, fz] = array:: from_fn ( |i| [ fract[ i] , fract[ i] - 1.0 ] ) ;
5165
52- let [ g000 , g001 , g010 , g011 , g100 , g101 , g110 , g111 ] = grads3 ( pt0 ) ;
66+ let yzs : [ _ ; 4 ] = array :: from_fn ( |i| [ fy [ ( i >> 1 ) & 1 ] , fz [ i & 1 ] ] ) ;
5367
54- let d000 = g000. dot ( & vec3 ( fx, fy, fz) ) ;
55- let d001 = g001. dot ( & vec3 ( fx, fy, ifz) ) ;
56- let d010 = g010. dot ( & vec3 ( fx, ify, fz) ) ;
57- let d011 = g011. dot ( & vec3 ( fx, ify, ifz) ) ;
58- let d100 = g100. dot ( & vec3 ( ifx, fy, fz) ) ;
59- let d101 = g101. dot ( & vec3 ( ifx, fy, ifz) ) ;
60- let d110 = g110. dot ( & vec3 ( ifx, ify, fz) ) ;
61- let d111 = g111. dot ( & vec3 ( ifx, ify, ifz) ) ;
68+ let ( left, right) = grads. split_to :: < 4 , 4 > ( ) ;
6269
63- let t: Vec3 = f. map ( smoothstep) ;
70+ let left: [ f32 ; 4 ] = array:: from_fn ( |i| {
71+ let [ y, z] = yzs[ i] ;
72+ left[ i] . dot ( & vec3 ( fx[ 0 ] , y, z) )
73+ } ) ;
74+ let right: [ f32 ; 4 ] = array:: from_fn ( |i| {
75+ let [ y, z] = yzs[ i] ;
76+ right[ i] . dot ( & vec3 ( fx[ 1 ] , y, z) )
77+ } ) ;
6478
65- let x0 = Vector :: < _ > :: new ( [ d000, d010, d001, d011] ) ;
66- let x1 = Vector :: < _ > :: new ( [ d100, d110, d101, d111] ) ;
67- let [ y0, y1, y2, y3] = lerp ( t. x ( ) , x0, x1) . 0 ;
68- let ( z0, z1) = lerp ( t. y ( ) , ( y0, y2) , ( y1, y3) ) ;
69- lerp ( t. z ( ) , z0, z1)
79+ trilerp ( fract, left, right)
7080}
7181
7282/// Returns the Perlin gradient vector corresponding to the 3D point.
7383pub fn perlin3v ( pt : Vec3 ) -> Vec3 {
7484 use super :: float:: f32;
7585 let fract = pt - pt. map ( f32:: floor) ;
86+ let [ lbn, lbf, ltn, ltf, rbn, rbf, rtn, rtf] = grads3 ( pt) ;
87+ trilerp ( fract, [ lbn, lbf, ltn, ltf] , [ rbn, rbf, rtn, rtf] )
88+ }
7689
77- let [ g000, g001, g010, g011, g100, g101, g110, g111] = grads3 ( pt) ;
78-
79- let t: Vec3 = fract. map ( smoothstep) ;
80-
81- let x0 = ( ( g000, g010) , ( g001, g011) ) ;
82- let x1 = ( ( g100, g110) , ( g101, g111) ) ;
83- let ( ( y0, y1) , ( y2, y3) ) = lerp ( t. x ( ) , x0, x1) ;
84- let ( z0, z1) = lerp ( t. y ( ) , ( y0, y2) , ( y1, y3) ) ;
85- lerp ( t. z ( ) , z0, z1)
90+ fn trilerp < V : Vary > ( pt : Vec3 , left : [ V ; 4 ] , right : [ V ; 4 ] ) -> V {
91+ let [ x, y, z] = pt. 0 . map ( smoothstep) ;
92+ let [ bot_near, bot_far, top_near, top_far] = lerp ( x, left, right) ;
93+ bilerp ( y, z, bot_near, top_near, bot_far, top_far)
8694}
8795
8896fn perm ( x : i32 ) -> i32 {
@@ -112,10 +120,6 @@ fn grad3(x: f32, y: f32, z: f32) -> Vec3 {
112120}
113121
114122fn grads3 ( pt0 : Vec3 ) -> [ Vec3 ; 8 ] {
115- let pt1 = pt0 + splat ( 1.0 ) ;
116- let [ x0, y0, z0] = pt0. 0 ;
117- let [ x1, y1, z1] = pt1. 0 ;
118-
119123 //
120124 // 011 +--------------+ 111
121125 // / | / |
@@ -128,16 +132,13 @@ fn grads3(pt0: Vec3) -> [Vec3; 8] {
128132 // 000 +--------------+ 100
129133 //
130134
131- let g000 = grad3 ( x0, y0, z0) ;
132- let g001 = grad3 ( x0, y0, z1) ;
133- let g010 = grad3 ( x0, y1, z0) ;
134- let g011 = grad3 ( x0, y1, z1) ;
135- let g100 = grad3 ( x1, y0, z0) ;
136- let g101 = grad3 ( x1, y0, z1) ;
137- let g110 = grad3 ( x1, y1, z0) ;
138- let g111 = grad3 ( x1, y1, z1) ;
139-
140- [ g000, g001, g010, g011, g100, g101, g110, g111]
135+ let pts = [ pt0, pt0 + splat ( 1.0 ) ] ;
136+ array:: from_fn ( |i| {
137+ let x = pts[ ( i >> 2 ) & 1 ] . x ( ) ;
138+ let y = pts[ ( i >> 1 ) & 1 ] . y ( ) ;
139+ let z = pts[ i & 1 ] . z ( ) ;
140+ grad3 ( x, y, z)
141+ } )
141142}
142143
143144const A : f32 = 1.237 ;
0 commit comments