BBC BASIC for Windows
Programming >> Graphics and Games >> Fractal landscape with D3D
http://bb4w.conforums.com/index.cgi?board=graphics&action=display&num=1439311250

Fractal landscape with D3D
Post by DDRM on Aug 11th, 2015, 4:40pm

As promised, here is a proof-of-principle demonstration of a fractal landscape rendered using D3DLIBA.

When you run it, a fractal landscape will be generated, and rendered very crudely to see if it is interesting. If you don't like it, press "n", and a new one will appear. When You've got one you like, press "y", and it will be converted to a D3D view which you can fly around.

Controls:
Arrow keys: bank left and right (causes you to turn in horizontal plane), "Dive" or "Climb"
A and Z: accelerate forwards or backwards
R: Reset position, heading and speed to the initial one (stationary above the (0,0) corner)
Q: quit

You can change the setting of s% in line 6 to alter the size of the map. 128 will generate fairly fast, and is big enough to get an idea of flying round it. 256 is my favourite. By 512 it all gets a bit ponderous, both creating and running.

Lots of other bits you can play with if you want to: change the position and/or colour of the lights for different times of day, change the colours (and fractions of the landscape) for the different regions.

I've tried to include reasonably clear annotation of what's going on.

Hope that's interesting to someone!

D


Code:
      HIMEM=PAGE +1E8
      INSTALL @lib$+"D3DLIBA"
      MODE 21
      xres%=800
      yres%=600
      s%=128 :REM must be a power of 2. Size of the map in squares (each way)
      vscale=yres%/s%
      hscale=xres%/s%
      DIM l%(s%,s%) :REM This will hold the height data

      REPEAT
        REM Set up a map and see if we like it!
        minh%=1000
        maxh%=0
        PROCfillland(0,0,s%)  :REM Recursive fractal generation of the landscape
        PROCMeasureLand       :REM Look for the highest and lowest points
        wlevel%=minh%+(maxh%-minh%)/2   :REM everything below this level will be sea
        l%()-=wlevel%
        maxh%-=wlevel%
        snowlevel%=maxh%*3/4            :REM Snowy mountains above this level
        REM Fill in the sea
        FOR y%=0 TO s%-1
          FOR x%=0 TO s%-1
            IF l%(x%,y%)<0 THEN l%(x%,y%)=0
          NEXT x%
        NEXT y%
  
        PROCPlot    :REM Quick and dirty view of the generated world, before we make the big vertex buffer
        PRINT "Fly this world (y/n/q)?"
        q$=GET$
        CLS
        IF q$="q" OR q$="Q" THEN QUIT
      UNTIL q$="y" OR q$="Y"
      PRINT "Creating the world: please wait a moment."

      REM OK, We've made our world, let's set up D3D and fly round it
      mapscaleh=5  :REM This determines how big the x,y squares are, relative to the vertical coordinates
      DIM l2%(1), b%(1), n%(1), f%(1), s%(1), m%(1), t%(1), y(1), p(1), r(1), X(1), Y(1), Z(1), e(2), a(2)

      ON CLOSE PROCcleanup:QUIT
      ON ERROR PROCcleanup:PRINT REPORT$:END

      PROCSetUpLights

      d% = FN_initd3d(@hwnd%, 1, 1)
      IF d% = 0 ERROR 100, "Can't initialise Direct3D"
      b%(0) = FN_MakeVBuf(d%, n%(0), f%(0), s%(0))
      IF b%(0) = 0 ERROR 100, "Failed to make buffer"
      PROCSetStartPos
      REPEAT
        REM Use arrow keys to bank left or right, or raise or lower nose
        REM Use keys A and Z to accelerate forward or backward, respectively.
        IF INKEY(-66) THEN v+=0.01
        IF INKEY(-98) THEN v-=0.01
        IF INKEY(-26) THEN ra+=0.01
        IF INKEY(-122) THEN ra-=0.01
        IF INKEY(-58) THEN va-=0.01
        IF INKEY(-42) THEN va+=0.01
        ha+=SIN(ra)/100
        px+=v*COS(ha)*COS(va)
        py+=v*SIN(ha)*COS(va)
        pz+=v*SIN(va)
        e() = px,pz,py
        a()=px+COS(ha),pz+SIN(va),py+SIN(ha)
        PROC_render(d%, &FF8080FF, 2, l2%(), 1, m%(), t%(), b%(), n%(), f%(), s%(), y(), p(), r(), X(), Y(), Z(), e(), a(), PI/4, 5/4, 1, 5000,ra)
        q$=INKEY$(1)
        IF q$="r" OR q$="R" THEN PROCSetStartPos:REM Reset position and speed
      UNTIL q$="q" OR q$="Q"
      QUIT
      :
      DEFPROCfillland(l%,b%,side%)
      LOCAL mx%,my%,r%,t%,hs%,localscale
      localscale=2*(RND(1))
      hs%=side% DIV 2
      mx%=l%+hs%
      my%=b%+hs%
      r%=l%+side%
      t%=b%+side%
      l%(r%,my%)=(l%(r%,b%)+l%(r%,t%))/2+(RND(side%)-hs%)*localscale
      l%(mx%,t%)=(l%(l%,t%)+l%(r%,t%))/2+(RND(side%)-hs%)*localscale
      l%(mx%,my%)=(l%(l%,my%)+l%(r%,my%)+l%(mx%,b%)+l%(mx%,t%))/4+(RND(side%)-hs%)*localscale
      IF side%>1 THEN
        PROCfillland(l%,b%,hs%)
        PROCfillland(l%,my%,hs%)
        PROCfillland(mx%,b%,hs%)
        PROCfillland(mx%,my%,hs%)
      ENDIF
      ENDPROC
      :
      DEFPROCMeasureLand
      LOCAL x%,y%
      FOR y%=0 TO s%-1
        FOR x%=0 TO s%-1
          IF l%(x%,y%)>maxh% THEN maxh%=l%(x%,y%)
          IF l%(x%,y%)<minh% THEN minh%=l%(x%,y%)
        NEXT x%
      NEXT y%
      ENDPROC
      :
      DEFPROCPlot
      LOCAL x%,y%
      FOR y%=0 TO s%-1
        MOVE xres%-hscale*y%,vscale*y%+l%(0,y%)*vscale
        FOR x%=0 TO s%-1
          IF l%(x%,y%)<=0 THEN GCOL 4 ELSE GCOL 2
          IF l%(x%,y%)>snowlevel%  THEN GCOL 7
          DRAW xres%-hscale*y%+hscale*x%,vscale*y%+vscale*x%+l%(x%,y%)*vscale
        NEXT x%
      NEXT y%
      ENDPROC
      :
      DEFFN_MakeVBuf(D%,RETURN N%,RETURN V%,RETURN L%)
      LOCAL B%,P%,R%
      N%=s%*s%*6   :REM Number of vertices
      V%=&52  :REM Format for each vertex
      L%=28   :REM Size of each vertex

      SYS!(!D%+92),D%,N%*L%,0,V%,0,^B% TO R%:REM CreateVertexBuffer
      IF R% THEN=0
      SYS!(!B%+44),B%,0,N%*L%,^P%,0:REM Lock

      FOR x%=0 TO s%-1
        FOR y%=0 TO s%-1
          PROCDoVBpoint(P%,x%,y%,n())
          PROCDoVBpoint(P%,(x%+1),y%,n())
          PROCDoVBpoint(P%,(x%+1),(y%+1),n())
    
          PROCDoVBpoint(P%,x%,y%,n())
          PROCDoVBpoint(P%,(x%+1),(y%+1),n())
          PROCDoVBpoint(P%,(x%),(y%+1),n())
        NEXT y%
      NEXT x%


      SYS!(!B%+48),B%:REM Unlock
      =B%
      :
      DEF PROC4(A%):BPUT#F%,A%:BPUT#F%,A%>>8:BPUT#F%,A%>>16:BPUT#F%,A%>>24:ENDPROC
      :
      DEFPROCDoVBpoint(RETURN p%,x%,y%,n())
      LOCAL c%,n(),u(),v()
      DIM n(2),u(2),v(2)
      REM XYZ data
      !p%=FN_f4(mapscaleh*x%)
      p%!4=FN_f4(l%(x%,y%))
      p%!8=FN_f4(mapscaleh*y%)
      p%+=12
      REM Sort out the surface normal, looking at points either side of this one
      IF x%=0 OR x%=s% OR y%=0 OR y%=s% THEN
        n()=0,0,1
      ELSE
  
        u(0)=2:u(1)=0:u(2)=l%(x%+1,y%)-l%(x%-1,y%)
        v(0)=0:v(1)=2:v(2)=l%(x%,y%+1)-l%(x%,y%-1)
  
        n(0)=u(1)*v(2)-u(2)*v(1)
        n(1)=u(2)*v(0)-u(0)*v(2)
        n(2)=u(0)*v(1)-u(1)*v(0)
      ENDIF
      REM Add surface normals
      !p%=FN_f4(n(0))
      p%!4=FN_f4(n(2))
      p%!8=FN_f4(n(1))
      p%+=12
      REM Now work out colour
      CASE TRUE OF
        WHEN l%(x%,y%)=0: c%=&FF0000F0                 :REM water
        WHEN l%(x%,y%)<3:c%=&FFF0F000                  :REM Sand
        WHEN l%(x%,y%)<snowlevel%*3/4:c%=&FF00F000     :REM Grass
        WHEN l%(x%,y%)<snowlevel%:c%=&FFF08050         :REM dirt
        OTHERWISE:c%=&FFF0F0F0                         :REM Snow
      ENDCASE
      !p%=c% :REM Colour data
      p%+=4
      ENDPROC
      :
      DEF PROCcleanup
      REM Stolen unchanged from one of Richard's demos: probably needs beefing up
      t%(1) += 0:IF t%(1) PROC_release(t%(1))
      b%(0) += 0:IF b%(0) PROC_release(b%(0))
      b%(1) += 0:IF b%(1) PROC_release(b%(1))
      d% += 0   :IF d%    PROC_release(d%)
      ENDPROC
      :
      DEFPROCSetUpLights
      REM Set up a couple of light sources: the first is "like the sun",
      REM while the second gives a bit of backlighting from directly above
      DIM D3Dlight8{Type%, Diffuse{r%,g%,b%,a%}, Specular{r%,g%,b%,a%}, \
      \ Ambient{r%,g%,b%,a%}, Position{x%,y%,z%}, Direction{x%,y%,z%}, \
      \ Range%, Falloff%, Attenuation0%, Attenuation1%, Attenuation2%, \
      \ Theta%, Phi% }
      D3Dlight8.Type% = 3 : REM directional source
      D3Dlight8.Diffuse.r% = FN_f4(0.2)
      D3Dlight8.Diffuse.g% = FN_f4(0.2)
      D3Dlight8.Diffuse.b% = FN_f4(0.2)
      D3Dlight8.Direction.x% = FN_f4(1)
      D3Dlight8.Direction.y% = FN_f4(-1)
      D3Dlight8.Direction.z% = FN_f4(1)
      l2%(0) = D3Dlight8{}

      DIM D3Dlight2{}=D3Dlight8{}
      D3Dlight2.Type% = 3 : REM directional source
      D3Dlight2.Diffuse.r% = FN_f4(0.1)
      D3Dlight2.Diffuse.g% = FN_f4(0.1)
      D3Dlight2.Diffuse.b% = FN_f4(0.1)
      D3Dlight2.Direction.x% = FN_f4(0)
      D3Dlight2.Direction.y% = FN_f4(-1)
      D3Dlight2.Direction.z% = FN_f4(0)
      l2%(1) = D3Dlight2{}
      ENDPROC
      :
      DEFPROCSetStartPos
      px=0
      py=0
      pz=maxh%*2
      v=0
      va=-PI/8
      ha=PI/4
      ra=0
      e()= px,pz,py
      a()=0,0,0
      ENDPROC

 

