Diamond Square Noise and Plasma Effect ● SmileBASIC Source

Register
What's going on?? See: Site Update March 2022

# Diamond Square Noise and Plasma Effect

This tutorial will not go into much depth about the code. An implementation of the plasma (with messier code than what's shown here) is available for testing in the RNDLIBTEST program of Random's Big Dumb Library. You can use it to test out various color and parameter combinations without having to reprogram them yourself.

# Random Noise

Random noise is a block of seemingly random data which actually has a semblance of a pattern. It can be used to generate terrain, clouds, AI, textures, and basically anything else that requires "controlled" randomness. Purely random noise looks like TV static. It's not very useful: But controlled random noise looks much nicer: We're going to use the Diamond Square algorithm (a controlled random noise generator) to make the plasma effect you see in the video above.

# Diamond Square

Diamond Square is a noise generator algorithm which uses 4 initial starting values and a series of decaying averages to generate interesting patterns. If you are interested in understanding the algorithm, more information can be found here: https://en.wikipedia.org/wiki/Diamond-square_algorithm First, we're going to need one other function: normalization. Noise isn't useful unless it's constrained to a known range, and default Diamond Square doesn't do this. Normalization will force the values (after generation) into the range of 0-1 (both inclusive). NOTE: Reusable code is the best code. All code here will be made into functions. ```COMMON DEF NORMALIZE2D D#,SIZEX,SIZEY DIM MINV#=MIN(D#) DIM MAXV#=MAX(D#) DIM RANGE#=MAXV#-MINV# DIM X,Y FOR Y=0 TO SIZEY-1 FOR X=0 TO SIZEX-1 D#[X,Y]=(D#[X,Y]-MINV#)/RANGE# NEXT NEXT END```This function is included in Random's Big Dumb Library Now we can do Diamond Square. Diamond square works on a chunk system like minecraft: each chunk is 2N wide and tall and the overall array is a series of these chunks. The array that's returned is JUST a 2D array of values though; the chunks are "imaginary" and are only used in the algorithm. The parameters are: Feature Size (N), Width (Chunks across), Height (Chunks down), Seed (same seed = same noise), Decay (lower=smoother noise). The final dimensions of the returned noise array is (2N*Width+1,2N*Height+1). The Feature Size (N parameter) determines how "big" all the bumps are. Larger N = larger bumps, but remember it scales up by powers of 2 so don't go larger than 8 or so (28 is 256). At 1, the array will be nearly random static noise like the first picture. Experiment with N to find a good feature size for your needs. The decay is inverse smoothness: from 0 to 0.5, it will be exceptionally smooth. From 0.5 on it gets more rough: at 1 (the highest value you should give), it looks like you mixed the static with the good noise. Again, just experiment to find the value you like. It's a parameter for a reason. In our function, we use a seeded random number generator. SB comes with 8 different generators: we're using #7. If you need a different one, just change S. ```COMMON DEF DIAMONDSQUARE#(N,WD,HT,SEED,DECAY#) DIM S=7 DIM BLOCK=POW(2,N) DIM SIZEX=BLOCK*WD+1 DIM SIZEY=BLOCK*HT+1 DIM ENDX=SIZEX-1 DIM ENDY=SIZEY-1 DIM D#[SIZEX,SIZEY] 'Final noise array. DIM P,RDEC#,OFS,HLF,X,Y,NUM,BX,BY DIM TOP,BOTTOM,LEFT,RIGHT,REDUX 'Optimization stuff RANDOMIZE S,SEED 'Corners (DS uses initial 4 corner values of each chunk to generate entire array) FOR Y=0 TO HT FOR X=0 TO WD D#[X*BLOCK,Y*BLOCK]=RNDF(S) NEXT NEXT 'Shrinking chunk series (look up Diamond Square to see what this is) FOR P=N TO 1 STEP -1 RDEC#=POW(DECAY#,N-P)*0.25 'Decaying randomness (plus a magic constant shrinking) OFS=POW(2,P) HLF=OFS/2 'Diamonds FOR Y=HLF TO ENDY STEP OFS FOR X=HLF TO ENDX STEP OFS D#[X,Y]=(D#[X-HLF,Y-HLF]+D#[X+HLF,Y-HLF]+D#[X-HLF,Y+HLF]+D#[X+HLF,Y+HLF])/4+(0.5-RNDF(S))*RDEC# NEXT NEXT 'Squares FOR Y=0 TO ENDY STEP HLF NUM=4 'All these TOP/BOTTOM/LEFT/RIGHT checks are because the square step might go out of bounds and we need to handle that IF Y>0 THEN TOP=Y-HLF ELSE TOP=Y:NUM=3 IF Y<ENDY THEN BOTTOM=Y+HLF ELSE BOTTOM=Y:NUM=3 FOR X=HLF*((Y AND (OFS-1))==0) TO ENDX STEP OFS REDUX=0 IF X>0 THEN LEFT=X-HLF ELSE LEFT=X:REDUX=1 IF X<ENDX THEN RIGHT=X+HLF ELSE RIGHT=X:REDUX=1 D#[X,Y]=(D#[X,TOP]+D#[X,BOTTOM]+D#[LEFT,Y]+D#[RIGHT,Y])/(NUM-REDUX)+(0.5-RNDF(S))*RDEC# NEXT NEXT NEXT NORMALIZE2D D#,SIZEX,SIZEY RETURN D# END```This function is included in Random's Big Dumb Library

# Plasma Effect

We will use the result from the DIAMONDSQUARE#() algorithm and convert it into palette data to use in GLOAD. We will only need to generate the noise array once (which takes time), but then we can use the same array for each frame of the animation and just shift the palette colors. Basically, each element in the array will change from 0-1 to, for instance, 0-255, then we'll generate 256 colors for the palette and use GLOAD (which draws palette data with the given colors onto the current GRP) to draw the plasma. Each frame, we'll rotate the palette by 1 so the colors seem to "move" around. The Diamond Square noise gives it that plasma feel. Note: you can use this same method to generate many other kinds of animations. GLOAD is a powerful tool.

## Color smoothing

We can't just plop palette colors into an array. To make it look like plasma, the colors need to smoothly transition to each other. Here's a simple color smoothing algorithm which using linear interpolation to blend two colors together by a certain amount: ```COMMON DEF LERP(A#,B#,T#) T#=MIN(ABS(T#),1) RETURN A#+T#*(B#-A#) END 'Shift is how much of each color to use. 0=all col1, 1=all col2, 0.5=half and half COMMON DEF BLENDCOLORS(COL1,COL2,SHIFT#) DIM C1R,C1G,C1B,C2R,C2G,C2B,A1,A2 RGBREAD COL1 OUT A1,C1R,C1G,C1B RGBREAD COL2 OUT A2,C2R,C2G,C2B RETURN RGB(FLOOR(LERP(A1,A2,SHIFT#)),FLOOR(LERP(C1R,C2R,SHIFT#)),FLOOR(LERP(C1G,C2G,SHIFT#)),FLOOR(LERP(C1B,C2B,SHIFT#))) END```These functions are included in Random's Big Dumb Library

## Plasma

Now for plasma. Note that I'm picking kinda arbitrary parameters for the noise: N, width, and height are VERY important, but the others are just values I like. ```DIM N=5 DIM WD=8 DIM HT=8 DIM DECAY#=0.8 DIM DS#[0,0] 'Raw Diamond Square data DIM PCNT=256 'How many colors in the whole palette (try to keep it under 256; more is unnecessary) DIM PL[PCNT] 'The palette of blended colors DIM CCNT=4 'The separate pure colors to use in the plasma (count) DIM COLS[CCNT] 'This is a red and blue plasma like in the video. We insert black between to make it look cooler COLS[0]=#RED COLS[1]=#BLACK COLS[2]=#BLUE COLS[3]=#BLACK 'Use MILLISEC as seed to make it random plasma each time DS#=DIAMONDSQUARE#(N,WD,HT,MILLISEC,DECAY#) 'Convert DS raw to palette data. Remember how big the DS array is: DIM SIZEX=POW(2,N)*WD+1 DIM SIZEY=POW(2,N)*HT+1 DIM X,Y,C,I,P DIM PD[SIZEY,SIZEX] 'Diamond Square data converted to palette range. We reverse X and Y because of how SB does GLOAD FOR X=0 TO SIZEX-1 FOR Y=0 TO SIZEY-1 PD[Y,X]=CEIL((PCNT-1)*DS#[X,Y]) NEXT NEXT 'Generate the base plasma palette. Iterate over each color, then spread out the blending over the palette range FOR C=0 TO CCNT-1 FOR I=0 TO PCNT/CCNT P=C*PCNT/CCNT+I IF P>=PCNT THEN BREAK PL[P]=BLENDCOLORS(COLS[C],COLS[(C+1)MOD CCNT],I/(PCNT/CCNT)) NEXT NEXT 'Now just display the plasma. Remember that GLOAD needs the correct width and height of the array. Also remember we're rotating the palette WHILE TRUE GLOAD 0,0,SIZEX,SIZEY,PD,PL,FALSE C=SHIFT(PL) PUSH PL,C VSYNC WEND ``` If you have any questions or if the code doesn't work, please let me know. I might've made a typo or something.
Updated
Rating
3 Comment(s) 12Me21 Syntax Highlighter Received for creating the code syntax highlighter on SBS Night Person I like the quiet night and sleep late. Express Yourself It might be faster to COPY between two arrays instead of using SHIFT/POP (though I don't know if this significantly affects the overall speed) randomous Owner Robot Hidden Easter Eggs Second Year My account is over 2 years old Website Drawing I like to draw! Hobbies How would that work? Does COPY wrap around? 12Me21 Syntax Highlighter Received for creating the code syntax highlighter on SBS Night Person I like the quiet night and sleep late. Express Yourself I mean, you'd have to do 2 COPYs ```source: 12345 dest: ..... ..123 'copy 1 54123 'copy 2 ```