Author Topic: 3D OpenWorld Mountains  (Read 12255 times)

0 Members and 1 Guest are viewing this topic.

This topic contains a post which is marked as Best Answer. Press here if you would like to see it.

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
3D OpenWorld Mountains
« on: March 08, 2019, 08:35:56 am »
Hi everyone!
This is my first attempt to code a OpenWorld Terrain/Mountain demo. A lot of effort is made by me to make it realistic.
Run the code below and enjoy!

Controls -
  • Use W,S,A,D for forward, backward, left and right movement respectively.
  • Use mouse movement for rotation.
  • Hit space bar key to switch between MODs. There are three MODs in the given program (sunny day, night and lines).
  • A small map is also displayed on the left bottom of the screen, where you can see your current location in the world.
Suggestions are welcome! Enjoy!

Code: QB64: [Select]
  1. '3D OpenWorld Terrain Demo
  2. 'Using Perlin Noise
  3. 'By Ashish Kushwaha
  4.  
  5.  
  6. _TITLE "3D OpenWorld Terrain"
  7. SCREEN _NEWIMAGE(800, 600, 32)
  8.  
  9.  
  10.  
  11. CONST sqrt2 = 2 ^ 0.5
  12. CONST mountHeightMax = 4
  13.  
  14. TYPE vec3
  15.     x AS SINGLE
  16.     y AS SINGLE
  17.     z AS SINGLE
  18.  
  19. TYPE camera
  20.     pos AS vec3
  21.     mpos AS vec3
  22.     target AS vec3
  23.  
  24. DECLARE LIBRARY 'camera control function
  25.     SUB gluLookAt (BYVAL eyeX#, BYVAL eyeY#, BYVAL eyeZ#, BYVAL centerX#, BYVAL centerY#, BYVAL centerZ#, BYVAL upX#, BYVAL upY#, BYVAL upZ#)
  26.  
  27.  
  28. 'noise function related variables
  29. DIM SHARED perlin_octaves AS SINGLE, perlin_amp_falloff AS SINGLE
  30.  
  31. DIM SHARED mapW, mapH
  32. mapW = 800: mapH = 800 'control the size of the map or world
  33.  
  34. 'Terrain Map related variables
  35. 'terrainData(mapW,mapH) contain elevation data and moistureMap(mapW,mapH) contain moisture data
  36. DIM SHARED terrainMap(mapW, mapH), moistureMap(mapW, mapH), terrainData(mapW, mapH) AS vec3
  37. 'these stored the 3 Dimensional coordinates of the objects. Used as a array buffer with glDrawArrays(). glDrawArrays() is faster than normal glBegin() ... glEnd() for rendering
  38. DIM SHARED mountVert(mapW * mapH * 6) AS SINGLE, mountColor(mapW * mapH * 6), mountNormal(mapW * mapH * 6)
  39.  
  40. 'MODs
  41. DIM SHARED worldMOD
  42.  
  43. 'map
  44. DIM SHARED worldMap&, myLocation& 'stored the 2D Map
  45. worldMap& = _NEWIMAGE(mapW + 300, mapH + 300, 32)
  46. myLocation& = _NEWIMAGE(10, 10, 32)
  47.  
  48. 'sky
  49. DIM SHARED skyTextures&(5), skyTextureHandle&(4)
  50. skyTextures&(0) = _NEWIMAGE(600, 600, 32)
  51. FOR i = 1 TO 5: skyTextures&(i) = _NEWIMAGE(200, 200, 32): NEXT
  52.  
  53. _DEST worldMap&
  54. CLS , _RGB(0, 0, 255)
  55. 'The reason of commenting down below code is given on line number -    279
  56. '_DEST skyTextures&(0)
  57. 'CLS , _RGB(109, 164, 255)
  58. 'FOR y = 0 TO _HEIGHT - 1
  59. '    FOR x = 0 TO _WIDTH - 1
  60. '        noiseDetail 5, 0.5
  61. '        k! = (ABS(noise(x * 0.04, y * 0.04, x / y * 0.01)) * 1.3) ^ 3
  62. '        PSET (x, y), _RGBA(255, 255, 255, k! * 255)
  63. 'NEXT x, y
  64. 'skyW = _WIDTH(skyTextures&(0))
  65. 'skyH = _HEIGHT(skyTextures&(0))
  66. '_PUTIMAGE (0, 0), 0, skyTextures&(1), (skyW / 3, 0)-STEP(skyW / 3, skyH / 3) 'back or rear
  67. '_PUTIMAGE (0, 0), 0, skyTextures&(2), (0, skyH / 3)-STEP(skyW / 3, skyH / 3) 'left
  68. '_PUTIMAGE (0, 0), 0, skyTextures&(3), (skyW / 3, skyH / 3)-STEP(skyW / 3, skyH / 3) 'up
  69. '_PUTIMAGE (0, 0), 0, skyTextures&(4), (2 * (skyW / 3), skyH / 3)-STEP(skyW / 3, skyH / 3) 'right
  70. '_PUTIMAGE (0, 0), 0, skyTextures&(5), (skyW / 3, 2 * (skyH / 3))-STEP(skyW / 3, skyH / 3) 'front
  71. '_DEST 0
  72.  
  73. 'camera
  74. DIM SHARED Cam AS camera, theta, phi
  75.  
  76.  
  77. DIM SHARED glAllow AS _BYTE
  78. _DEST myLocation& 'Generating the blip icon
  79. FOR i = 0 TO 10
  80.     FOR j = 0 TO 10
  81.         READ cx
  82.         IF cx = 1 THEN PSET (j, i), _RGB(255, 0, 200)
  83. NEXT j, i
  84. 'image data of blip icon
  85. DATA 0,0,0,0,0,1,0,0,0,0,0
  86. DATA 0,0,0,0,0,1,0,0,0,0,0
  87. DATA 0,0,0,0,1,1,1,0,0,0,0
  88. DATA 0,0,0,1,1,1,1,1,0,0,0
  89. DATA 0,0,0,1,1,1,1,1,0,0,0
  90. DATA 0,0,1,1,1,1,1,1,1,0,0
  91. DATA 0,1,1,1,1,1,1,1,1,1,0
  92. DATA 0,1,1,1,1,1,1,1,1,1,0
  93. DATA 1,1,1,1,0,0,0,1,1,1,1
  94. DATA 1,1,0,0,0,0,0,0,0,1,1
  95. DATA 1,0,0,0,0,0,0,0,0,0,1
  96. DATA 0,0,0,0,0,0,0,0,0,0,0
  97.  
  98.  
  99. 'Map elevations and mositure calculation done here with the help of perlin noise
  100. freq = 2
  101. FOR y = 0 TO mapH
  102.     FOR x = 0 TO mapW
  103.         nx = x * 0.01
  104.         ny = y * 0.01
  105.         noiseDetail 2, 0.4
  106.         v! = ABS(noise(nx * freq, ny * freq, 0)) * 1.5 + ABS(noise(nx * freq * 4, ny * freq * 4, 0)) * .25
  107.         v! = v! ^ (3.9)
  108.         elev = v! * 255
  109.         noiseDetail 2, 0.4
  110.         m! = ABS(noise(nx * 2, ny * 2, 0))
  111.         m! = m! ^ 1.4
  112.  
  113.         ' pset (x+mapW,y),_rgb(0,0,m!*255)
  114.         moistureMap(x, y) = m!
  115.  
  116.         ' PSET (x, y), _RGB(elev, elev, elev)
  117.         terrainMap(x, y) = (elev / 255) * mountHeightMax
  118.         terrainData(x, y).x = map(x, 0, mapW, -mapW * 0.02, mapW * 0.02)
  119.         terrainData(x, y).y = terrainMap(x, y)
  120.         terrainData(x, y).z = map(y, 0, mapH, -mapH * 0.02, mapH * 0.02)
  121.  
  122.         setMountColor x, y, 0, elev / 255, mountHeightMax
  123.         clr~& = _RGB(mountColor(0) * 255, mountColor(1) * 255, mountColor(2) * 255)
  124.         _DEST worldMap&
  125.         PSET (x + 150, y + 150), clr~&
  126.         _DEST 0
  127.         ' pset(x,y+mapH),clr~&
  128.     NEXT x
  129.  
  130.     CLS
  131.     PRINT "Generating World..."
  132.     'need to show a catchy progress bar
  133.     FOR j = 0 TO map(y, 0, mapH - 1, 0, _WIDTH - 1): LINE (j, _HEIGHT - 6)-(j, _HEIGHT - 1), hsb~&(map(j, 0, _WIDTH - 1, 0, 255), 255, 128, 255): NEXT j
  134.     _DISPLAY
  135. generateTerrainData
  136. PRINT "Hit Enter To Step In The World."
  137. PRINT "Map size : "; (mapH * mapW * 24) / 1024; " kB"
  138.  
  139. glAllow = -1
  140.     theta = (_MOUSEX / _WIDTH) * _PI(2.5) 'controls x-axis rotation
  141.     phi = map(_MOUSEY, 0, _HEIGHT, -_PI(0), _PI(0.5)) 'controls y-axis rotation
  142.  
  143.     IF Cam.mpos.z > mapH - 2 THEN Cam.mpos.z = mapH - 2 'prevent reaching out of the world map
  144.     IF Cam.mpos.x > mapW - 2 THEN Cam.mpos.x = mapW - 2 '
  145.     IF Cam.mpos.z < 2 THEN Cam.mpos.z = 2 '
  146.     IF Cam.mpos.x < 2 THEN Cam.mpos.x = 2 '
  147.  
  148.     IF _KEYDOWN(ASC("w")) OR _KEYDOWN(ASC("W")) THEN 'forward movement based on y-axis rotation
  149.         Cam.mpos.z = Cam.mpos.z + SIN(theta) * 0.3: Cam.mpos.x = Cam.mpos.x + COS(theta) * 0.3
  150.     END IF
  151.     IF _KEYDOWN(ASC("s")) OR _KEYDOWN(ASC("S")) THEN ' backward movement based on y-axis rotation
  152.         Cam.mpos.z = Cam.mpos.z - SIN(theta) * 0.3: Cam.mpos.x = Cam.mpos.x - COS(theta) * 0.3
  153.     END IF
  154.     IF _KEYDOWN(ASC("a")) OR _KEYDOWN(ASC("A")) THEN 'left movement based on y-axis rotation
  155.         Cam.mpos.z = Cam.mpos.z + SIN(theta - _PI(0.5)) * 0.3: Cam.mpos.x = Cam.mpos.x + COS(theta - _PI(0.5)) * 0.3
  156.     END IF
  157.     IF _KEYDOWN(ASC("d")) OR _KEYDOWN(ASC("D")) THEN 'right movement based on y-axis rotation
  158.         Cam.mpos.z = Cam.mpos.z + SIN(theta + _PI(0.5)) * 0.3: Cam.mpos.x = Cam.mpos.x + COS(theta + _PI(0.5)) * 0.3
  159.     END IF
  160.  
  161.     IF _KEYHIT = ASC(" ") THEN 'switching between MODs
  162.         IF worldMOD = 2 THEN worldMOD = 0 ELSE worldMOD = worldMOD + 1
  163.     END IF
  164.  
  165.     CLS , 1 'clear the screen and make it transparent so that GL context not get hidden.
  166.     _LIMIT 60
  167.  
  168.     'rotation of world causes rotation of map too. calculation of the source points of map is done below
  169.     sx1 = COS(_PI(.75) + theta) * 50 * sqrt2 + Cam.mpos.x + 150: sy1 = SIN(_PI(.75) + theta) * 50 * sqrt2 + Cam.mpos.z + 150
  170.     sx2 = COS(_PI(1.25) + theta) * 50 * sqrt2 + Cam.mpos.x + 150: sy2 = SIN(_PI(1.25) + theta) * 50 * sqrt2 + Cam.mpos.z + 150
  171.     sx3 = COS(_PI(1.75) + theta) * 50 * sqrt2 + Cam.mpos.x + 150: sy3 = SIN(_PI(1.75) + theta) * 50 * sqrt2 + Cam.mpos.z + 150
  172.     sx4 = COS(_PI(2.25) + theta) * 50 * sqrt2 + Cam.mpos.x + 150: sy4 = SIN(_PI(2.25) + theta) * 50 * sqrt2 + Cam.mpos.z + 150
  173.     'displaying the minimap
  174.     _MAPTRIANGLE (sx3, sy3)-(sx4, sy4)-(sx2, sy2), worldMap& TO(0, _HEIGHT - 100 * sqrt2)-(100 * sqrt2, _HEIGHT - 100 * sqrt2)-(0, _HEIGHT - 1)
  175.     _MAPTRIANGLE (sx2, sy2)-(sx4, sy4)-(sx1, sy1), worldMap& TO(0, _HEIGHT - 1)-(100 * sqrt2, _HEIGHT - 100 * sqrt2)-(100 * sqrt2, _HEIGHT - 1)
  176.     'showing your location
  177.     _PUTIMAGE (50 * sqrt2, _HEIGHT - 50 * sqrt2)-STEP(10, 10), myLocation&
  178.     'drawing red border along the map make it attractive
  179.     LINE (1, _HEIGHT - 100 * sqrt2)-STEP(100 * sqrt2, 100 * sqrt2), _RGB(255, 0, 0), B
  180.     _DISPLAY
  181.  
  182.  
  183. SUB _GL () STATIC
  184.  
  185.     IF glAllow = 0 THEN EXIT SUB 'we are not ready yet
  186.  
  187.     IF NOT glSetup THEN
  188.         glSetup = -1
  189.         _glViewport 0, 0, _WIDTH, _HEIGHT 'define our rendering area
  190.  
  191.         aspect# = _WIDTH / _HEIGHT 'used to create perspective view
  192.  
  193.         rad = 1 'distance of camera from origin (0,0,0)
  194.         farPoint = 1.0 'far point of camera target
  195.  
  196.         'initialize camera
  197.         Cam.mpos.x = mapW / 2
  198.         Cam.mpos.z = mapH / 2
  199.         Cam.mpos.y = 6
  200.         'initialize textures for sky
  201.         FOR i = 1 TO UBOUND(skyTextures&)
  202.             _glGenTextures 1, _OFFSET(skyTextureHandle&(i - 1))
  203.  
  204.             DIM m AS _MEM
  205.             m = _MEMIMAGE(skyTextures&(i))
  206.  
  207.             _glBindTexture _GL_TEXTURE_2D, skyTextureHandle&(i - 1)
  208.             _glTexImage2D _GL_TEXTURE_2D, 0, _GL_RGB, _WIDTH(skyTextures&(i)), _HEIGHT(skyTextures&(i)), 0, _GL_BGRA_EXT, _GL_UNSIGNED_BYTE, m.OFFSET
  209.  
  210.             _MEMFREE m
  211.  
  212.             _glTexParameteri _GL_TEXTURE_2D, _GL_TEXTURE_MAG_FILTER, _GL_LINEAR
  213.             _glTexParameteri _GL_TEXTURE_2D, _GL_TEXTURE_MIN_FILTER, _GL_NEAREST
  214.             _FREEIMAGE skyTextures&(i)
  215.         NEXT
  216.     END IF
  217.  
  218.     IF worldMOD = 0 THEN _glClearColor 0.7, 0.8, 1.0, 1.0 'this makes the background look sky blue.
  219.     IF worldMOD = 1 THEN _glClearColor 0.031, 0.0, 0.307, 1.0 'night sky
  220.     IF worldMOD = 2 THEN _glClearColor 0.0, 0.0, 0.0, 1.0
  221.     _glClear _GL_COLOR_BUFFER_BIT
  222.  
  223.     _glEnable _GL_DEPTH_TEST 'Of course, we are going to do 3D
  224.     _glClearDepth 10.0
  225.  
  226.     '_glEnable _GL_TEXTURE_2D 'so that we can use texture for our sky. :)
  227.  
  228.     IF worldMOD <> 2 THEN
  229.         _glEnable _GL_LIGHTING 'Without light, everything dull.
  230.         _glEnable _GL_LIGHT0
  231.     END IF
  232.  
  233.     IF worldMOD = 1 THEN
  234.         'night MOD
  235.         _glLightfv _GL_LIGHT0, _GL_AMBIENT, glVec4(0.05, 0.05, 0.33, 0)
  236.         _glLightfv _GL_LIGHT0, _GL_DIFFUSE, glVec4(0.55, 0.55, 0.78, 0)
  237.         _glLightfv _GL_LIGHT0, _GL_SPECULAR, glVec4(0.75, 0.75, 0.98, 0)
  238.     ELSEIF worldMOD = 0 THEN
  239.         _glLightfv _GL_LIGHT0, _GL_AMBIENT, glVec4(0.35, 0.35, 0.33, 0) 'gives a bit yellowing color to the light
  240.         _glLightfv _GL_LIGHT0, _GL_DIFFUSE, glVec4(0.75, 0.75, 0.60, 0) 'so it will feel like sun is in the sky
  241.         _glLightfv _GL_LIGHT0, _GL_SPECULAR, glVec4(0.95, 0.95, 0.80, 0)
  242.     END IF
  243.     _glShadeModel _GL_SMOOTH 'to make the rendering smooth
  244.  
  245.     _glMatrixMode _GL_PROJECTION
  246.     _gluPerspective 70, aspect#, 0.01, 10.0 'set up out perpective
  247.  
  248.     _glMatrixMode _GL_MODELVIEW
  249.  
  250.     IF Cam.mpos.y > (terrainMap(Cam.mpos.x, Cam.mpos.z)) THEN Cam.mpos.y = Cam.mpos.y - 0.03 ELSE Cam.mpos.y = (terrainMap(Cam.mpos.x, Cam.mpos.z)) 'if you are in air then you must fall.
  251.  
  252.     'calculation of camera eye, its target, etc...
  253.     Cam.target.y = Cam.pos.y * COS(phi)
  254.     Cam.target.x = Cam.pos.x + COS(theta) * farPoint
  255.     Cam.target.z = Cam.pos.z + SIN(theta) * farPoint
  256.  
  257.     Cam.pos.x = map(Cam.mpos.x, 0, mapW, -mapW * 0.02, mapW * 0.02)
  258.     Cam.pos.z = map(Cam.mpos.z, 0, mapH, -mapH * 0.02, mapH * 0.02)
  259.     Cam.pos.y = Cam.mpos.y + 0.3
  260.  
  261.     gluLookAt Cam.pos.x, Cam.pos.y, Cam.pos.z, Cam.target.x, Cam.target.y, Cam.target.z, 0, 1, 0
  262.  
  263.  
  264.     'use of this skybox was avoided by me because I believe that it makes the scene a bit unrealistic.
  265.     ' skybox 5.0
  266.  
  267.     ' draw the world
  268.     _glEnable _GL_COLOR_MATERIAL
  269.     _glColorMaterial _GL_FRONT, _GL_AMBIENT_AND_DIFFUSE
  270.  
  271.     _glEnableClientState _GL_VERTEX_ARRAY
  272.     _glVertexPointer 3, _GL_FLOAT, 0, _OFFSET(mountVert())
  273.     _glEnableClientState _GL_COLOR_ARRAY
  274.     _glColorPointer 3, _GL_FLOAT, 0, _OFFSET(mountColor())
  275.     _glEnableClientState _GL_NORMAL_ARRAY
  276.     _glNormalPointer _GL_FLOAT, 0, _OFFSET(mountNormal())
  277.  
  278.     IF worldMOD = 2 THEN _glDrawArrays _GL_LINE_STRIP, 0, UBOUND(mountvert) / 3 ELSE _glDrawArrays _GL_TRIANGLE_STRIP, 0, UBOUND(mountVert) / 3
  279.  
  280.     _glDisableClientState _GL_VERTEX_ARRAY
  281.  
  282.  
  283.     _glFlush
  284.  
  285. 'draws a beautiful sky
  286. SUB skybox (s)
  287.     _glDisable _GL_LIGHTING
  288.     _glDisable _GL_LIGHT0
  289.     _glDisable _GL_DEPTH_TEST
  290.     _glDepthMask _GL_FALSE
  291.    
  292.     _glBindTexture _GL_TEXTURE_2D, skyTextureHandle&(4)
  293.    
  294.     _glBegin _GL_QUADS
  295.     _glTexCoord2f 0, 1
  296.     _glVertex3f -s, s, -s 'front
  297.     _glTexCoord2f 0, 0
  298.     _glVertex3f -s, -s, -s
  299.     _glTexCoord2f 1, 0
  300.     _glVertex3f s, -s, -s
  301.     _glTexCoord2f 1, 1
  302.     _glVertex3f s, s, -s
  303.     _glEnd
  304.    
  305.     _glBindTexture _GL_TEXTURE_2D, skyTextureHandle&(0)
  306.     _glBegin _GL_QUADS
  307.     _glTexCoord2f 0, 1
  308.     _glVertex3f -s, s, s 'rear
  309.     _glTexCoord2f 0, 0
  310.     _glVertex3f -s, -s, s
  311.     _glTexCoord2f 1, 0
  312.     _glVertex3f s, -s, s
  313.     _glTexCoord2f 1, 1
  314.     _glVertex3f s, s, s
  315.     _glEnd
  316.    
  317.     _glBindTexture _GL_TEXTURE_2D, skyTextureHandle&(1)
  318.     _glBegin _GL_QUADS
  319.     _glTexCoord2f 1, 0
  320.     _glVertex3f -s, s, s 'left
  321.     _glTexCoord2f 0, 0
  322.     _glVertex3f -s, -s, s
  323.     _glTexCoord2f 0, 1
  324.     _glVertex3f -s, -s, -s
  325.     _glTexCoord2f 1, 1
  326.     _glVertex3f -s, s, -s
  327.     _glEnd
  328.    
  329.     _glBindTexture _GL_TEXTURE_2D, skyTextureHandle&(3)
  330.     _glBegin _GL_QUADS
  331.     _glTexCoord2f 1, 0
  332.     _glVertex3f s, s, s 'right
  333.     _glTexCoord2f 0, 0
  334.     _glVertex3f s, -s, s
  335.     _glTexCoord2f 0, 1
  336.     _glVertex3f s, -s, -s
  337.     _glTexCoord2f 1, 1
  338.     _glVertex3f s, s, -s
  339.     _glEnd
  340.  
  341.     _glBindTexture _GL_TEXTURE_2D, skyTextureHandle&(2)
  342.     _glBegin _GL_QUADS
  343.     _glTexCoord2f 0, 1
  344.     _glVertex3f -s, s, -s 'up
  345.     _glTexCoord2f 0, 0
  346.     _glVertex3f -s, s, s
  347.     _glTexCoord2f 1, 0
  348.     _glVertex3f s, s, s
  349.     _glTexCoord2f 1, 1
  350.     _glVertex3f s, s, -s
  351.     _glEnd
  352.    
  353.     _glDepthMask _GL_TRUE
  354.     _glEnable _GL_DEPTH_TEST
  355.     _glEnable _GL_LIGHTING
  356.     _glEnable _GL_LIGHT0
  357.  
  358. SUB setMountColor (xi, yi, i, h, h_max) 'assign color on the basis of height map and moisture map.
  359.     IF h > 0.8 * h_max THEN
  360.         IF moistureMap(xi, yi) < 0.1 THEN mountColor(i) = 0.333: mountColor(i + 1) = 0.333: mountColor(i + 2) = 0.333: EXIT SUB 'scorched
  361.         IF moistureMap(xi, yi) < 0.2 THEN mountColor(i) = 0.533: mountColor(i + 1) = 0.533: mountColor(i + 2) = 0.533: EXIT SUB 'bare
  362.         IF moistureMap(xi, yi) < 0.5 THEN mountColor(i) = 0.737: mountColor(i + 1) = 0.737: mountColor(i + 2) = 0.6705: EXIT SUB 'tundra
  363.         mountColor(i) = 0.8705: mountColor(i + 1) = 0.8705: mountColor(i + 2) = 0.898: EXIT SUB 'snow
  364.     END IF
  365.     IF h > 0.6 * h_max THEN
  366.         IF moistureMap(xi, yi) < 0.33 THEN mountColor(i) = 0.788: mountColor(i + 1) = 0.823: mountColor(i + 2) = 0.607: EXIT SUB 'temperate desert
  367.         IF moistureMap(xi, yi) < 0.66 THEN mountColor(i) = 0.533: mountColor(i + 1) = 0.600: mountColor(i + 2) = 0.466: EXIT SUB 'shrubland
  368.         mountColor(i) = 0.6: mountColor(i + 1) = 0.6705: mountColor(i + 2) = 0.466: EXIT SUB 'taiga
  369.     END IF
  370.     IF h > 0.3 * h_max THEN
  371.         IF moistureMap(xi, yi) < 0.16 THEN mountColor(i) = 0.788: mountColor(i + 1) = 0.823: mountColor(i + 2) = 0.607: EXIT SUB 'temperate desert
  372.         IF moistureMap(xi, yi) < 0.50 THEN mountColor(i) = 0.533: mountColor(i + 1) = 0.6705: mountColor(i + 2) = 0.333: EXIT SUB 'grassland
  373.         IF moistureMap(xi, yi) < 0.83 THEN mountColor(i) = 0.403: mountColor(i + 1) = 0.576: mountColor(i + 2) = 0.349: EXIT SUB 'temperate deciduous forest
  374.         mountColor(i) = 0.262: mountColor(i + 1) = 0.533: mountColor(i + 2) = 0.233: EXIT SUB 'temperate rain forest
  375.     END IF
  376.     IF h < 0.1 * h THEN mountColor(i) = 0.262: mountColor(i + 1) = 0.262: mountColor(i + 2) = 0.478: EXIT SUB 'ocean
  377.     IF h < 0.14 * h THEN mountColor(i) = 0.627: mountColor(i + 1) = 0.568: mountColor(i + 2) = 0.466: EXIT SUB 'beach
  378.     IF h <= 0.3 * h_max THEN
  379.         IF moistureMap(xi, yi) < 0.16 THEN mountColor(i) = 0.823: mountColor(i + 1) = 0.725: mountColor(i + 2) = 0.545: EXIT SUB 'subtropical desert
  380.         IF moistureMap(xi, yi) < 0.33 THEN mountColor(i) = 0.533: mountColor(i + 1) = 0.6705: mountColor(i + 2) = 0.333: EXIT SUB 'grassland
  381.         IF moistureMap(xi, yi) < 0.66 THEN mountColor(i) = 0.337: mountColor(i + 1) = 0.600: mountColor(i + 2) = 0.266: EXIT SUB 'tropical seasonal forest
  382.         mountColor(i) = 0.2: mountColor(i + 1) = 0.466: mountColor(i + 2) = 0.333: EXIT SUB 'tropical rain forest
  383.     END IF
  384.  
  385. SUB generateTerrainData ()
  386.     DIM A AS vec3, B AS vec3, C AS vec3, R AS vec3
  387.     index = 0
  388.  
  389.     '##################################################################################################
  390.     '# Note : The below method consumes more memory. It uses 3x more vertex array than the next one.  #
  391.     '# So, use of this method was avoided by me.                                                      #
  392.     '##################################################################################################
  393.  
  394.     ' _dest _console
  395.     ' FOR z = 0 TO mapH - 1
  396.     ' FOR x = 0 TO mapW - 1
  397.     ' A = terrainData(x, z)
  398.     ' B = terrainData(x, z + 1)
  399.     ' C = terrainData(x + 1, z)
  400.     ' D = terrainData(x+1,z+1)
  401.  
  402.     ' ' ?index
  403.     ' ' OBJ_CalculateNormal A, B, C, R
  404.  
  405.     ' ' mountNormal(index) = R.x : mountNormal(index+1) = R.y : mountNormal(index+2) = R.z
  406.     ' ' mountNormal(index+3) = R.x : mountNormal(index+4) = R.y : mountNormal(index+5) = R.z
  407.     ' ' mountNormal(index+6) = R.x : mountNormal(index+7) = R.y : mountNormal(index+8) = R.z
  408.  
  409.     ' mountVert(index) = A.x : mountVert(index+1) = A.y : mountVert(index+2) = A.z : setMountColor x,z,index, A.y, mountHeightMax
  410.     ' mountVert(index+3) = B.x : mountVert(index+4) = B.y : mountVert(index+5) = B.z :  setMountColor x,z+1,index+3, B.y, mountHeightMax
  411.     ' mountVert(index+6) = C.x : mountVert(index+7) = C.y : mountVert(index+8) = C.z: setMountColor x+1,z,index+6, C.y, mountHeightMax
  412.  
  413.     ' ' OBJ_CalculateNormal C,B,D, R
  414.  
  415.     ' ' mountNormal(index+9) = R.x : mountNormal(index+10) = R.y : mountNormal(index+11) = R.z
  416.     ' ' mountNormal(index+12) = R.x : mountNormal(index+13) = R.y : mountNormal(index+14) = R.z
  417.     ' ' mountNormal(index+15) = R.x : mountNormal(index+16) = R.y : mountNormal(index+17) = R.z
  418.  
  419.     ' mountVert(index+9) = C.x : mountVert(index+10) = C.y : mountVert(index+11) = C.z: setMountColor x+1,z, index+9, C.y, mountHeightMax
  420.     ' mountVert(index+12) = B.x : mountVert(index+13) = B.y : mountVert(index+14) = B.z: setMountColor x,z+1,index+12, B.y, mountHeightMax
  421.     ' mountVert(index+15) = D.x : mountVert(index+16) = D.y : mountVert(index+17) = D.z: setMountColor x+1,z+1,index+15, D.y, mountHeightMax
  422.     ' index = index+18
  423.     ' NEXT x,z
  424.  
  425.     'this method is efficient than the above one.
  426.     DO
  427.         IF z MOD 2 = 0 THEN x = x + 1 ELSE x = x - 1
  428.  
  429.         A = terrainData(x, z) 'get out coordinates from our stored data
  430.         B = terrainData(x, z + 1)
  431.         C = terrainData(x + 1, z)
  432.  
  433.         OBJ_CalculateNormal A, B, C, R 'calculates the normal of a triangle
  434.  
  435.         'store color, coordinate & normal data in an array
  436.         mountNormal(index) = R.x: mountNormal(index + 1) = R.y: mountNormal(index + 2) = R.z
  437.         mountVert(index) = A.x: mountVert(index + 1) = A.y: mountVert(index + 2) = A.z: setMountColor x, z, index, A.y, mountHeightMax
  438.  
  439.         mountNormal(index + 3) = R.x: mountNormal(index + 4) = R.y: mountNormal(index + 5) = R.z
  440.         mountVert(index + 3) = B.x: mountVert(index + 4) = B.y: mountVert(index + 5) = B.z: setMountColor x, z + 1, index + 3, B.y, mountHeightMax
  441.  
  442.         index = index + 6
  443.  
  444.         IF x = mapW - 1 THEN
  445.             IF z MOD 2 = 0 THEN x = x + 1: z = z + 1
  446.         END IF
  447.         IF x = 1 THEN
  448.             IF z MOD 2 = 1 THEN x = x - 1: z = z + 1
  449.         END IF
  450.         IF z = mapH - 1 THEN EXIT DO
  451.     LOOP
  452.     _DEST 0
  453.  
  454.  
  455. FUNCTION p5random! (mn!, mx!)
  456.     IF mn! > mx! THEN
  457.         SWAP mn!, mx!
  458.     END IF
  459.     p5random! = RND * (mx! - mn!) + mn!
  460.  
  461.  
  462. FUNCTION map! (value!, minRange!, maxRange!, newMinRange!, newMaxRange!)
  463.     map! = ((value! - minRange!) / (maxRange! - minRange!)) * (newMaxRange! - newMinRange!) + newMinRange!
  464.  
  465. 'coded in QB64 by Fellipe Heitor
  466. 'Can be found in p5js.bas library
  467. 'http://bit.ly/p5jsbas
  468. FUNCTION noise! (x AS SINGLE, y AS SINGLE, z AS SINGLE)
  469.     STATIC p5NoiseSetup AS _BYTE
  470.     STATIC perlin() AS SINGLE
  471.     STATIC PERLIN_YWRAPB AS SINGLE, PERLIN_YWRAP AS SINGLE
  472.     STATIC PERLIN_ZWRAPB AS SINGLE, PERLIN_ZWRAP AS SINGLE
  473.     STATIC PERLIN_SIZE AS SINGLE
  474.  
  475.     IF p5NoiseSetup = 0 THEN
  476.         p5NoiseSetup = 1
  477.  
  478.         PERLIN_YWRAPB = 4
  479.         PERLIN_YWRAP = INT(1 * (2 ^ PERLIN_YWRAPB))
  480.         PERLIN_ZWRAPB = 8
  481.         PERLIN_ZWRAP = INT(1 * (2 ^ PERLIN_ZWRAPB))
  482.         PERLIN_SIZE = 4095
  483.  
  484.         perlin_octaves = 4
  485.         perlin_amp_falloff = 0.5
  486.  
  487.         REDIM perlin(PERLIN_SIZE + 1) AS SINGLE
  488.         DIM i AS SINGLE
  489.         FOR i = 0 TO PERLIN_SIZE + 1
  490.             perlin(i) = RND
  491.         NEXT
  492.     END IF
  493.  
  494.     x = ABS(x)
  495.     y = ABS(y)
  496.     z = ABS(z)
  497.  
  498.     DIM xi AS SINGLE, yi AS SINGLE, zi AS SINGLE
  499.     xi = INT(x)
  500.     yi = INT(y)
  501.     zi = INT(z)
  502.  
  503.     DIM xf AS SINGLE, yf AS SINGLE, zf AS SINGLE
  504.     xf = x - xi
  505.     yf = y - yi
  506.     zf = z - zi
  507.  
  508.     DIM r AS SINGLE, ampl AS SINGLE, o AS SINGLE
  509.     r = 0
  510.     ampl = .5
  511.  
  512.     FOR o = 1 TO perlin_octaves
  513.         DIM of AS SINGLE, rxf AS SINGLE
  514.         DIM ryf AS SINGLE, n1 AS SINGLE, n2 AS SINGLE, n3 AS SINGLE
  515.         of = xi + INT(yi * (2 ^ PERLIN_YWRAPB)) + INT(zi * (2 ^ PERLIN_ZWRAPB))
  516.  
  517.         rxf = 0.5 * (1.0 - COS(xf * _PI))
  518.         ryf = 0.5 * (1.0 - COS(yf * _PI))
  519.  
  520.         n1 = perlin(of AND PERLIN_SIZE)
  521.         n1 = n1 + rxf * (perlin((of + 1) AND PERLIN_SIZE) - n1)
  522.         n2 = perlin((of + PERLIN_YWRAP) AND PERLIN_SIZE)
  523.         n2 = n2 + rxf * (perlin((of + PERLIN_YWRAP + 1) AND PERLIN_SIZE) - n2)
  524.         n1 = n1 + ryf * (n2 - n1)
  525.  
  526.         of = of + PERLIN_ZWRAP
  527.         n2 = perlin(of AND PERLIN_SIZE)
  528.         n2 = n2 + rxf * (perlin((of + 1) AND PERLIN_SIZE) - n2)
  529.         n3 = perlin((of + PERLIN_YWRAP) AND PERLIN_SIZE)
  530.         n3 = n3 + rxf * (perlin((of + PERLIN_YWRAP + 1) AND PERLIN_SIZE) - n3)
  531.         n2 = n2 + ryf * (n3 - n2)
  532.  
  533.         n1 = n1 + (0.5 * (1.0 - COS(zf * _PI))) * (n2 - n1)
  534.  
  535.         r = r + n1 * ampl
  536.         ampl = ampl * perlin_amp_falloff
  537.         xi = INT(xi * (2 ^ 1))
  538.         xf = xf * 2
  539.         yi = INT(yi * (2 ^ 1))
  540.         yf = yf * 2
  541.         zi = INT(zi * (2 ^ 1))
  542.         zf = zf * 2
  543.  
  544.         IF xf >= 1.0 THEN xi = xi + 1: xf = xf - 1
  545.         IF yf >= 1.0 THEN yi = yi + 1: yf = yf - 1
  546.         IF zf >= 1.0 THEN zi = zi + 1: zf = zf - 1
  547.     NEXT
  548.     noise! = r
  549.  
  550. SUB noiseDetail (lod!, falloff!)
  551.     IF lod! > 0 THEN perlin_octaves = lod!
  552.     IF falloff! > 0 THEN perlin_amp_falloff = falloff!
  553.  
  554. 'method adapted form http://stackoverflow.com/questions/4106363/converting-rgb-to-hsb-colors
  555. FUNCTION hsb~& (__H AS _FLOAT, __S AS _FLOAT, __B AS _FLOAT, A AS _FLOAT)
  556.     DIM H AS _FLOAT, S AS _FLOAT, B AS _FLOAT
  557.  
  558.     H = map(__H, 0, 255, 0, 360)
  559.     S = map(__S, 0, 255, 0, 1)
  560.     B = map(__B, 0, 255, 0, 1)
  561.  
  562.     IF S = 0 THEN
  563.         hsb~& = _RGBA32(B * 255, B * 255, B * 255, A)
  564.         EXIT FUNCTION
  565.     END IF
  566.  
  567.     DIM fmx AS _FLOAT, fmn AS _FLOAT
  568.     DIM fmd AS _FLOAT, iSextant AS INTEGER
  569.     DIM imx AS INTEGER, imd AS INTEGER, imn AS INTEGER
  570.  
  571.     IF B > .5 THEN
  572.         fmx = B - (B * S) + S
  573.         fmn = B + (B * S) - S
  574.     ELSE
  575.         fmx = B + (B * S)
  576.         fmn = B - (B * S)
  577.     END IF
  578.  
  579.     iSextant = INT(H / 60)
  580.  
  581.     IF H >= 300 THEN
  582.         H = H - 360
  583.     END IF
  584.  
  585.     H = H / 60
  586.     H = H - (2 * INT(((iSextant + 1) MOD 6) / 2))
  587.  
  588.     IF iSextant MOD 2 = 0 THEN
  589.         fmd = (H * (fmx - fmn)) + fmn
  590.     ELSE
  591.         fmd = fmn - (H * (fmx - fmn))
  592.     END IF
  593.  
  594.     imx = _ROUND(fmx * 255)
  595.     imd = _ROUND(fmd * 255)
  596.     imn = _ROUND(fmn * 255)
  597.  
  598.     SELECT CASE INT(iSextant)
  599.         CASE 1
  600.             hsb~& = _RGBA32(imd, imx, imn, A)
  601.         CASE 2
  602.             hsb~& = _RGBA32(imn, imx, imd, A)
  603.         CASE 3
  604.             hsb~& = _RGBA32(imn, imd, imx, A)
  605.         CASE 4
  606.             hsb~& = _RGBA32(imd, imn, imx, A)
  607.         CASE 5
  608.             hsb~& = _RGBA32(imx, imn, imd, A)
  609.         CASE ELSE
  610.             hsb~& = _RGBA32(imx, imd, imn, A)
  611.     END SELECT
  612.  
  613.  
  614.  
  615. SUB OBJ_CalculateNormal (p1 AS vec3, p2 AS vec3, p3 AS vec3, N AS vec3)
  616.     DIM U AS vec3, V AS vec3
  617.  
  618.     U.x = p2.x - p1.x
  619.     U.y = p2.y - p1.y
  620.     U.z = p2.z - p1.z
  621.  
  622.     V.x = p3.x - p1.x
  623.     V.y = p3.y - p1.y
  624.     V.z = p3.z - p1.z
  625.  
  626.     N.x = (U.y * V.z) - (U.z * V.y)
  627.     N.y = (U.z * V.x) - (U.x * V.z)
  628.     N.z = (U.x * V.y) - (U.y * V.x)
  629.     OBJ_Normalize N
  630.  
  631. SUB OBJ_Normalize (V AS vec3)
  632.     mag! = SQR(V.x * V.x + V.y * V.y + V.z * V.z)
  633.     V.x = V.x / mag!
  634.     V.y = V.y / mag!
  635.     V.z = V.z / mag!
  636.  
  637. FUNCTION glVec4%& (x, y, z, w)
  638.     STATIC internal_vec4(3)
  639.     internal_vec4(0) = x
  640.     internal_vec4(1) = y
  641.     internal_vec4(2) = z
  642.     internal_vec4(3) = w
  643.     glVec4%& = _OFFSET(internal_vec4())
  644.  