Re: Fractal landscape with D3D
Post by David Williams on Aug 11th, 2015, 6:01pm

Wow! Good work, David. It runs nicely. It was definitely worth signing back up to the BB4W Yahoo! Group just to obtain D3DLIBA so I could run it. smiley

I'll probably experiment a bit with larger landscape sizes.


David.
--


Re: Fractal landscape with D3D
Post by David Williams on Aug 12th, 2015, 6:16pm

Suppose a 'Chocks Away!'-style game where you fire bullets at enemy planes and ground objects, what might be your strategy for accurate (or reasonably accurate) collision detection? For instance, an enemy craft might comprise a few dozen polygons, and there may be dozens of enemy craft flying around. So perhaps an initial, easy, efficient bullet-in-bounding-sphere test followed by (in the case of collision with sphere) a more computationally intensive (but more accurate) check to see if the projectile lies within an angled rectangular prism surrounding each polygon/face of the object?

I haven't yet checked if Direct3D 8, 9 or 11 offers any collision detection functions, so I'll have a look now...


David.
--

Re: Fractal landscape with D3D
Post by DDRM on Aug 12th, 2015, 10:26pm

Yes, something like that - "could I have hit?", refined to "did I hit?". Depends a bit on how fast things will run - you could just cheat, use a slightly smaller bounding sphere, and rely on proximity fuses... wink

