|
@@ -0,0 +1,313 @@
|
|
|
+package hide.prefab;
|
|
|
+
|
|
|
+class NoiseGen extends Prefab {
|
|
|
+
|
|
|
+ static var DEFAULT_SEED = 42;
|
|
|
+
|
|
|
+ public var scale : Float = 1.;
|
|
|
+ public var channels : Int = 1;
|
|
|
+ public var normals : Bool = false;
|
|
|
+ public var contrast : Float = 0.;
|
|
|
+ public var brightness : Float = 0.;
|
|
|
+
|
|
|
+ public var size : Int = 512;
|
|
|
+ public var octaves : Int = 1;
|
|
|
+ public var persist : Float = 0.5;
|
|
|
+ public var lacunarity : Float = 2.;
|
|
|
+ public var ridged : Bool = false;
|
|
|
+ public var gain : Float = 2.0;
|
|
|
+ public var offset : Float = 0.5;
|
|
|
+ public var turbulence : Float = 0.;
|
|
|
+ public var turbulenceScale : Float = 1.;
|
|
|
+
|
|
|
+ override public function load(v:Dynamic) {
|
|
|
+ this.size = v.size;
|
|
|
+ this.scale = v.scale;
|
|
|
+ if( v.channels != null ) this.channels = v.channels;
|
|
|
+ this.octaves = v.octaves;
|
|
|
+ this.persist = v.persist;
|
|
|
+ this.lacunarity = v.lacunarity;
|
|
|
+ this.ridged = v.ridged;
|
|
|
+ if( v.gain != null ) this.gain = v.gain;
|
|
|
+ if( v.offset != null ) this.offset = v.offset;
|
|
|
+ if( v.contrast != null ) this.contrast = v.contrast;
|
|
|
+ if( v.brightness != null ) this.brightness = v.brightness;
|
|
|
+ if( v.normals != null ) this.normals = v.normals;
|
|
|
+ if( v.turbulence != null ) this.turbulence = v.turbulence;
|
|
|
+ if( v.turbulenceScale != null ) this.turbulenceScale = v.turbulenceScale;
|
|
|
+ }
|
|
|
+
|
|
|
+ override function save() {
|
|
|
+ var o : Dynamic = {
|
|
|
+ size : size,
|
|
|
+ scale : scale,
|
|
|
+ octaves : octaves,
|
|
|
+ persist : persist,
|
|
|
+ lacunarity : lacunarity,
|
|
|
+ };
|
|
|
+ if( channels != 1 )
|
|
|
+ o.channels = channels;
|
|
|
+ if( ridged ) {
|
|
|
+ o.ridged = ridged;
|
|
|
+ o.gain = gain;
|
|
|
+ o.offset = offset;
|
|
|
+ }
|
|
|
+ if( contrast != 0 )
|
|
|
+ o.contrast = contrast;
|
|
|
+ if( brightness != 0 )
|
|
|
+ o.brightness = brightness;
|
|
|
+ if( normals )
|
|
|
+ o.normals = normals;
|
|
|
+ if( turbulence != 0 ) {
|
|
|
+ o.turbulence = turbulence;
|
|
|
+ o.turbulenceScale = turbulenceScale;
|
|
|
+ }
|
|
|
+ return o;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function updateTexture( t : h3d.mat.Texture, seed : Int ) {
|
|
|
+ var e = h3d.Engine.getCurrent();
|
|
|
+ e.pushTarget(t);
|
|
|
+ @:privateAccess e.flushTarget();
|
|
|
+ var pass = new h3d.pass.ScreenFx(new NoiseShader());
|
|
|
+ pass.shader.seed = seed;
|
|
|
+ pass.shader.channels = normals ? 0 : channels;
|
|
|
+ pass.shader.octaves = octaves;
|
|
|
+ var scale = size * scale * scale / 16;
|
|
|
+ pass.shader.scale = Math.round(scale*0.5) * 2;
|
|
|
+ pass.shader.persist = persist;
|
|
|
+ pass.shader.lacunarity = lacunarity;
|
|
|
+
|
|
|
+ pass.shader.ridged = ridged;
|
|
|
+ pass.shader.gain = gain;
|
|
|
+ pass.shader.offset = offset;
|
|
|
+
|
|
|
+ pass.shader.contrast = contrast;
|
|
|
+ pass.shader.brightness = brightness;
|
|
|
+ pass.shader.normals = normals;
|
|
|
+
|
|
|
+ pass.shader.turbulence = turbulence * 16 / size;
|
|
|
+ pass.shader.turbulenceScale = turbulenceScale;
|
|
|
+
|
|
|
+ pass.render();
|
|
|
+ pass.dispose();
|
|
|
+ e.popTarget();
|
|
|
+ }
|
|
|
+
|
|
|
+ public function makeTexture( ?size, ?seed ) {
|
|
|
+ if( seed == null ) seed = DEFAULT_SEED;
|
|
|
+ if( size == null ) size = this.size;
|
|
|
+ var t = new h3d.mat.Texture(size, size, [Target]);
|
|
|
+ updateTexture(t, seed);
|
|
|
+ return t;
|
|
|
+ }
|
|
|
+
|
|
|
+ function makeTile( tex : h3d.mat.Texture ) {
|
|
|
+ var t = h2d.Tile.fromTexture(tex);
|
|
|
+ if( tex.flags.has(IsNPOT) )
|
|
|
+ return t;
|
|
|
+ // make wrapping artefacts apparent, if any
|
|
|
+ return t.sub(tex.width >> 1, tex.height >> 1, tex.width, tex.height);
|
|
|
+ }
|
|
|
+
|
|
|
+ override function makeInstance( ctx : Context ) {
|
|
|
+ var tex = makeTexture();
|
|
|
+ ctx = ctx.clone(this);
|
|
|
+ var bmp = new h2d.Bitmap(makeTile(tex), ctx.local2d);
|
|
|
+ bmp.tileWrap = !tex.flags.has(IsNPOT);
|
|
|
+ ctx.local2d = bmp;
|
|
|
+ ctx.shared.cleanups.push(tex.dispose);
|
|
|
+ return ctx;
|
|
|
+ }
|
|
|
+
|
|
|
+ override function getHideProps() : HideProps {
|
|
|
+ return { icon : "chess-board", name : "Noise Generator" };
|
|
|
+ }
|
|
|
+
|
|
|
+ override function edit( ctx : EditContext ) {
|
|
|
+ #if editor
|
|
|
+ var e = ctx.properties.add(new hide.Element('
|
|
|
+ <dl>
|
|
|
+ <dt>Size</dt><dd><input type="range" min="16" max="2048" step="16" field="size"/></dd>
|
|
|
+ <dt>Scale</dt><dd><input type="range" min="0" max="2" field="scale"/></dd>
|
|
|
+ <dt>Channels</dt><dd><input type="range" min="1" max="4" step="1" field="channels"/></dd>
|
|
|
+ <dt>NormalMap</dt><dd><input type="checkbox" field="normals"/></dd>
|
|
|
+ </dl>
|
|
|
+ <br/>
|
|
|
+ <dl>
|
|
|
+ <dt>Octaves</dt><dd><input type="range" min="1" max="8" step="1" field="octaves"/></dd>
|
|
|
+ <dt>Persistence</dt><dd><input type="range" min="0.01" max="1" field="persist"/></dd>
|
|
|
+ <dt>Lacunarity</dt><dd><input type="range" min="1" max="5" field="lacunarity"/></dd>
|
|
|
+ </dl>
|
|
|
+ <br/>
|
|
|
+ <dl>
|
|
|
+ <dt>Ridged</dt><dd><input type="checkbox" field="ridged"/></dd>
|
|
|
+ <dt>Offset</dt><dd><input type="range" min="-1" max="1" field="offset"/></dd>
|
|
|
+ <dt>Gain</dt><dd><input type="range" min="0.01" max="5" field="gain"/></dd>
|
|
|
+ </dl>
|
|
|
+ <br/>
|
|
|
+ <dl>
|
|
|
+ <dt>Turbulence</dt><dd><input type="range" min="0" max="1" field="turbulence"/></dd>
|
|
|
+ <dt>Scale</dt><dd><input type="range" min="0" max="10" field="turbulenceScale"/></dd>
|
|
|
+ </dl>
|
|
|
+ <br/>
|
|
|
+ <dl>
|
|
|
+ <dt>Contrast</dt><dd><input type="range" min="-1" max="1" field="contrast"/></dd>
|
|
|
+ <dt>Brightness</dt><dd><input type="range" min="-1" max="1" field="brightness"/></dd>
|
|
|
+ </dl>
|
|
|
+ <br/>
|
|
|
+ <dl>
|
|
|
+ <dt> </dt><dd><input type="button" value="Download" name="dl"/></dd>
|
|
|
+ </dl>
|
|
|
+ '),this,function(_) {
|
|
|
+ var bmp = cast(ctx.getContext(this).local2d, h2d.Bitmap);
|
|
|
+ var tex = bmp.tile.getTexture();
|
|
|
+ if( tex.width != size ) {
|
|
|
+ tex.resize(size, size);
|
|
|
+ bmp.tile = makeTile(tex);
|
|
|
+ bmp.tileWrap = !tex.flags.has(IsNPOT);
|
|
|
+ }
|
|
|
+ updateTexture(tex, DEFAULT_SEED);
|
|
|
+ });
|
|
|
+ e.find("[name=dl]").click(function(_) {
|
|
|
+ hide.ui.Ide.inst.chooseFileSave("noise.png", function(f) if( f != null ) {
|
|
|
+ try {
|
|
|
+ var data = cast(ctx.getContext(this).local2d, h2d.Bitmap).tile.getTexture().capturePixels().toPNG();
|
|
|
+ sys.io.File.saveBytes(f, data);
|
|
|
+ } catch( e : Dynamic ) {
|
|
|
+ js.Browser.alert(e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ #end
|
|
|
+ }
|
|
|
+
|
|
|
+ static var _ = Library.register("noise", NoiseGen);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+class NoiseShader extends h3d.shader.ScreenShader {
|
|
|
+
|
|
|
+ static var SRC = {
|
|
|
+
|
|
|
+ @:import h3d.shader.NoiseLib;
|
|
|
+
|
|
|
+ @const var channels : Int = 1;
|
|
|
+ @const var octaves : Int = 1;
|
|
|
+
|
|
|
+ @param var seed : Int;
|
|
|
+ @param var scale : Float = 8;
|
|
|
+ @param var persist : Float = 0.5;
|
|
|
+ @param var lacunarity : Float = 2.0;
|
|
|
+
|
|
|
+ @const var ridged : Bool;
|
|
|
+ @param var gain : Float;
|
|
|
+ @param var offset : Float;
|
|
|
+
|
|
|
+ @param var contrast : Float;
|
|
|
+ @param var brightness : Float;
|
|
|
+ @param var turbulence : Float;
|
|
|
+ @param var turbulenceScale : Float;
|
|
|
+
|
|
|
+ @const var normals : Bool;
|
|
|
+
|
|
|
+ function perturb( uv : Vec2, scale : Float, seed : Int ) : Vec2 {
|
|
|
+ if( turbulence > 0. ) {
|
|
|
+ var turbScaleRepeat = int(scale * turbulenceScale * 0.5) * 2.;
|
|
|
+ noiseSeed = channels * octaves + 1 + seed;
|
|
|
+ uv.x += psnoise(calculatedUV * turbScaleRepeat, turbScaleRepeat.xx) * turbulence;
|
|
|
+ noiseSeed = channels * octaves + 1025 + seed;
|
|
|
+ uv.y += psnoise(calculatedUV * turbScaleRepeat, turbScaleRepeat.xx) * turbulence;
|
|
|
+ }
|
|
|
+ return uv;
|
|
|
+ }
|
|
|
+
|
|
|
+ function noise( seed : Int, scale : Float ) : Float {
|
|
|
+ var scaleRepeat = int(scale * 0.5) * 2.;
|
|
|
+ var uv = perturb(calculatedUV,scale,seed);
|
|
|
+ noiseSeed = seed;
|
|
|
+ return psnoise(uv * scaleRepeat, scaleRepeat.xx);
|
|
|
+ }
|
|
|
+
|
|
|
+ function noiseNormal( seed : Int, scale : Float ) : Vec3 {
|
|
|
+ var scaleRepeat = int(scale * 0.5) * 2.;
|
|
|
+ var uv = perturb(calculatedUV, scale,seed);
|
|
|
+ noiseSeed = seed;
|
|
|
+ return psrdnoise(uv * scaleRepeat, scaleRepeat.xx, 0.).yzx;
|
|
|
+ }
|
|
|
+
|
|
|
+ function calc( channel : Int ) : Float {
|
|
|
+ var v = 0.;
|
|
|
+ var seed = seed + channel * octaves;
|
|
|
+ var scale = scale;
|
|
|
+ if( ridged ) {
|
|
|
+ var k = 1.;
|
|
|
+ var s = lacunarity;
|
|
|
+ var weight = 1.;
|
|
|
+ var tot = 0.;
|
|
|
+ for( i in 0...octaves ) {
|
|
|
+ var g = noise(seed + i, scale) * k;
|
|
|
+ g = offset - abs(g);
|
|
|
+ g *= g;
|
|
|
+ g *= weight;
|
|
|
+ v += g * s;
|
|
|
+ tot += k;
|
|
|
+ weight = g * gain;
|
|
|
+ if( weight < 0 ) weight = 0 else if( weight > 1 ) weight = 1;
|
|
|
+ k *= persist;
|
|
|
+ scale *= lacunarity;
|
|
|
+ }
|
|
|
+ v /= tot;
|
|
|
+ } else {
|
|
|
+ var k = 1.;
|
|
|
+ for( i in 0...octaves ) {
|
|
|
+ v += noise(seed + i, scale) * k;
|
|
|
+ k *= persist;
|
|
|
+ scale *= lacunarity;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return (v * (1 + contrast) + 1) * 0.5 + brightness;
|
|
|
+ }
|
|
|
+
|
|
|
+ function calcNormal() : Vec3 {
|
|
|
+ var v = vec3(0.);
|
|
|
+ var scale = scale;
|
|
|
+ if( ridged ) {
|
|
|
+ // TODO
|
|
|
+ v.z = 1.;
|
|
|
+ } else {
|
|
|
+ var k = 1.;
|
|
|
+ for( i in 0...octaves ) {
|
|
|
+ v += noiseNormal(seed + i, scale) * k;
|
|
|
+ k *= persist;
|
|
|
+ scale *= lacunarity;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ v.z = (v.z + 1) * 0.5 + 10;
|
|
|
+ v = v.normalize();
|
|
|
+ v.xy *= pow(2., 1. + contrast * 4.);
|
|
|
+ return v.normalize();
|
|
|
+ }
|
|
|
+
|
|
|
+ function fragment() {
|
|
|
+ var out = vec4(0, 0, 0, 1);
|
|
|
+
|
|
|
+ if( normals ) {
|
|
|
+ out = packNormal(calcNormal());
|
|
|
+ } else {
|
|
|
+ if( channels >= 1 ) {
|
|
|
+ out.r = calc(0);
|
|
|
+ if( channels == 1 ) out.gb = out.rr;
|
|
|
+ }
|
|
|
+ if( channels >= 2 )
|
|
|
+ out.g = calc(1);
|
|
|
+ if( channels >= 3 )
|
|
|
+ out.b = calc(2);
|
|
|
+ if( channels >= 4 )
|
|
|
+ out.a = calc(3);
|
|
|
+ }
|
|
|
+ output.color = out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|