Screenshot_1.png

MOD : Sunny Day

 
Screenshot_2.png

MOD : Night time.
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #1 on: March 08, 2019, 08:38:49 am »
Wow! Fabulous!

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #2 on: March 08, 2019, 08:43:35 am »
@bplus
I'm glad you enjoyed it. :D
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

FellippeHeitor

  • Guest
Re: 3D OpenWorld Mountains
« Reply #3 on: March 08, 2019, 08:59:56 am »
This is *very* impressive, Ashish. Great job!

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #4 on: March 08, 2019, 09:04:46 am »
What! No trees or bunny rabbits? Nah, kidding. Very nicely done indeed...
But, seriously, I wandered all over that landscape and didn't spot one zombie or alien...
Logic is the beginning of wisdom.

Offline qb4ever

  • Newbie
  • Posts: 40
  • LOCATE 15,15: COLOR 14: PRINT "Hello World!"
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #5 on: March 08, 2019, 09:08:45 am »
WOW Ashish !
Stunning job !

Offline _vince

  • Seasoned Forum Regular
  • Posts: 422
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #6 on: March 08, 2019, 09:24:04 am »
nice job, reminds me of http://www.petesqbsite.com/reviews/engines/xeno.html also a similar concept to static's sanctus

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #7 on: March 08, 2019, 09:28:21 am »
@Fellippe, @qb4ever
Thank You!
@johnno56
I agree. I think this program can be modify into a 3D game or something? like PUBG?
@vince
Thanks! Yeah. I was inspired by many of them. I liked STxAxTIC's engine and also a similar demo posted by Petr using _MAPTRIANGLE.
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #8 on: March 08, 2019, 09:54:15 am »
God, that's something! That's fantastic!

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #9 on: March 08, 2019, 10:01:07 am »
Thank You, Petr! :)
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #10 on: March 08, 2019, 07:25:08 pm »
Hi Ashish

