Just A Quick Update

用 Shader 来做 Noise 比 CPU 做快太多了。
举个例子:

CGINCLUDE

		void FAST32_hash_2D( float2 gridcell, out float4 hash_0, out float4 hash_1 )	//	generates 2 random numbers for each of the 4 cell corners
		{
			//    gridcell is assumed to be an integer coordinate
			const float2 OFFSET = float2( 26.0, 161.0 );
			const float DOMAIN = 71.0;
			const float2 SOMELARGEFLOATS = float2( 951.135664, 642.949883 );
			float4 P = float4( gridcell.xy, gridcell.xy + 1.0 );
			P = P - floor(P * ( 1.0 / DOMAIN )) * DOMAIN;
			P += OFFSET.xyxy;
			P *= P;
			P = P.xzxz * P.yyww;
			hash_0 = frac( P * ( 1.0 / SOMELARGEFLOATS.x ) );
			hash_1 = frac( P * ( 1.0 / SOMELARGEFLOATS.y ) );
		}

		float2 Interpolation_C2( float2 x ) { return x * x * x * (x * (x * 6.0 - 15.0) + 10.0); }

		float Perlin2D( float2 P )
		{
			float2 Pi = floor(P);
			float4 Pf_Pfmin1 = P.xyxy - float4( Pi, Pi + 1.0 );
		
			float4 hash_x, hash_y;
			FAST32_hash_2D( Pi, hash_x, hash_y );
		
			float4 grad_x = hash_x - 0.49999;
			float4 grad_y = hash_y - 0.49999;
			float4 grad_results = rsqrt( grad_x * grad_x + grad_y * grad_y ) * ( grad_x * Pf_Pfmin1.xzxz + grad_y * Pf_Pfmin1.yyww );
		
			grad_results *= 1.4142135623730950488016887242097;		//	(optionally) scale things to a strict -1.0->1.0 range    *= 1.0/sqrt(0.5)
			float2 blend = Interpolation_C2( Pf_Pfmin1.xy );
			float2 res0 = lerp( grad_results.xy, grad_results.zw, blend.y );
			return lerp( res0.x, res0.y, blend.x );

		}
		float PerlinNormal(float2 p, int octaves, float2 offset, float frequency, float amplitude, float lacunarity, float persistence)
		{
			float sum = 0;
			for (int i = 0; i < octaves; i++)
			{
				float h = 0;
				h = Perlin2D((p + offset) * frequency);
				sum += h*amplitude;
				frequency *= lacunarity;
				amplitude *= persistence;
			}
			return sum;
		}

	ENDCG

这段代码,取自 briansharpe,在 Unity 上写成 Shader 后使用 RenderTexture (需要 Unity Pro) 渲染到 Texture 上就可以拿到 float[4096][2048] 的数据了,而且在 Update() 里面可以实时更改种子。而相比之下 LibNoise 的 .Net Port 需要半分钟来做到类似的事情。
这个发现让我很兴奋,因为 LibNoise 实在是太慢了,即使是 C++ 版本作者自己也说生成一个星球贴图需要二十分钟。之前尝试了各种加速生成的方法,甚至开始准备写一个 LibNoise 在 Swift 上使用 Accelerate.Framework 来通过 SIMD 加速的移植版本,但是效果都不是很理想。如果一开始就使用 Shader 来做计算的话,这个坎早就过了。