Fail attempt at Perlin noise algorithm

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
IcarusLives
Posts: 161
Joined: 17 Jan 2016 23:55

Fail attempt at Perlin noise algorithm

#1 Post by IcarusLives » 01 Jan 2017 23:46

Hello all,

I've been attempting to create the perlin noise algorithm. perlin noise algorithm

I really was hoping I could use this algorithm for some possible terrain generation for some sort of a game. I find the idea of perlin noise to be very interesting.

Upon my research I've learned that a piece of the algorithm consists of a smoothstep algorithm, which is given a value from a "clamp" function.

Here is my attempt at this code. I've only really gotten up to the smoothStep part, and implementing it into perlin noise is really challenging for me.

Only tested on Win10. Uses mshta javascript for floating point numbers

Code: Select all

@echo off & setlocal enableDelayedExpansion


   
    call :init



:main
   cls
    for /l %%a in (0,9,99) do (
        set /a "r=%%a"
    REM for /l %%a in (1,1,10) do (
        REM set /a "r=!random! %% %edge1% + %edge0%"
       
        call :clamp x "(!r! - %edge0%)/(%edge1% - %edge0%)" 0.000 1.000
        ::smoothstep(x) = 3x^2  - 2x^3
        call :float_JS "smoothstep=!x! * !x! * ( 3 - 2 * !x!)"
       
        echo !smoothstep!
        REM call :genDisp !smoothstep:~2,1!
    )
pause & exit

:genDisp
    set "o="
        if not "!smoothstep:~2,1!" equ "" (
            for /l %%0 in (1,1,%1) do set "o=!o! "
            echo !o!#
        )
goto :eof


:prep_smoothStep
    set /a "edge0=%1", "edge1=%2"
goto :eof

:clamp
    call :float_JS "r=%~2"
    if %r:~0,5% lss %3 ( set "%1=%3" ) else if %r:~0,5% gtr %4 ( set "%1=%4" ) else set "%1=%r:~0,5%"
    set "r="
goto :eof

:float_JS
    ( for /f "tokens=1,2 delims==" %%a in ("%~1") do (
        for /f %%N in ('%beginJS% %%b %endJS%') do set "%%a=%%N"
    ))
goto :eof

:init
    set "beginJS=mshta "javascript:close(new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1).Write(eval("
    set "endJS=)));""
    call :prep_smoothStep 1 99
goto :eof


OUTPUT:

Code: Select all

1
1
0.079431566
0.17345575
0.291348414
0.422281216
0.559872
0.693400064
0.813521152
0.910891008
0.976165376
1
Press any key to continue . . .


With all honesty, I believe I've done everything right so far, but something feels off to me. Opinions?
Last edited by IcarusLives on 02 Jan 2017 15:22, edited 5 times in total.

penpen
Expert
Posts: 1991
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Fail attempt at Perlin noise algorithm

#2 Post by penpen » 02 Jan 2017 07:34

On a first look your smoothstep implementation seems to be OK.

Note that when using this batch in multiple regions, the format of a floating point number may be unexpected:

Code: Select all

1.23456
1,23456    ("if" won't work at all, because the comma character is a seperator.)
+1.23456   (second "if" may fail, for example: if "+0.23400" gtr "1.00000" echo ok)
1.235
So you should enforce the number format you expect by yourself within :float_JS.

Your clamp should produce errors on negative numbers, because "batch if" cannot compare floating point numbers:

Code: Select all

:: line: if %r:~0,7% lss %3 (
:: this fails:
if "-1.23400" lss "0.00000" echo ok


penpen

IcarusLives
Posts: 161
Joined: 17 Jan 2016 23:55

Re: Fail attempt at Perlin noise algorithm

#3 Post by IcarusLives » 02 Jan 2017 14:59

penpen wrote:Your clamp should produce errors on negative numbers, because "batch if" cannot compare floating point numbers:

Code: Select all

:: line: if %r:~0,7% lss %3 (
:: this fails:
if "-1.23400" lss "0.00000" echo ok


penpen


I'm unsure about how this works on other OS's, but I'm running Win10. From what testing I have done. You must notice that there are an equ number of digits. I "believe" this works, because 'IF' will ignore the period if comparing gtr, geq, lss, or leq. Much like comparing the number as a whole number.

For example: 63.2 > 19.2 OR 632 > 192.

This is true in both situations, and the '.' is simply ignored.

Code: Select all

>if 1.2 gtr 1.3 (echo yes) else (echo no)
no

>if 1.4 gtr 1.3 (echo yes) else (echo no)
yes

>if 63.4 gtr 99.0 (echo yes) else (echo no)
no

>if 63.4 gtr 19.0 (echo yes) else (echo no)
yes

>


These below however will NOT work properly. You will notice that there were a different number of digits in each comparison.
NONE of these if statements below are correct

Code: Select all

>if 63.2 lss 100.0 (echo yes) else (echo no)
no

>if 63.2 lss 9.0 (echo yes) else (echo no)
yes

>if 63.2 gtr 9.0 (echo yes) else (echo no)
no

>if 1.2 gtr 1.14 (echo yes) else (echo no)
yes

>

penpen
Expert
Posts: 1991
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Fail attempt at Perlin noise algorithm

#4 Post by penpen » 03 Jan 2017 10:37

IcarusLives wrote:I'm unsure about how this works on other OS's, but I'm running Win10. From what testing I have done. You must notice that there are an equ number of digits. I "believe" this works, because 'IF' will ignore the period if comparing gtr, geq, lss, or leq. Much like comparing the number as a whole number.
1) I gave you an example (with the same numbers of digits) where it fails (although i have added doublequotes;
you could enhance it (removing the doublequotes in order to be nearer to your first ":clamp if" instruction) to:

Code: Select all

Z:\>if -1.23400 lss 0.00000 (echo ok) else echo fail
fail

Z:\>
Your ":clamp" function depends on this case when clamping (should clamp -1.23400 to 0.00000, but it doesn't).

2) The "batch if" command doesn't ignore dots or something like that.
Instead if the comparands are not (decimal/octal/hexadecimal) integer numbers, then they are compared as (UCS-2) strings:
But i admit that in this case the result is unexpected... (because in UCS-2 '-' == 0x002D < 0x0030 == '0'; so the above if instruction should return ok),
so Microsoft seems to use a custom sort order (at least under "my" Win10 32-bit.).

Examples:

Code: Select all

Z:\>if .0 lss 0. echo fail
fail

Z:\>rem because of ('.' == 0x002E < 0x0030 == '0')

Z:\>if -1.23400 lss 0.00000 (echo ok) else echo fail
fail

Z:\>if -123400 lss 000000 (echo ok) else echo fail
ok

Z:\>


3) Actually your implementation doesn't ensure that the floating point numbers have the same number of digits; example:
6.54321 versus 76.54321.

4) Even if you were using the same number of digits the result might be unexpected

Code: Select all

Z:\>if -1.2 lss +1.2 (echo ok) else echo fail
fail

Z:\>

5) Your above "if" test cases the dot is compared to itself (if reached by comparison).


penpen

IcarusLives
Posts: 161
Joined: 17 Jan 2016 23:55

Re: Fail attempt at Perlin noise algorithm

#5 Post by IcarusLives » 03 Jan 2017 10:57

penpen wrote:snip


Ahh, ofc. Perhaps a better way would be to split them using . as a delimeter and do comparisons without it. This should result more accurately.

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Fail attempt at Perlin noise algorithm

#6 Post by Aacini » 03 Jan 2017 19:24

I like this type of applications, so I read the Wikipedia article and then tried to review your program, but this was very hard to me because the code organization and the frequent jumps required to review parameters and values defined elsewhere... So I wrote my own version instead:

Code: Select all

@echo off
setlocal EnableDelayedExpansion

rem Define the limits, step and edges for the test
set /A start=-4, step=9, end=108,  edge0=1, edge1=99

rem Define the number of decimals
set /A decimals=3

rem Define the values used to manage fixed point arithmetic
rem http://www.dostips.com/forum/viewtopic.php?f=3&t=2704&p=12523#p12523
set /A one=1, decimalsP1=decimals+1
for /L %%i in (1,1,%decimals%) do set "one=!one!0"

rem Define clamp(x) and smoothstep(x) functions
rem http://www.dostips.com/forum/viewtopic.php?f=3&t=6744
set "clamp(x)=(x - edge0)*one/(edge1 - edge0)"
set "smoothstep(x)=(3*one - 2*x) * x/one * x/one"

rem Insert a TAB after the equal sign:
set "TAB=   "

cls
echo edge0=%edge0%,  edge1=%edge1%
echo/
echo x!TAB!clamp!TAB!smoothstep
echo --------------------------

set /A edge0*=one, edge1*=one
for /L %%a in (%start%,%step%,%end%) do (

   set /A "r=%%a*one, x=%clamp(x):x=r%"
   if !x! lss 0 (set "x=0") else if !x! gtr %one% set "x=%one%"
   set /A "smooth=%smoothstep(x)%"

   set "clamp=000000000!x!" & set "clamp=!clamp:~-%decimalsP1%!
   set "smooth=000000000!smooth!" & set "smooth=!smooth:~-%decimalsP1%!
   echo %%a!TAB!!clamp:~0,-%decimals%!.!clamp:~-%decimals%!!TAB!!smooth:~0,-%decimals%!.!smooth:~-%decimals%!

)

Output:

Code: Select all

edge0=1,  edge1=99

x       clamp   smoothstep
--------------------------
-4      0.000   0.000
5       0.040   0.004
14      0.132   0.047
23      0.224   0.127
32      0.316   0.236
41      0.408   0.363
50      0.500   0.500
59      0.591   0.634
68      0.683   0.762
77      0.775   0.870
86      0.867   0.951
95      0.959   0.994
104     1.000   1.000

Antonio

IcarusLives
Posts: 161
Joined: 17 Jan 2016 23:55

Re: Fail attempt at Perlin noise algorithm

#7 Post by IcarusLives » 03 Jan 2017 19:41

Aacini wrote:I like this type of applications, so I read the Wikipedia article and then tried to review your program, but this was very hard to me because the code organization and the frequent jumps required to review parameters and values defined elsewhere... So I wrote my own version instead:
Antonio


Oh wow that's neat! Now all that's left is using the values from smoothstep and place them into Perlin noise ^-^

penpen
Expert
Posts: 1991
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Fail attempt at Perlin noise algorithm

#8 Post by penpen » 08 Jan 2017 13:20

I'm unsure whether you wanted to implement Perlin noise on your own, or not.
If you don't know how to proceed, then just implement all other dependencies before implementing the function perlin:
All line by line.

If you "fear" the p (or permutation) array (which most disencourage), then note that it might be easier than most people fear; for example you could do something like this:

Code: Select all

@echo off
setlocal enableExtensions enableDelayedExpansion

set /A "i=0, j=256"
for %%a in (
                                                          151,160,137,91,90,15,
   131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
   190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
   88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
   77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
   102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
   135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
   5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
   223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
   129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
   251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
   49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
   138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
) do set /A "p[!i!]=%%a, p[!j!]=%%a, i+=1, j+=1"
set "i="
set "j="

:: ...

set p[
endlocal
goto :eof


penpen

IcarusLives
Posts: 161
Joined: 17 Jan 2016 23:55

Re: Fail attempt at Perlin noise algorithm

#9 Post by IcarusLives » 08 Jan 2017 17:50

penpen wrote:I'm unsure whether you wanted to implement Perlin noise on your own, or not.
If you don't know how to proceed, then just implement all other dependencies before implementing the function perlin:
All line by line.

If you "fear" the p (or permutation) array (which most disencourage), then note that it might be easier than most people fear; for example you could do something like this:

Code: Select all

@echo off
setlocal enableExtensions enableDelayedExpansion

set /A "i=0, j=256"
for %%a in (
                                                          151,160,137,91,90,15,
   131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
   190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
   88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
   77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
   102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
   135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
   5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
   223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
   129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
   251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
   49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
   138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
) do set /A "p[!i!]=%%a, p[!j!]=%%a, i+=1, j+=1"
set "i="
set "j="

:: ...

set p[
endlocal
goto :eof


penpen



My apologies for the absence, I've been up to my usual tinkering. Thank you for your advice, penpen ^-^

Post Reply