cool this world!
But where is the EasterEgg? Moving across it I haven't met hidden surprise!

Thanks to share it.
Programming isn't difficult, only it's  consuming time and coffee

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #11 on: March 09, 2019, 01:01:59 pm »
Looks fantastic Ashish, you continue to astound us all! This code is a great guide for people (thinking mostly of myself here) to understand how QB64 interfaces with GL tech in a less-than-trivial way.

It looks like GL has done the 'painter's algorithm' (or something similar) to avoid drawing the background first - or did you explicitly do some z-sorting without being obvious about it? I also assume the nasty math of calculating 3D projections is handled by GL somewhere deep behind the blue screen.

All that said, this demo is worth becoming an entry in the Samples section. Are you supposing this is the final version for now, or should we wait a little while?

When I was your age I was proud to make a Mystify screensaver clone. Are you sure your last name isn't Skywalker?
« Last Edit: March 09, 2019, 01:08:29 pm by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #12 on: March 10, 2019, 11:52:29 am »
Hi Ashish

cool this world!
But where is the EasterEgg? Moving across it I haven't met hidden surprise!

Thanks to share it.
Thank You. Okay I think many of you expect a surprise in this demo. I will add a surprsie in it soon. (You know my final exams are going on).

Looks fantastic Ashish, you continue to astound us all! This code is a great guide for people (thinking mostly of myself here) to understand how QB64 interfaces with GL tech in a less-than-trivial way.

