DosTips.com

A Forum all about DOS Batch
It is currently 24 Apr 2017 11:03

All times are UTC-06:00




Post new topic  Reply to topic  [ 9 posts ] 
Author Message
PostPosted: 01 Jan 2017 23:46 
Offline

Joined: 17 Jan 2016 23:55
Posts: 12
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.

Top
   
PostPosted: 02 Jan 2017 07:34 
Offline

Joined: 23 Jun 2013 06:15
Posts: 1280
Location: Germany
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


Top
   
PostPosted: 02 Jan 2017 14:59 
Offline

Joined: 17 Jan 2016 23:55
Posts: 12
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

>


Top
   
PostPosted: 03 Jan 2017 10:37 
Offline

Joined: 23 Jun 2013 06:15
Posts: 1280
Location: Germany
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


Top
   
PostPosted: 03 Jan 2017 10:57 
Offline

Joined: 17 Jan 2016 23:55
Posts: 12
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.


Top
   
PostPosted: 03 Jan 2017 19:24 
Offline
Expert

Joined: 06 Dec 2011 22:15
Posts: 1344
Location: México City, México
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


Top
   
PostPosted: 03 Jan 2017 19:41 
Offline

Joined: 17 Jan 2016 23:55
Posts: 12
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 ^-^


Top
   
PostPosted: 08 Jan 2017 13:20 
Offline

Joined: 23 Jun 2013 06:15
Posts: 1280
Location: Germany
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


Top
   
PostPosted: 08 Jan 2017 17:50 
Offline

Joined: 17 Jan 2016 23:55
Posts: 12
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 ^-^


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 9 posts ] 

All times are UTC-06:00


Who is online

Users browsing this forum: Bing [Bot], Yahoo [Bot] and 23 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Limited