Not sure D3D does collision detection, though it may be in the extension DLL that is causing all the trouble with D3D9, and/or may be in later versions. Anyway, I thought that was what GFXLIB(2) was for? grin

D
Re: Fractal landscape with D3D
Post by Torro on Aug 13th, 2015, 07:09am

In dx11 http://www.braynzarsoft.net/index.php?p=D3D11BVCD
Re: Fractal landscape with D3D
Post by David Williams on Aug 13th, 2015, 07:46am

on Aug 12th, 2015, 10:26pm, DDRM wrote:
Not sure D3D does collision detection, though it may be in the extension DLL that is causing all the trouble with D3D9, and/or may be in later versions. Anyway, I thought that was what GFXLIB(2) was for? grin


GFXLIB is oriented towards 2D games; essentially it's an overly-extensive collection of sprite plotters!

Perhaps a new library - 3DLIB.BBC - could include a bunch of subs & functions for doing collision detection, 3D object creation (for creating e.g. Platonic solids, (ir-)regular polyhedra, cones, spheres, etc.), and object loaders for importing 3D objects from Blender, 3DS Max, etc., as well as other useful functions to facilitate game/app creation.

(Just daydreaming. Not volunteering to undertake such a project myself!)


David.
--
Re: Fractal landscape with D3D
Post by Torro on Aug 15th, 2015, 09:06am