It looks like GL has done the 'painter's algorithm' (or something similar) to avoid drawing the background first - or did you explicitly do some z-sorting without being obvious about it? I also assume the nasty math of calculating 3D projections is handled by GL somewhere deep behind the blue screen.

All that said, this demo is worth becoming an entry in the Samples section. Are you supposing this is the final version for now, or should we wait a little while?

When I was your age I was proud to make a Mystify screensaver clone. Are you sure your last name isn't Skywalker?
Thank you, STxAxTIC. I don't have to do any calculation except for position of camera, its target & for elevation data. OpenGL do calculation of projection with function gluPerspective(fov,aspect,zNear,zFar). Depth calculation done automatically by GPU when it is enable using glEnable(GL_DEPTH_TEST).

I will be proud if it get into samples gallery but this is not final version. It will receive one or two more updates by me. I apologize, but you all have to wait a little. :)

My last name is "Kushwaha". But what I have to do with last name Skywalker? What does it mean?
« Last Edit: March 10, 2019, 11:53:43 am by Ashish »
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #13 on: March 10, 2019, 02:10:45 pm »
... But what I have to do with last name Skywalker? What does it mean?

It means you're my new best friend! Man, I hate Star Wars. Nice to meet someone who apparently never heard of it, never saw it, or saw it and was so bored, never took in who the main character was. :D :D :D

