From c2e657b4386e9c4e9d0e58060c507da3241ffa12 Mon Sep 17 00:00:00 2001 From: stegu Date: Sun, 3 Apr 2011 17:30:50 +0200 Subject: [PATCH] Added 4D classic noise, declutter, speedups, removed dep of noiseStdLib.glsl, benchmark changed to test all six versions of noise. --- LICENSE | 4 +- README | 16 ++- benchmark/Linux/Makefile | 6 +- benchmark/MacOSX/Makefile | 8 +- benchmark/Win32/Makefile | 31 ++++-- benchmark/common/GLSL-ashimanoise.vert | 18 ---- benchmark/common/Makefile | 35 +++++-- benchmark/common/commonShader.frag | 10 +- benchmark/common/noisebench.c | 139 ++++++++++++++++--------- src/classicnoise2D.glsl | 44 ++++---- src/classicnoise3D.glsl | 6 +- src/noise2D.glsl | 58 ++++------- src/noise3D.glsl | 88 +++++++--------- src/noise4D.glsl | 86 +++++++-------- src/noiseStdLib.glsl | 33 ------ 15 files changed, 272 insertions(+), 310 deletions(-) delete mode 100755 benchmark/common/GLSL-ashimanoise.vert delete mode 100644 src/noiseStdLib.glsl diff --git a/LICENSE b/LICENSE index 1e202d0..001a9e5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Copyright (C) 2011 by Ashima Arts +Copyright (C) 2011 by Ashima Arts (Simplex noise) +Copyright (C) 2011 by Stefan Gustavson (Classic noise) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -17,4 +18,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/README b/README index abb860e..4487464 100644 --- a/README +++ b/README @@ -1,14 +1,12 @@ - This work follows Stefan Gustavson's paper "Simplex noise demystified" -http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf +http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf without using uniform arrays or texture engines. -A single vec4 uniform 'pParam' is used to set the length and a and -c constants respectively of the permutation polynomial to use. The -last element of the vec4 is the number of gradients to select from -on the vertices. An example vec4 is ( 19*19, 2*19, 1, 7 ) - -Refer to http://en.wikipedia.org/wiki/Permutation_polynomial for -more information on permutation polynomials. +The resulting noise functions are fast and self contained, +and their performance scales well with massive parallelism. +Simplex noise functions are (C) Ashima Arts +Classic noise functions are (C) Stefan Gustavson +Source code for the noise functions is released under the +conditions of the MIT license. See the file LICENSE for details. diff --git a/benchmark/Linux/Makefile b/benchmark/Linux/Makefile index 0483343..c81dde2 100755 --- a/benchmark/Linux/Makefile +++ b/benchmark/Linux/Makefile @@ -1,5 +1,6 @@ -SHADERS=GLSL-ashimanoise.vert GLSL-ashimanoise2D.frag \ - GLSL-ashimanoise3D.frag GLSL-ashimanoise4D.frag +SHADERS=noisebench.vert simplexnoise2D.frag simplexnoise3D.frag\ + simplexnoise4D.frag classicnoise2D.frag classicnoise3D.frag\ + classicnoise4D.frag constant.frag COMDIR=../common VPATH=$(COMDIR) EXECNAME=noisebench @@ -19,4 +20,3 @@ clean: run: ./$(EXECNAME) cat $(OUTPUTFILE) - diff --git a/benchmark/MacOSX/Makefile b/benchmark/MacOSX/Makefile index 8d5f5ab..317fa65 100644 --- a/benchmark/MacOSX/Makefile +++ b/benchmark/MacOSX/Makefile @@ -3,8 +3,9 @@ OUTPUTFILE=ashimanoise.log COMDIR=../common OBJS=noisebench.o -SHADERS=GLSL-ashimanoise.vert GLSL-ashimanoise2D.frag \ - GLSL-ashimanoise3D.frag GLSL-ashimanoise4D.frag +SHADERS=noisebench.vert simplexnoise2D.frag simplexnoise3D.frag\ + simplexnoise4D.frag classicnoise2D.frag classicnoise3D.frag\ + classicnoise4D.frag constant.frag VPATH=$(COMDIR) CFLAGS=-I. -I/usr/X11/include @@ -27,6 +28,5 @@ clean: - rm $(EXECNAME) links_done $(OBJS) $(SHADERS) $(OUTPUTFILE) run: - open -W -a $(EXECNAME) + open -W ./$(EXECNAME).app cat $(OUTPUTFILE) - diff --git a/benchmark/Win32/Makefile b/benchmark/Win32/Makefile index 1909c2a..8340cfb 100644 --- a/benchmark/Win32/Makefile +++ b/benchmark/Win32/Makefile @@ -3,7 +3,8 @@ MINGW32 = C:/Dev-Cpp #MINGW32 = C:/mingw CC = gcc.exe SRC = noisebench.c -SHADERS = GLSL-ashimanoise.vert GLSL-ashimanoise2D.frag GLSL-ashimanoise3D.frag GLSL-ashimanoise4D.frag +SHADERS = noisebench.vert constant.frag simplexnoise2D.frag simplexnoise3D.frag\ + simplexnoise4D.frag classicnoise2D.frag classicnoise3D.frag classicnoise4D.frag OBJ = noisebench.o LINKOBJ = noisebench.o LIBS = -L$(MINGW32)/lib -mwindows -lglfw -lopengl32 -lglu32 -mconsole -g3 @@ -17,17 +18,29 @@ all: $(EXECNAME) clean: del $(OBJ) $(EXECNAME) $(SHADERS) $(OUTPUTFILE) $(SRC) -GLSL-ashimanoise.vert: - copy ..\common\GLSL-ashimanoise.vert . +noisebench.vert: + copy ..\common\noisebench.vert . -GLSL-ashimanoise2D.frag: - copy ..\common\GLSL-ashimanoise2D.frag . +constant.frag: + copy ..\common\constant.frag . -GLSL-ashimanoise3D.frag: - copy ..\common\GLSL-ashimanoise3D.frag . +simplexnoise2D.frag: + copy ..\common\simplexnoise2D.frag . -GLSL-ashimanoise4D.frag: - copy ..\common\GLSL-ashimanoise4D.frag . +simplexnoise3D.frag: + copy ..\common\simplexnoise3D.frag . + +simplexnoise4D.frag: + copy ..\common\simplexnoise4D.frag . + +classicnoise2D.frag: + copy ..\common\classicnoise2D.frag . + +classicnoise3D.frag: + copy ..\common\classicnoise3D.frag . + +classicnoise4D.frag: + copy ..\common\classicnoise4D.frag . $(SRC): copy ..\common\$(SRC) . diff --git a/benchmark/common/GLSL-ashimanoise.vert b/benchmark/common/GLSL-ashimanoise.vert deleted file mode 100755 index 09a281c..0000000 --- a/benchmark/common/GLSL-ashimanoise.vert +++ /dev/null @@ -1,18 +0,0 @@ -#version 120 - -uniform float time; - -/* - * Both 2D and 3D texture coordinates are defined, for testing purposes. - */ -varying vec2 v_texCoord2D; -varying vec3 v_texCoord3D; -varying vec4 v_texCoord4D; - -void main( void ) -{ - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; - v_texCoord2D = gl_MultiTexCoord0.xy * 16.0 + vec2(0.0, time); - v_texCoord3D = vec3(gl_MultiTexCoord0.xy * 16.0, time); - v_texCoord4D = vec4(gl_MultiTexCoord0.xy * 16.0, 0.0, time); -} diff --git a/benchmark/common/Makefile b/benchmark/common/Makefile index 89d7c59..e30f93a 100644 --- a/benchmark/common/Makefile +++ b/benchmark/common/Makefile @@ -1,25 +1,40 @@ -OPTIONS=-DNORMALISE_GRADIENTS -DCOLLAPSE_SORTNET +OPTIONS= SRCDIR=../../src -COMMON=commonShader.frag $(SRCDIR)/noiseStdLib.glsl -SHADERS=GLSL-ashimanoise2D.frag GLSL-ashimanoise3D.frag \ - GLSL-ashimanoise4D.frag +COMMON=commonShader.frag +SHADERS=simplexnoise2D.frag simplexnoise3D.frag simplexnoise4D.frag \ + classicnoise2D.frag classicnoise3D.frag classicnoise4D.frag all: $(SHADERS) clean: - rm $(SHADERS) -GLSL-ashimanoise2D.frag: $(SRCDIR)/noise2D.glsl $(COMMON) +simplexnoise2D.frag: $(SRCDIR)/noise2D.glsl $(COMMON) cpp -P -I$(SRCDIR) -DSHADER=\"noise2D.glsl\" \ - -DVTYPE=vec2 -DVNAME=v_texCoord2D\ + -DVTYPE=vec2 -DVNAME=v_texCoord2D -DNOISEFUN=snoise\ $(OPTIONS) -DVERSION='#version 120' commonShader.frag $@ -GLSL-ashimanoise3D.frag: $(SRCDIR)/noise3D.glsl $(COMMON) +simplexnoise3D.frag: $(SRCDIR)/noise3D.glsl $(COMMON) cpp -P -I$(SRCDIR) -DSHADER=\"noise3D.glsl\" \ - -DVTYPE=vec3 -DVNAME=v_texCoord3D\ + -DVTYPE=vec3 -DVNAME=v_texCoord3D -DNOISEFUN=snoise\ $(OPTIONS) -DVERSION='#version 120' commonShader.frag $@ -GLSL-ashimanoise4D.frag: $(SRCDIR)/noise4D.glsl $(COMMON) +simplexnoise4D.frag: $(SRCDIR)/noise4D.glsl $(COMMON) cpp -P -I$(SRCDIR) -DSHADER=\"noise4D.glsl\" \ - -DVTYPE=vec4 -DVNAME=v_texCoord4D\ + -DVTYPE=vec4 -DVNAME=v_texCoord4D -DNOISEFUN=snoise\ + $(OPTIONS) -DVERSION='#version 120' commonShader.frag $@ + +classicnoise2D.frag: $(SRCDIR)/classicnoise2D.glsl $(COMMON) + cpp -P -I$(SRCDIR) -DSHADER=\"classicnoise2D.glsl\" \ + -DVTYPE=vec2 -DVNAME=v_texCoord2D -DNOISEFUN=cnoise\ + $(OPTIONS) -DVERSION='#version 120' commonShader.frag $@ + +classicnoise3D.frag: $(SRCDIR)/classicnoise3D.glsl $(COMMON) + cpp -P -I$(SRCDIR) -DSHADER=\"classicnoise3D.glsl\" \ + -DVTYPE=vec3 -DVNAME=v_texCoord3D -DNOISEFUN=cnoise\ + $(OPTIONS) -DVERSION='#version 120' commonShader.frag $@ + +classicnoise4D.frag: $(SRCDIR)/classicnoise4D.glsl $(COMMON) + cpp -P -I$(SRCDIR) -DSHADER=\"classicnoise4D.glsl\" \ + -DVTYPE=vec4 -DVNAME=v_texCoord4D -DNOISEFUN=cnoise\ $(OPTIONS) -DVERSION='#version 120' commonShader.frag $@ diff --git a/benchmark/common/commonShader.frag b/benchmark/common/commonShader.frag index 567b935..e26243a 100755 --- a/benchmark/common/commonShader.frag +++ b/benchmark/common/commonShader.frag @@ -1,22 +1,16 @@ VERSION -// uniform vec4 pParam; -// Example constant with a 289-element permutation -const vec4 pParam = vec4( 17.0*17.0, 34.0, 1.0, 7.0); - -#include "noiseStdLib.glsl" #include SHADER uniform float time; // Used for texture animation varying VTYPE VNAME ; + // // main() // void main( void ) { - float n = simplexNoise(VNAME); - + float n = NOISEFUN(VNAME); gl_FragColor = vec4(0.5 + 0.5 * vec3(n, n, n), 1.0); } - diff --git a/benchmark/common/noisebench.c b/benchmark/common/noisebench.c index 759a831..35ec714 100755 --- a/benchmark/common/noisebench.c +++ b/benchmark/common/noisebench.c @@ -1,22 +1,26 @@ - /* - * Testbed for GLSL procedural noise functions. + * Benchmark for GLSL procedural noise functions. * - * Shaders are loaded from two external files: - * "GLSL-ashimanoise.vert" and "GLSL-ashimanoise.frag". - * The program itself draws a spinning sphere - * with a noise-generated fragment color. + * Shaders are loaded from external files, named in + * the macro definitions VERTSHADERFILE and FRAGSHADERFILE*. + * The main program draws a flat plane covering the + * viewport, activates each of six fragment shaders in turn + * and reports the fragment shading performance in Msamples/s + * for each. * * This program uses GLFW for convenience, to handle the OS-specific * window management stuff. Some Windows-specific stuff for extension * loading is still here, but that code is short-circuited on other - * platforms - this file compiles unedited on Windows, Linux and MacOS X. + * platforms - this file compiles unedited on Windows, Linux and MacOS X, + * provided you have the relevant libraries and header files installed + * and set up your compilation to include the GLFW and OpenGL libraries. * * Author: Stefan Gustavson (stegu@itn.liu.se) 2004, 2005, 2010, 2011 + * This code is in the public domain. */ // Identify the exact version of noise being benchmarked -#define NOISEVERSION "2011-03-25" +#define NOISEVERSION "2011-04-03" #include #include @@ -33,21 +37,25 @@ #ifdef __APPLE__ // MacOS application bundles have the executable inside a directory structure -#define VERTEXSHADERFILE2D "../../../GLSL-ashimanoise.vert" -#define FRAGMENTSHADERFILE2D "../../../GLSL-ashimanoise2D.frag" -#define VERTEXSHADERFILE3D "../../../GLSL-ashimanoise.vert" -#define FRAGMENTSHADERFILE3D "../../../GLSL-ashimanoise3D.frag" -#define VERTEXSHADERFILE4D "../../../GLSL-ashimanoise.vert" -#define FRAGMENTSHADERFILE4D "../../../GLSL-ashimanoise4D.frag" +#define VERTSHADERFILE "../../../noisebench.vert" +#define FRAGSHADERFILE_S2D "../../../simplexnoise2D.frag" +#define FRAGSHADERFILE_S3D "../../../simplexnoise3D.frag" +#define FRAGSHADERFILE_S4D "../../../simplexnoise4D.frag" +#define FRAGSHADERFILE_C2D "../../../classicnoise2D.frag" +#define FRAGSHADERFILE_C3D "../../../classicnoise3D.frag" +#define FRAGSHADERFILE_C4D "../../../classicnoise4D.frag" +#define FRAGSHADERFILE_CONST "../../../constant.frag" #define LOGFILENAME "../../../ashimanoise.log" #else // Windows, Linux and other Unix systems expose executables as naked files -#define VERTEXSHADERFILE2D "GLSL-ashimanoise.vert" -#define FRAGMENTSHADERFILE2D "GLSL-ashimanoise2D.frag" -#define VERTEXSHADERFILE3D "GLSL-ashimanoise.vert" -#define FRAGMENTSHADERFILE3D "GLSL-ashimanoise3D.frag" -#define VERTEXSHADERFILE4D "GLSL-ashimanoise.vert" -#define FRAGMENTSHADERFILE4D "GLSL-ashimanoise4D.frag" +#define VERTSHADERFILE "noisebench.vert" +#define FRAGSHADERFILE_S2D "simplexnoise2D.frag" +#define FRAGSHADERFILE_S3D "simplexnoise3D.frag" +#define FRAGSHADERFILE_S4D "simplexnoise4D.frag" +#define FRAGSHADERFILE_C2D "classicnoise2D.frag" +#define FRAGSHADERFILE_C3D "classicnoise3D.frag" +#define FRAGSHADERFILE_C4D "classicnoise4D.frag" +#define FRAGSHADERFILE_CONST "constant.frag" #define LOGFILENAME "ashimanoise.log" #endif @@ -350,7 +358,7 @@ int main(int argc, char *argv[]) { GLuint displayList; GLuint programObject; double performance = 0.0; - int ndims = 2; // Currently running version of noise: 2D, 3D or 4D + int activeshader = 0; // Currently active version of noise shader FILE *logfile; GLFWvidmode vidmode; @@ -382,14 +390,11 @@ int main(int argc, char *argv[]) { logfile = fopen(LOGFILENAME, "w"); - fprintf(logfile, "GL vendor: %s\n", glGetString(GL_VENDOR)); - fprintf(logfile, "GL renderer: %s\n", glGetString(GL_RENDERER)); - fprintf(logfile, "GL version: %s\n", glGetString(GL_VERSION)); - fprintf(logfile, "Desktop size: %d x %d pixels\n", vidmode.Width, vidmode.Height); - - // Create the shader object from two external GLSL source files - createShader(&programObject, VERTEXSHADERFILE2D, FRAGMENTSHADERFILE2D); - fprintf(logfile, "\n2D simplex noise, version %s, ", NOISEVERSION); + fprintf(logfile, "GL vendor: %s\n", glGetString(GL_VENDOR)); + fprintf(logfile, "GL renderer: %s\n", glGetString(GL_RENDERER)); + fprintf(logfile, "GL version: %s\n", glGetString(GL_VERSION)); + fprintf(logfile, "Desktop size: %d x %d pixels\n", vidmode.Width, vidmode.Height); + fprintf(logfile, "Noise version: %s\n\n", NOISEVERSION); // Disable Z buffering for this simple 2D shader benchmark glDisable(GL_DEPTH_TEST); // Use the Z buffer @@ -402,6 +407,59 @@ int main(int argc, char *argv[]) { // Main loop while(running) { + double benchmarktime = 3.0; // Total time to run each shader + // Switch between the different versions of noise + if(activeshader == 0) { + createShader(&programObject, VERTSHADERFILE, FRAGSHADERFILE_CONST); + activeshader++; + fprintf(logfile, "Constant shading, "); + } + if((activeshader == 1) && (glfwGetTime() > benchmarktime * activeshader)) { + fprintf(logfile, "%.1f Msamples/s\n", performance); + createShader(&programObject, VERTSHADERFILE, FRAGSHADERFILE_S2D); + activeshader++; + fprintf(logfile, "2D simplex noise, "); + } + if((activeshader == 2) && (glfwGetTime() > benchmarktime * activeshader)) { + fprintf(logfile, "%.1f Msamples/s\n", performance); + createShader(&programObject, VERTSHADERFILE, FRAGSHADERFILE_S3D); + activeshader++; + fprintf(logfile, "3D simplex noise, "); + } + if((activeshader == 3) && (glfwGetTime() > benchmarktime * activeshader)) { + fprintf(logfile, "%.1f Msamples/s\n", performance); + createShader(&programObject, VERTSHADERFILE, FRAGSHADERFILE_S4D); + activeshader++; + fprintf(logfile, "4D simplex noise, "); + } + if((activeshader == 4) && (glfwGetTime() > benchmarktime * activeshader)) { + fprintf(logfile, "%.1f Msamples/s\n", performance); + createShader(&programObject, VERTSHADERFILE, FRAGSHADERFILE_C2D); + activeshader++; + fprintf(logfile, "2D classic noise, "); + } + if((activeshader == 5) && (glfwGetTime() > benchmarktime * activeshader)) { + fprintf(logfile, "%.1f Msamples/s\n", performance); + createShader(&programObject, VERTSHADERFILE, FRAGSHADERFILE_C3D); + activeshader++; + fprintf(logfile, "3D classic noise, "); + } + if((activeshader == 6) && (glfwGetTime() > benchmarktime * activeshader)) { + fprintf(logfile, "%.1f Msamples/s\n", performance); + createShader(&programObject, VERTSHADERFILE, FRAGSHADERFILE_C4D); + activeshader++; + fprintf(logfile, "4D classic noise, "); + } + if((activeshader == 7) && (glfwGetTime() > benchmarktime * activeshader)) { + fprintf(logfile, "%.1f Msamples/s\n", performance); + running = GL_FALSE; + } + + // Exit prematurely if the ESC key is pressed or the window is closed. + if(glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam(GLFW_OPENED)) { + running = GL_FALSE; + } + // Calculate and update the frames per second (FPS) display performance = computeFPS(); @@ -416,29 +474,6 @@ int main(int argc, char *argv[]) { // Swap buffers, i.e. display the image and prepare for next frame. glfwSwapBuffers(); - - // Switch between 2D, 3D and 4D versions of noise - if((glfwGetTime() > 5.0) && (ndims == 2)) { - fprintf(logfile, "%.1f Msamples/s\n", performance); - createShader(&programObject, VERTEXSHADERFILE3D, FRAGMENTSHADERFILE3D); - fprintf(logfile, "3D simplex noise, version %s, ", NOISEVERSION); - ndims = 3; - } - if((glfwGetTime() > 10.0) && (ndims == 3)) { - fprintf(logfile, "%.1f Msamples/s\n", performance); - createShader(&programObject, VERTEXSHADERFILE4D, FRAGMENTSHADERFILE4D); - fprintf(logfile, "4D simplex noise, version %s, ", NOISEVERSION); - ndims = 4; - } - if((glfwGetTime() > 15.0) && (ndims == 4)) { - fprintf(logfile, "%.1f Msamples/s\n", performance); - running = GL_FALSE; - } - - // Exit prematurely if the ESC key is pressed or the window is closed. - if(glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam(GLFW_OPENED)) { - running = GL_FALSE; - } } // Close the OpenGL window and terminate GLFW. diff --git a/src/classicnoise2D.glsl b/src/classicnoise2D.glsl index 296d6bb..3d13ac8 100644 --- a/src/classicnoise2D.glsl +++ b/src/classicnoise2D.glsl @@ -2,7 +2,7 @@ // GLSL textureless classic 3D noise "cnoise", // with an RSL-style periodic variant "pnoise". // Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-04-01 +// Version: 2011-04-03 // // Many thanks to Ian McEwan of Ashima Arts for the // ideas for permutation and gradient selection. @@ -30,11 +30,8 @@ // THE SOFTWARE. // -#version 120 - vec4 permute(vec4 x) { - x = mod(x, 289.0); return floor(mod(((x*34.0)+1.0)*x, 289.0)); } @@ -50,18 +47,17 @@ vec2 fade(vec2 t) { // Classic Perlin noise float cnoise(vec2 P) { - vec2 Pi = floor(P); // Integer part for indexing - vec2 Pf = fract(P); // Fractional part for interpolation - vec4 ox = vec4(0.0, 1.0, 0.0, 1.0); - vec4 oy = vec4(0.0, 0.0, 1.0, 1.0); - vec4 ix = vec4(Pi.x) + ox; - vec4 iy = vec4(Pi.y) + oy; - vec4 fx = vec4(Pf.x) - ox; - vec4 fy = vec4(Pf.y) - oy; + vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0); + vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, 289.0); // To avoid truncation effects in permutation + vec4 ix = Pi.xzxz; + vec4 iy = Pi.yyww; + vec4 fx = Pf.xzxz; + vec4 fy = Pf.yyww; vec4 i = permute(permute(ix) + iy); - vec4 gx = 2.0 * fract(i / 43.0) - 1.0 ; + vec4 gx = 2.0 * fract(i / 41.0) - 1.0 ; vec4 gy = abs(gx) - 0.5 ; vec4 tx = floor(gx + 0.5); gx = gx - tx; @@ -82,7 +78,7 @@ float cnoise(vec2 P) float n01 = dot(g01, vec2(fx.z, fy.z)); float n11 = dot(g11, vec2(fx.w, fy.w)); - vec2 fade_xy = fade(Pf); + vec2 fade_xy = fade(Pf.xy); vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x); float n_xy = mix(n_x.x, n_x.y, fade_xy.y); return 2.3 * n_xy; @@ -91,18 +87,18 @@ float cnoise(vec2 P) // Classic Perlin noise, periodic variant float pnoise(vec2 P, vec2 rep) { - vec2 Pi = floor(P); // Integer part for indexing - vec2 Pf = fract(P); // Fractional part for interpolation - vec4 ox = vec4(0.0, 1.0, 0.0, 1.0); - vec4 oy = vec4(0.0, 0.0, 1.0, 1.0); - vec4 ix = mod(vec4(Pi.x) + ox, rep.x); // Index modulo period. The only - vec4 iy = mod(vec4(Pi.y) + oy, rep.y); // difference from cnoise(). - vec4 fx = vec4(Pf.x) - ox; - vec4 fy = vec4(Pf.y) - oy; + vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0); + vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0); + Pi = mod(Pi, rep.xyxy); // To create noise with explicit period + Pi = mod(Pi, 289.0); // To avoid truncation effects in permutation + vec4 ix = Pi.xzxz; + vec4 iy = Pi.yyww; + vec4 fx = Pf.xzxz; + vec4 fy = Pf.yyww; vec4 i = permute(permute(ix) + iy); - vec4 gx = 2.0 * fract(i / 43.0) - 1.0 ; + vec4 gx = 2.0 * fract(i / 41.0) - 1.0 ; vec4 gy = abs(gx) - 0.5 ; vec4 tx = floor(gx + 0.5); gx = gx - tx; @@ -123,7 +119,7 @@ float pnoise(vec2 P, vec2 rep) float n01 = dot(g01, vec2(fx.z, fy.z)); float n11 = dot(g11, vec2(fx.w, fy.w)); - vec2 fade_xy = fade(Pf); + vec2 fade_xy = fade(Pf.xy); vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x); float n_xy = mix(n_x.x, n_x.y, fade_xy.y); return 2.3 * n_xy; diff --git a/src/classicnoise3D.glsl b/src/classicnoise3D.glsl index 22d73e2..a81f08f 100644 --- a/src/classicnoise3D.glsl +++ b/src/classicnoise3D.glsl @@ -2,7 +2,7 @@ // GLSL textureless classic 3D noise "cnoise", // with an RSL-style periodic variant "pnoise". // Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-04-01 +// Version: 2011-04-03 // // Many thanks to Ian McEwan of Ashima Arts for the // ideas for permutation and gradient selection. @@ -30,8 +30,6 @@ // THE SOFTWARE. // -#version 120 - vec4 permute(vec4 x) { x = mod(x, 289.0); @@ -119,8 +117,8 @@ float cnoise(vec3 P) float pnoise(vec3 P, vec3 rep) { vec3 Pi0 = mod(floor(P), rep); // Integer part, modulo period - vec3 Pf0 = fract(P); // Fractional part for interpolation vec3 Pi1 = mod(Pi0 + vec3(1.0), rep); // Integer part + 1, mod period + vec3 Pf0 = fract(P); // Fractional part for interpolation vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); vec4 iy = vec4(Pi0.yy, Pi1.yy); diff --git a/src/noise2D.glsl b/src/noise2D.glsl index fd1c6dd..100a2d9 100644 --- a/src/noise2D.glsl +++ b/src/noise2D.glsl @@ -1,25 +1,33 @@ // -// Description : Array and textureless GLSL 2D/3D/4D simplex -// noise functions. +// Description : Array and textureless GLSL 2D simplex noise function. // Author : Ian McEwan, Ashima Arts. // Maintainer : ijm -// Lastmod : 20110327 +// Lastmod : 20110403 (stegu) // License : Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // -float simplexNoise(vec2 v) +vec3 permute(vec3 x) +{ + return floor(mod(((x*34.0)+1.0)*x, 289.0)); +} + +vec3 taylorInvSqrt(vec3 r) +{ + return 1.79284291400159 - 0.85373472095314 * r; +} + +float snoise(vec2 v) { const vec2 C = vec2(0.211324865405187134, // (3.0-sqrt(3.0))/6.0; 0.366025403784438597); // 0.5*(sqrt(3.0)-1.0); - const vec3 D = vec3( 0.0, 0.5, 2.0) * 3.14159265358979312; // First corner vec2 i = floor(v + dot(v, C.yy) ); vec2 x0 = v - i + dot(i, C.xx); // Other corners vec2 i1; - i1.x = float( (x0.x>x0.y) ); + i1.x = step( x0.y, x0.x ); // 1.0 if x0.x > x0.y, else 0.0 i1.y = 1.0 - i1.x; // x0 = x0 - 0.0 + 0.0 * C.xx ; @@ -30,46 +38,26 @@ float simplexNoise(vec2 v) xC.xy -= i1; // Permutations - i = mod(i, pParam.x); - vec3 p = permute( permute( - i.y + vec3(0.0, i1.y, 1.0 ), pParam.xyz) - + i.x + vec3(0.0, i1.x, 1.0 ), pParam.xyz); + i = mod(i, 289.0); // Avoid truncation effects in permutation + vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + + i.x + vec3(0.0, i1.x, 1.0 )); vec3 m = max(0.5 - vec3(dot(x0,x0), dot(xC.xy,xC.xy), dot(xC.zw,xC.zw)), 0.0); m = m*m ; m = m*m ; -#ifndef USE_CIRCLE + // ( N points uniformly over a line, mapped onto a diamond.) - vec3 x = 2.0 * fract(p / pParam.w) - 1.0 ; + vec3 x = 2.0 * fract(p / 41.0) - 1.0 ; vec3 h = abs(x) - 0.5 ; - - vec3 ox = floor(x+0.5); - + vec3 ox = floor(x + 0.5); vec3 a0 = x - ox; -# ifdef NORMALISE_GRADIENTS +// Normalise gradients implicitly by scaling m m *= taylorInvSqrt( a0*a0 + h*h ); -# endif - //vec2 p0 = vec2(a0.x,h.x); - //vec2 p1 = vec2(a0.y,h.y); - //vec2 p2 = vec2(a0.z,h.z); - //vec3 g = vec3( dot(p0, x0), dot(p1, xC.xy), dot(p2, xC.zw) ); +// Compute final noise value at P vec3 g; -// a0 *= m; -// h *= m; g.x = a0.x * x0.x + h.x * x0.y; g.yz = a0.yz * xC.xz + h.yz * xC.yw; - -#else -// N points around a unit circle. - vec3 phi = D.z * mod(p,pParam.w) /pParam.w ; - vec4 a0 = sin(phi.xxyy+D.xyxy); - vec2 a1 = sin(phi.zz +D.xy); -// mix - vec3 g = vec3( dot(a0.xy, x0), dot(a0.zw, xC.xy), dot(a1.xy, xC.zw) ); -#endif - return 130.0 * dot(m, g); - - } +} diff --git a/src/noise3D.glsl b/src/noise3D.glsl index 9eb21fe..fd452c3 100644 --- a/src/noise3D.glsl +++ b/src/noise3D.glsl @@ -3,14 +3,24 @@ // noise functions. // Author : Ian McEwan, Ashima Arts. // Maintainer : ijm -// Lastmod : 20110327 +// Lastmod : 20110403 (stegu) // License : Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // -float simplexNoise(vec3 v) +vec4 permute(vec4 x) +{ + return floor(mod(((x*34.0)+1.0)*x, 289.0)); +} + +vec4 taylorInvSqrt(vec4 r) +{ + return 1.79284291400159 - 0.85373472095314 * r; +} + +float snoise(vec3 v) { - const vec2 C = vec2(1.0/6.0, 1.0/3.0 ) ; + const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); // First corner @@ -18,56 +28,32 @@ float simplexNoise(vec3 v) vec3 x0 = v - i + dot(i, C.xxx) ; // Other corners -#ifdef COLLAPSE_SORTNET - vec3 g = vec3( greaterThan( x0.xyz, x0.yzx) ); -// vec3 l = vec3( lessThanEqual( x0.xyz, x0.yzx) ); + vec3 g = step(x0.yzx, x0.xyz); vec3 l = 1.0 - g; vec3 i1 = min( g.xyz, l.zxy ); vec3 i2 = max( g.xyz, l.zxy ); -#else -// Keeping this clean - let the compiler optimize. -// Force existence of strict total ordering in sort. - vec3 q0 = floor(x0 * 1024.0) + vec3( 0.0, 1.0/4.0, 2.0/4.0); - vec3 q1; - q1.x = max(q0.x, q0.y); - q1.y = min(q0.x, q0.y); - q1.z = q0.z; - vec3 q2; - q2.x = max(q1.x,q1.z); - q2.z = min(q1.x,q1.z); - q2.y = q1.y; - - vec3 q3; - q3.y = max(q2.y, q2.z); - q3.z = min(q2.y, q2.z); - q3.x = q2.x; - - vec3 i1 = vec3(lessThanEqual(q3.xxx, q0)); - vec3 i2 = vec3(lessThanEqual(q3.yyy, q0)); -#endif - - // x0 = x0 - 0. + 0.0 * C + // x0 = x0 - 0. + 0.0 * C vec3 x1 = x0 - i1 + 1.0 * C.xxx; vec3 x2 = x0 - i2 + 2.0 * C.xxx; vec3 x3 = x0 - 1. + 3.0 * C.xxx; // Permutations - i = mod(i, pParam.x ); + i = mod(i, 289.0 ); vec4 p = permute( permute( permute( - i.z + vec4(0.0, i1.z, i2.z, 1.0 ), pParam.xyz) - + i.y + vec4(0.0, i1.y, i2.y, 1.0 ), pParam.xyz) - + i.x + vec4(0.0, i1.x, i2.x, 1.0 ), pParam.xyz); + i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); // Gradients // ( N*N points uniformly over a square, mapped onto a octohedron.) - float n_ = 1.0/pParam.w ; - vec3 ns = n_ * D.wyz - D.xzx ; + float n_ = 1.0/7.0; // N=7 + vec3 ns = n_ * D.wyz - D.xzx; - vec4 j = p - pParam.w*pParam.w*floor(p * ns.z *ns.z); // mod(p,N*N) + vec4 j = p - 49.0 * floor(p * ns.z *ns.z); // mod(p,N*N) - vec4 x_ = floor(j * ns.z) ; - vec4 y_ = floor(j - pParam.w * x_ ) ; // mod(j,N) + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) vec4 x = x_ *ns.x + ns.yyyy; vec4 y = y_ *ns.x + ns.yyyy; @@ -76,11 +62,11 @@ float simplexNoise(vec3 v) vec4 b0 = vec4( x.xy, y.xy ); vec4 b1 = vec4( x.zw, y.zw ); - //vec4 s0 = vec4(lessThan(b0,D.xxxx)) *2.0 -1.0; - //vec4 s1 = vec4(lessThan(b1,D.xxxx)) *2.0 -1.0; - vec4 s0 = floor(b0) *2.0 +1.0; - vec4 s1 = floor(b1) *2.0 +1.0; - vec4 sh = -vec4(lessThan(h, D.xxxx)); + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0)*2.0 + 1.0; + vec4 s1 = floor(b1)*2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; @@ -90,15 +76,15 @@ float simplexNoise(vec3 v) vec3 p2 = vec3(a1.xy,h.z); vec3 p3 = vec3(a1.zw,h.w); -#ifdef NORMALISE_GRADIENTS - p0 *= taylorInvSqrt(dot(p0,p0)); - p1 *= taylorInvSqrt(dot(p1,p1)); - p2 *= taylorInvSqrt(dot(p2,p2)); - p3 *= taylorInvSqrt(dot(p3,p3)); -#endif +//Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; -// Mix - vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.); +// Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); m = m * m; return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) ); diff --git a/src/noise4D.glsl b/src/noise4D.glsl index 3a2bb05..4ffefc4 100644 --- a/src/noise4D.glsl +++ b/src/noise4D.glsl @@ -3,17 +3,37 @@ // noise functions. // Author : Ian McEwan, Ashima Arts. // Maintainer : ijm -// Lastmod : 20110327 +// Lastmod : 20110403 (stegu) // License : Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. // +vec4 permute(vec4 x) +{ + return floor(mod(((x*34.0)+1.0)*x, 289.0)); +} + +float permute(float x) +{ + return floor(mod(((x*34.0)+1.0)*x, 289.0)); +} + +vec4 taylorInvSqrt(vec4 r) +{ + return 1.79284291400159 - 0.85373472095314 * r; +} + +float taylorInvSqrt(float r) +{ + return 1.79284291400159 - 0.85373472095314 * r; +} + vec4 grad4(float j, vec4 ip) { const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0); vec4 p,s; - p.xyz = floor( fract (vec3(j) * ip.xyz) *pParam.w) * ip.z - 1.0; + p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0; p.w = 1.5 - dot(abs(p.xyz), ones.xyz); s = vec4(lessThan(p, vec4(0.0))); p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www; @@ -21,7 +41,7 @@ vec4 grad4(float j, vec4 ip) return p; } -float simplexNoise(vec4 v) +float snoise(vec4 v) { const vec2 C = vec2( 0.138196601125010504, // (5 - sqrt(5))/20 G4 0.309016994374947451); // (sqrt(5) - 1)/4 F4 @@ -31,8 +51,7 @@ float simplexNoise(vec4 v) // Other corners -#ifdef COLLAPSE_SORTNET - // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) +// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) vec4 i0; vec3 isX = step( x0.yzw, x0.xxx ); @@ -52,26 +71,6 @@ float simplexNoise(vec4 v) vec4 i3 = clamp( i0, 0.0, 1.0 ); vec4 i2 = clamp( i0-1.0, 0.0, 1.0 ); vec4 i1 = clamp( i0-2.0, 0.0, 1.0 ); -#else -// Force existence of strict total ordering in sort. - vec4 q0 = floor(x0 * 1024.0) + vec4( 0.0, 1.0/4.0, 2.0/4.0 , 3.0/4.0); - vec4 q1; - q1.xy = max(q0.xy, q0.zw); // x:z y:w - q1.zw = min(q0.xy, q0.zw); - - vec4 q2; - q2.xz = max(q1.xz, q1.yw); // x:y z:w - q2.yw = min(q1.xz, q1.yw); - - vec4 q3; - q3.y = max(q2.y, q2.z); // y:z - q3.z = min(q2.y, q2.z); - q3.xw = q2.xw; - - vec4 i1 = vec4(lessThanEqual(q3.xxxx, q0)); - vec4 i2 = vec4(lessThanEqual(q3.yyyy, q0)); - vec4 i3 = vec4(lessThanEqual(q3.zzzz, q0)); -#endif // x0 = x0 - 0.0 + 0.0 * C vec4 x1 = x0 - i1 + 1.0 * C.xxxx; @@ -80,27 +79,18 @@ float simplexNoise(vec4 v) vec4 x4 = x0 - 1.0 + 4.0 * C.xxxx; // Permutations - i = mod(i, pParam.x); - float j0 = permute( permute( permute( permute ( - i.w, pParam.xyz) + i.z, pParam.xyz) - + i.y, pParam.xyz) + i.x, pParam.xyz); + i = mod(i, 289.0); + float j0 = permute( permute( permute( permute(i.w) + i.z) + i.y) + i.x); vec4 j1 = permute( permute( permute( permute ( - i.w + vec4(i1.w, i2.w, i3.w, 1.0 ), pParam.xyz) - + i.z + vec4(i1.z, i2.z, i3.z, 1.0 ), pParam.xyz) - + i.y + vec4(i1.y, i2.y, i3.y, 1.0 ), pParam.xyz) - + i.x + vec4(i1.x, i2.x, i3.x, 1.0 ), pParam.xyz); + i.w + vec4(i1.w, i2.w, i3.w, 1.0 )) + + i.z + vec4(i1.z, i2.z, i3.z, 1.0 )) + + i.y + vec4(i1.y, i2.y, i3.y, 1.0 )) + + i.x + vec4(i1.x, i2.x, i3.x, 1.0 )); // Gradients // ( 7*7*6 points uniformly over a cube, mapped onto a 4-octahedron.) -// The permutation ring is 17*17, and that should be close -// to an even multiple of the number of points to avoid -// directional preferences for the noise field. -// 7*7*6 = 294, which is close to 17*17 = 289. +// 7*7*6 = 294, which is close to the ring size 17*17 = 289. - vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ; -// vec4 ip = vec4(pParam.w) ; -// ip.xy *= pParam.w ; -// ip.x *= pParam.w ; -// ip = vec4(1.0, 1.0, 1.0, 2.0) / ip ; + vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ; vec4 p0 = grad4(j0, ip); vec4 p1 = grad4(j1.x, ip); @@ -108,13 +98,13 @@ float simplexNoise(vec4 v) vec4 p3 = grad4(j1.z, ip); vec4 p4 = grad4(j1.w, ip); -#ifdef NORMALISE_GRADIENTS - p0 *= taylorInvSqrt(dot(p0,p0)); - p1 *= taylorInvSqrt(dot(p1,p1)); - p2 *= taylorInvSqrt(dot(p2,p2)); - p3 *= taylorInvSqrt(dot(p3,p3)); +// Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; p4 *= taylorInvSqrt(dot(p4,p4)); -#endif // Mix contributions from the five corners vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0); diff --git a/src/noiseStdLib.glsl b/src/noiseStdLib.glsl deleted file mode 100644 index abd162e..0000000 --- a/src/noiseStdLib.glsl +++ /dev/null @@ -1,33 +0,0 @@ -// -// Description : Array and textureless GLSL 2D/3D/4D simplex -// noise functions. Library function. -// Author : Ian McEwan, Ashima Arts. -// Maintainer : ijm -// Lastmod : 20110227 -// License : Copyright (C) 2011 Ashima Arts. All rights reserved. -// Distributed under the MIT License. See LICENSE file. -// - -#ifdef FASTMOD -# define PERMMOD(X,Y) (X) -#else -# define PERMMOD(X,Y) mod((X),(Y)) -#endif - -#define PERMFUN(X) X permute(X x, vec3 p) { \ - return floor( mod( (PERMMOD(x * p.y, p.x) + p.z)*x, p.x)); } - -PERMFUN(float) -PERMFUN(vec2) -PERMFUN(vec3) -PERMFUN(vec4) - -#define TAYLOR_L07(X) X taylorInvSqrt(X r) { \ - return ( 1.195228609334394 + 0.7*0.85373472095314 - 0.85373472095314 * r ); } - -TAYLOR_L07(float) -TAYLOR_L07(vec2) -TAYLOR_L07(vec3) -TAYLOR_L07(vec4) - -