ta da

http://bulletphysics.org/Bullet/BulletFull/

https://directxtk.codeplex.com/wikipage?title=GeometricPrimitive&referringTitle=Home

isn't already a object viewer in examples?
Re: Fractal landscape with D3D
Post by David Williams on Aug 15th, 2015, 11:48am

on Aug 15th, 2015, 09:06am, Torro wrote:
ta da

http://bulletphysics.org/Bullet/BulletFull/


We can all dream. wink

I'd give greater priority to a 3D utilities library (perhaps a 3DTOOLSLIB.BBC) I outlined earlier to DDRM, as a companion library to D3DLIB/D3D9LIB, etc.

Just a reminder of some of the functionality that a hypothetical 3DTOOLSLIB could offer:

- Collision detection
- Object loaders (to import from Blender, 3DS, etc.)
- Scene loaders
- Object and mesh manipulation
- 3D primitive object creation
- Procedural texture generators
- Object texturing functions
- Various 3D maths functions
- Various other utility functions

Sadly, the great effort involved in creating such a library, however, may just end up being largely a waste of time and energy. Sorry to be so negative about this.

Torro, have you seen DDRM's germinal/proof-of-concept, fractal landscape-based flight sim he posted to this board a few days ago? Check it out if you haven't already.


David.
--
Re: Fractal landscape with D3D
Post by Torro on Aug 15th, 2015, 3:54pm

David respect for what you did previously just don't end up a troll.


Re: Fractal landscape with D3D
Post by DDRM on Aug 15th, 2015, 10:09pm

Hi Guys,

I have made some progress. I have a model plane, but I am struggling to render the propeller disk semi-transparent. Simply setting the alpha value doesn't seem to hack it. I've played with various things in SetRenderState (such as alpha enable!), but some web sources suggest I need to play with SetTextureStageState as well. Anyone managed to make this work in D3D8 or 9 (I'm currently working with 9, to get Richard's declarations, and so the MSDN pages relate to what I'm doing).

I've managed to get ambient light working: you need to turn it on with SetRenderState, but also tell it to use the vertex colours. That gives a bit of "fill in" light, so the shadows aren't so harsh.

I'm also thinking about the map. It seems obvious that I can't render the whole world at full detail or everything will grind to a halt. I'm planning a low-res, large scale map, which will probable be hand-designed to include interesting places (including flat bits for airfields), and then a modified version of the fractal generator to generate the detailed landscape. Obviously I'll need to pass a seed and reset the RND function each time, so it comes up the same... I thought I could have 4, or maybe 9, buffers containing the local patches of territory around your position.

I haven't quite worked out how to implement that, though...

D
Re: Fractal landscape with D3D
Post by David Williams on Aug 16th, 2015, 12:12pm

Glad you've made some more progress, David.

I'm keeping tabs on this project of yours!

Admittedly, my own tinkerings with D3DLIB some years back never ventured into semi-transparent polygons (most likely because I didn't have the know-how).

David.
--

http://www.proggies.uk/
https://www.youtube.com/channel/UC1E2sxhlc9h9C82q6RFvAWQ
Re: Fractal landscape with D3D
Post by DDRM on Aug 17th, 2015, 4:56pm

OK, a further update.

I now have a model biplane and a model monoplane, including semi-transparent propellers and canopies. That's a bit of a problem, because you can see through the bottom of the plane (normals face the other way...).

You can fly the biplane around (currently using a "chase" view), look at the landscape, and watch the monoplane fly by and disappear (it flies across repeatedly).

I've posted it as an .exe on both wiggio (under games and graphics) and yahoo (under games):

Wiggio
https://wiggio.com/get_document.php?docid=7964547

Yahoo
https://xa.yimg.com/df/bb4w/fracland_Fly.exe?token=YRTx-2h-AQuTsWO1pe0s0_SEAarKtvXui1oxOAI959AnRh82m1NxEtI5MGslG5---buWF_2XvtfUSjxCk7OFFgXcwdG_yRSvHGSJx13iXCk2l63PYA&type=download

Still no physics model or interactions. My daughter likes flying under the earth, and up inside the mountains...

Best wishes,

D
Re: Fractal landscape with D3D
Post by David Williams on Aug 17th, 2015, 5:38pm

Splendid. smiley