Anyway... Hey new best friend, you owe me a new set of dentures! That's right, they broke with all that bumpiness I experienced while traveling. Can there be a way to travel without all that bumpiness? A gain / decrease altitude key maybe? Well, other than that, I curious how much GL you had to learn to put this together? I figure you're just a few IQ points behind me, when I was your age and washing machines were being invented... (wow, I bet he's worried about his future now...) So you have me wondering if I could pick up on this stuff someday? I can envision a golf simulator, so when I'm too old to carry the clubs, thinking next Tuesday, I can just carry a mouse and navigate through Torrey Pines. Anyway, kidding aside, great job! If I saw homemade stuff like this 40 years ago, I'd probably  be a retire graphics designer. I'd put fire breathing dragons in this simulation, and give the point of view character a cross bow. Evade the dragons and shoot them or get hit by fire balls and loose a life. Maybe put a castle somewhere in the map, and if you reach it, you win.

Oh well, enough rambling, it's time for my mid-morning nap. Oh, don't worry too much about the teeth and the mind stuff. Your hair will fall out long before any of that stuff happens.

Pete

- My the Force be without you!
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: 3D OpenWorld Mountains
« Reply #14 on: March 10, 2019, 02:13:37 pm »
@Pete
why do you hate SpaceBalls?
Programming isn't difficult, only it's  consuming time and coffee