BBC BASIC for Windows
Programming >> Graphics and Games >> The circling sun
http://bb4w.conforums.com/index.cgi?board=graphics&action=display&num=1439155479

The circling sun
Post by KenDown on Aug 9th, 2015, 9:24pm

That rotating world program in the Examples is fascinating. I've been playing around with it and have worked out how to rotate the globe so that it is upright or tilted at the correct angle. I can make the shadow go from half-way round in one direction to half-way round in the other direction, but I can't get it to go all the way around (as if the sun were moving around the earth instead of the earth rotating).

I presume it has something to do with the .z and sure enough, if I alter that I can get the visible face of the globe in complete darkness, but the curious thing is that setting it back to -20 does not restore things to as they were.

Can you give any guidance? Please?
Re: The circling sun
Post by DDRM on Aug 10th, 2015, 08:41am

Hi KenDown,

I presume you are changing the z coordinate of the light? That just controls the position of the light into (or out of) the screen.

If you want the sun to orbit the earth (!), you will need to change the x coordinate as well (assuming the y coordinate is normal to the plane of the ecliptic: not quite true, but good enough for now...).

Try this, added to the loop where the rotation of the earth is occurring:
Code:
        D3Dlight8.Position.x% = FN_f4(20*COS(y(0)))
        D3Dlight8.Position.z% = FN_f4(20*SIN(y(0)))
 


Best wishes,

D


Re: The circling sun
Post by KenDown on Aug 10th, 2015, 11:23am

Thanks very much. In fact Richard wrote early this morning with a similar solution: this is his:

REPEAT
D3Dlight8.Position.x% = FN_f4(30*SIN(TIME/1000))
D3Dlight8.Position.z% = FN_f4(30*COS(TIME/1000))
y() = -TIME/200
r() = -0.4 * COS(y(0))
p() = 0.4 * SIN(y(0))

It works fine. To be honest, it never occurred to me to use SIN and COS - 3D graphics are *very* much a closed book to me, so what you and Richard have posted is extremely useful for my education!

I also wanted to vary the position of the sun to show how the sun moves between the Tropics and discovered that there is a D3Dlight8.Position.y% variable which usefully varies between -18 and 18 to show the movement of the sun.
Re: The circling sun
Post by DDRM on Aug 10th, 2015, 1:48pm

Hi KenDown,

You need to think about a 3D world (or universe!) space. Richard's world is centred at (0,0,0), and I think has radius 1, though I haven't checked rigorously. The light x,y,z parameters control the position of the light in that space.

X means left-to-right, Y means up and down the screen and Z means into or out of it, so using SIN and COS to set the X and Z positions rotates the light around the origin (where the world is) in a plane lying perpendicular to the screen.

As you say, you could mimic summer and winter by changing the Y parameter, but conceptually you might be better off thinking in terms of the angle relative to the origin, rather than absolute Y values. The tropics are about 23.5 degrees above and below the equator, so you could use a sin function to vary the angle with time within these ranges, and then set the Y parameter to 20*SIN(angle), or something like that...

Best wishes,

D
Re: The circling sun
Post by DDRM on Aug 10th, 2015, 3:56pm

I should perhaps add that to get the seasons right you'd need to set the world upright! You can do that by setting the roll r() and pitch p() assignments in the program to 0.

That gives a bit of a geocentric view, though! The sun doesn't REALLY wobble up and down...

smiley

D
Re: The circling sun
Post by Torro on Aug 10th, 2015, 5:26pm

REM Solar System Simulator

MODE 10 : OFF
REM screen dimensions
SCREEN_WIDTH% = 1440
SCREEN_HEIGHT% = 1152

REM -------------------------------------------
REM STUFF TO MUCK AROUND WITH
REM -------------------------------------------
SUN_RADIUS% = 100 : REM pixels
SUN_MASS% = 100 : REM relative units
PLANETS% = 30
REM -------------------------------------------

BLACK% = 1 : COLOUR BLACK%, 0, 0, 0
SUN_COL% = 2 : COLOUR SUN_COL%, 255, 255, 0
PLANET_COL% = 3 : REM colour pot for planets
PLANET_MULT% = 4 : REM size of planet per unit of mass

REM create the planet structure
DIM planet{(PLANETS%-1) x, y, dx, dy, mass, green%, blue% }

REM randomly create planets
PROC_createPlanet( planet{()} )

REM MAIN LOOP
REPEAT
*refresh off
PROC_drawSun
PROC_drawPlanets( planet{()} )
*refresh
WAIT 5
*refresh off
PROC_removePlanets( planet{()} )
*refresh
PROC_move( planet{()} )
PROC_gravity( planet{()} )
UNTIL FALSE



DEFPROC_createPlanet( this{()} )
REM creates random planets
LOCAL i%
FOR i% = 0 TO PLANETS%-1
this{(i%)}.x = RND(SCREEN_WIDTH%)
this{(i%)}.y = RND(SCREEN_HEIGHT%)
this{(i%)}.dx = RND(10)+5
this{(i%)}.dy = RND(10)+5
this{(i%)}.green% = RND(256)-1
this{(i%)}.blue% = RND(256)-1
this{(i%)}.mass = RND(10)
NEXT
ENDPROC


DEFPROC_drawSun
REM draws the yellow star in center of screen
GCOL 0, SUN_COL%
CIRCLE FILLSCREEN_WIDTH% DIV 2, SCREEN_HEIGHT% DIV 2, SUN_RADIUS%
ENDPROC


DEFPROC_drawPlanets( this{()} )
REM draw each planet
LOCAL i%
FOR i% = 0 TO PLANETS% -1
COLOUR PLANET_COL%, 0, this{(i%)}.green%, this{(i%)}.blue%
GCOL 0, PLANET_COL%
CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.mass * PLANET_MULT%
NEXT
ENDPROC

DEFPROC_removePlanets( this{()} )
REM remove planets from the screen
LOCAL i%
GCOL 0, BLACK%
FOR i% = 0 TO PLANETS% -1
CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.mass * PLANET_MULT%
NEXT
ENDPROC


DEFPROC_move( this{()} )
REM move planet due to its own velocity
LOCAL i%
FOR i% = 0 TO PLANETS% -1
this{(i%)}.x += this{(i%)}.dx
this{(i%)}.y += this{(i%)}.dy
NEXT
ENDPROC


DEFPROC_gravity( this{()} )
REM apply gravity to each planet from the sun
LOCAL distance
LOCAL i% : REM iterator
FOR i% = 0 TO PLANETS% - 1
distance = SQR( (SCREEN_WIDTH% DIV 2 - this{(i%)}.x)^2 + (SCREEN_HEIGHT% DIV 2 - this{(i%)}.y)^2 )
IF distance<>0 THEN
this{(i%)}.dx += ( this{(i%)}.mass * SUN_MASS% * (SCREEN_WIDTH% DIV 2 - this{(i%)}.x) / distance^2 )
this{(i%)}.dy += ( this{(i%)}.mass * SUN_MASS% * (SCREEN_HEIGHT% DIV 2 - this{(i%)}.y) / distance^2 )
ENDIF
NEXT
ENDPROC


a starting pint to directxtify

Re: The circling sun
Post by David Williams on Aug 10th, 2015, 5:40pm

Very nice Torro!

Sorry to presume, but here's my slightly modified version which eliminates the flicker (which you may not have noticed in your original version):

Note: If it runs too fast then just increase the delay value for the WAIT command (currently specified as 2)


Code:
      REM Solar System Simulator

      REM Modified by D.A.W.

      MODE 10 : OFF
      REM screen dimensions
      SCREEN_WIDTH% = 1440
      SCREEN_HEIGHT% = 1152

      REM -------------------------------------------
      REM STUFF TO MUCK AROUND WITH
      REM -------------------------------------------
      SUN_RADIUS% = 100 : REM pixels
      SUN_MASS% = 100 : REM relative units
      PLANETS% = 30
      REM -------------------------------------------

      BLACK% = 1 : COLOUR BLACK%, 0, 0, 0
      SUN_COL% = 2 : COLOUR SUN_COL%, 255, 255, 0
      PLANET_COL% = 3 : REM colour pot for planets
      PLANET_MULT% = 4 : REM size of planet per unit of mass

      REM create the planet structure
      DIM planet{(PLANETS%-1) x, y, dx, dy, mass, green%, blue% }

      REM randomly create planets
      PROC_createPlanet( planet{()} )

      *refresh off

      REM MAIN LOOP
      REPEAT
        CLS
        PROC_drawSun
        PROC_drawPlanets( planet{()} )
        REM *refresh
        REM WAIT 5
        REM *refresh off
        REM PROC_removePlanets( planet{()} )
        *refresh
        WAIT 2
        PROC_move( planet{()} )
        PROC_gravity( planet{()} )
      UNTIL FALSE



      DEFPROC_createPlanet( this{()} )
      REM creates random planets
      LOCAL i%
      FOR i% = 0 TO PLANETS%-1
        this{(i%)}.x = RND(SCREEN_WIDTH%)
        this{(i%)}.y = RND(SCREEN_HEIGHT%)
        this{(i%)}.dx = RND(10)+5
        this{(i%)}.dy = RND(10)+5
        this{(i%)}.green% = RND(256)-1
        this{(i%)}.blue% = RND(256)-1
        this{(i%)}.mass = RND(10)
      NEXT
      ENDPROC


      DEFPROC_drawSun
      REM draws the yellow star in center of screen
      GCOL 0, SUN_COL%
      CIRCLE FILLSCREEN_WIDTH% DIV 2, SCREEN_HEIGHT% DIV 2, SUN_RADIUS%
      ENDPROC


      DEFPROC_drawPlanets( this{()} )
      REM draw each planet
      LOCAL i%
      FOR i% = 0 TO PLANETS% -1
        COLOUR PLANET_COL%, 0, this{(i%)}.green%, this{(i%)}.blue%
        GCOL 0, PLANET_COL%
        CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.mass * PLANET_MULT%
      NEXT
      ENDPROC

      DEFPROC_removePlanets( this{()} )
      REM remove planets from the screen
      LOCAL i%
      GCOL 0, BLACK%
      FOR i% = 0 TO PLANETS% -1
        CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.mass * PLANET_MULT%
      NEXT
      ENDPROC


      DEFPROC_move( this{()} )
      REM move planet due to its own velocity
      LOCAL i%
      FOR i% = 0 TO PLANETS% -1
        this{(i%)}.x += this{(i%)}.dx
        this{(i%)}.y += this{(i%)}.dy
      NEXT
      ENDPROC


      DEFPROC_gravity( this{()} )
      REM apply gravity to each planet from the sun
      LOCAL distance
      LOCAL i% : REM iterator
      FOR i% = 0 TO PLANETS% - 1
        distance = SQR( (SCREEN_WIDTH% DIV 2 - this{(i%)}.x)^2 + (SCREEN_HEIGHT% DIV 2 - this{(i%)}.y)^2 )
        IF distance<>0 THEN
          this{(i%)}.dx += ( this{(i%)}.mass * SUN_MASS% * (SCREEN_WIDTH% DIV 2 - this{(i%)}.x) / distance^2 )
          this{(i%)}.dy += ( this{(i%)}.mass * SUN_MASS% * (SCREEN_HEIGHT% DIV 2 - this{(i%)}.y) / distance^2 )
        ENDIF
      NEXT
      ENDPROC
 

Re: The circling sun
Post by Torro on Aug 10th, 2015, 5:49pm

how is this done?

http://www.solarsystemscope.com/


Re: The circling sun
Post by KenDown on Aug 11th, 2015, 10:34am

Wow! There's a lot there for me to study and - I hope - learn. I'm particularly interested in the planets, though I intend to have just one and to make it the sun, to pass across or behind the globe as the daylight moves.

Anyway, here is my version of Richard's program. Purists will doubtless cringe at some of the things, but it is intended as a teaching aid, not as a demonstration of how the earth/sun actually are.

REM. Direct3D Rotating Globe in BBC BASIC for Windows
REM (C) R.T.Russell 2013, http://www.rtrussell.co.uk/

REM Additions: Keypad + and - alter the angle of rotation from upright to tilted
REM Up and Down arrow alter the season
REM S (Ctrl to reverse) move the sun around the globe
REM Left and Right arrow rotate the globe
REM R G B (Ctrl to reverse) alter the colour of the background
REM Q causes the program to terminate

MODE8:OFF
PROCinit

ON CLOSE PROCcleanup:QUIT
ON ERROR PROCcleanup:PRINTREPORT$:END

*REFRESH OFF
VDU5

REPEAT
r()=-inc*COS(y(0))
p()=inc*SIN(y(0))
PROC_render(d%,I%,1,l%(),1,m%(),t%(),b%(),n%(),f%(),s%(),y(),p(),r(),X(),Y(),Z(),e(),a(),0.4,5/4,1,1000)
IFINKEY-26y()+=0.01:REM Left to rotate the globe
IFINKEY-122y()-=0.01:REM Right
IFINKEY-59=-1inc+=0.01:IFinc>0.4inc=0.4:REM Keypad + to tilt the globe
IFINKEY-60=-1inc-=0.01:IFinc<0inc=0:REM Keypad -
IFINKEY-82=-1IFINKEY-2=0S+=0.002:IFS>9.59S=3.2:REM S to alter the time
IFINKEY-82=-1IFINKEY-2=-1S-=0.004:IFS<3.2S=9.59:REM Ctrl+S
IFINKEY-58=-1day%=(day%+1)MOD365:REM Up to alter the date
IFINKEY-42=-1day%-=1:IFday%=0day%=365:REM Down
IFINKEY-52=-1I%+=&00010000:IFINKEY-2=-1I%-=&00020000:REM R to alter the background colour
IFINKEY-84=-1I%+=&00000100:IFINKEY-2=-1I%-=&00000200:REM G
IFINKEY-101=-1I%+=&00000001:IFINKEY-2=-1I%-=&00000002:REM B
Y=-1.6*(ABS(day%-182.5)/10)+18.2

sx%=100:IFS>6.4sx%=1180
sy%=Y*10
GCOL3,11:CIRCLEFILLsx%,512+(sy%+inc*400),50
D3Dlight8.Position.x%=FN_f4(30*SIN(S))
D3Dlight8.Position.z%=FN_f4(30*COS(S)-8)
D3Dlight8.Position.y%=FN_f4(Y+inc*30)

SYS"SetDlgItemText",!dialog%,110,FNtime(S)
SYS"SetDlgItemText",!dialog%,111,FNm(day%)
*REFRESH
GCOL3,11:CIRCLEFILLsx%,512+(sy%+inc*400),50

*FX21,0
g%=INKEY(1)
UNTILINKEY-17=-1
PROCcleanup
*REFRESH ON
END

IFINKEY-52=-1I%+=&00010000:IFINKEY-2=-1I%-=&00020000:REM R
IFINKEY-84=-1I%+=&00000100:IFINKEY-2=-1I%-=&00000200:REM G
IFINKEY-101=-1I%+=&00000001:IFINKEY-2=-1I%-=&00000002:REM B
:
DEFFNatan2(y,x):ON ERROR LOCAL:=SGN(y)*PI/2
IFx>0:=ATN(y/x) ELSEIFy>0:=ATN(y/x)+PI ELSE=ATN(y/x)-PI


DEFPROCcleanup
b%(0)+=0:IFb%(0)PROC_release(b%(0))
d%+=0:IFd%PROC_release(d%)
ENDPROC

DEFPROCtriangulate(L%,F%,x0,y0,z0,x1,y1,z1,x2,y2,z2)
L%-=1
IFL%THEN
LOCALa(),b(),c()
DIMa(2),b(2),c(2)
a(0)=x0+x2:a(1)=y0+y2:a(2)=z0+z2:a()/=MOD(a())
b(0)=x0+x1:b(1)=y0+y1:b(2)=z0+z1:b()/=MOD(b())
c(0)=x1+x2:c(1)=y1+y2:c(2)=z1+z2:c()/=MOD(c())
PROCtriangulate(L%,F%,x0,y0,z0,b(0),b(1),b(2),a(0),a(1),a(2))
PROCtriangulate(L%,F%,b(0),b(1),b(2),x1,y1,z1,c(0),c(1),c(2))
PROCtriangulate(L%,F%,a(0),a(1),a(2),b(0),b(1),b(2),c(0),c(1),c(2))
PROCtriangulate(L%,F%,a(0),a(1),a(2),c(0),c(1),c(2),x2,y2,z2)
ELSE
LOCALu0,u1,u2,v0,v1,v2
PROCvertex(x0,y0,z0,u0,v0)
PROCvertex(x1,y1,z1,u1,v1)
PROCvertex(x2,y2,z2,u2,v2)
IF(u1-u0)>0.5u0+=1.0
IF(u0-u1)>0.5u1+=1.0
IF(u2-u1)>0.5u1+=1.0
IF(u1-u2)>0.5u2+=1.0
IF(u0-u2)>0.5u2+=1.0
IF(u2-u0)>0.5u0+=1.0
PROC4(F%,FN_f4(-x0)):PROC4(F%,FN_f4(z0)):PROC4(F%, FN_f4(y0))
PROC4(F%,FN_f4(-x0)):PROC4(F%,FN_f4(z0)):PROC4(F%, FN_f4(y0))
PROC4(F%,&FFFFFF) :PROC4(F%,FN_f4(u0)):PROC4(F%, FN_f4(v0))
PROC4(F%,FN_f4(-x1)):PROC4(F%,FN_f4(z1)):PROC4(F%, FN_f4(y1))
PROC4(F%,FN_f4(-x1)):PROC4(F%,FN_f4(z1)):PROC4(F%, FN_f4(y1))
PROC4(F%,&FFFFFF) :PROC4(F%,FN_f4(u1)):PROC4(F%, FN_f4(v1))
PROC4(F%,FN_f4(-x2)):PROC4(F%,FN_f4(z2)):PROC4(F%, FN_f4(y2))
PROC4(F%,FN_f4(-x2)):PROC4(F%,FN_f4(z2)):PROC4(F%, FN_f4(y2))
PROC4(F%,&FFFFFF) :PROC4(F%,FN_f4(u2)):PROC4(F%, FN_f4(v2))
ENDIF
ENDPROC

DEFPROCvertex(x,y,z,RETURN u,RETURN v)
u=FNatan2(x,y)/PI/2+0.5
v=FNatan2(z,SQR(x^2+y^2))/PI+0.5
ENDPROC
:
DEFPROC4(F%,A%)
BPUT#F%,A%:BPUT#F%,A%>>8:BPUT#F%,A%>>16:BPUT#F%,A%>>24
ENDPROC
:
DEFFNm(day%):LOCALi%
day%-=9:IFday%<1day%+=365
WHILEday%>month%(i%)
day%-=month%(i%)
i%+=1
ENDWHILE
=STR$day%+" "+MID$(month$,i%*3+1,3)+" "
:
DEFFNtime(S)
t=S-3.2
h%=(12+(t*3.75))MOD24
m%=(S*225)MOD60
PROCclock(h%,m%)
=FNp(h%)+":"+FNp(m%)+":00"
:
DEFFNp(n%)
=RIGHT$("0"+STR$n%,2)
:
DEFPROCclock(h%,m%)
GCOL0,15:CIRCLEFILLclockx%,clocky%,60
GCOL0,0: CIRCLEclockx%,clocky%,60
h=h%*PI/6
LINEclockx%,clocky%,clockx%+SINh*40,clocky%+COSh*40
m=m%*PI/30
LINEclockx%,clocky%,clockx%+SINm*50,clocky%+COSm*50
ENDPROC
:
DEFPROCinit
INSTALL@lib$+"WINLIB2"
INSTALL@lib$+"D3DLIB"

DIM l%(0), b%(0), n%(0), f%(0), s%(0), m%(0), t%(0), y(0), p(0), r(0), X(0), Y(0), Z(0), e(2), a(2)
d%=FN_initd3d(@hwnd%, 1, 1)
IFd%=0 ERROR 100,"Can't initialise Direct3D"

file%=OPENOUT(@tmp$+"SPHERE.B3D")
PROC4(file%,6144):REM vertex count
PROC4(file%,&00240152):REM vertex format and size
PROCtriangulate(5,file%, 1, 0, 0, 0, 0, 1, 0, 1, 0)
PROCtriangulate(5,file%, 0, 1, 0, 0, 0, 1,-1, 0, 0)
PROCtriangulate(5,file%,-1, 0, 0, 0, 0, 1, 0,-1, 0)
PROCtriangulate(5,file%, 0,-1, 0, 0, 0, 1, 1, 0, 0)
PROCtriangulate(5,file%, 1, 0, 0, 0, 1, 0, 0, 0,-1)
PROCtriangulate(5,file%, 0, 1, 0,-1, 0, 0, 0, 0,-1)
PROCtriangulate(5,file%,-1, 0, 0, 0,-1, 0, 0, 0,-1)
PROCtriangulate(5,file%, 0,-1, 0, 1, 0, 0, 0, 0,-1)
CLOSE#file%

b%(0)=FN_load3d(d%,@tmp$+"SPHERE.B3D",n%(0),f%(0),s%(0))
IFb%(0)=0 ERROR 100,"Can't load SPHERE.B3D"

t%(0)=FN_loadtexture(d%,@dir$+"WORLD.JPG")
IFt%(0)=0 ERROR 100,"Can't load WORLD.JPG"

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% = 1 : REM point source
D3Dlight8.Diffuse.r% = FN_f4(1)
D3Dlight8.Diffuse.g% = FN_f4(1)
D3Dlight8.Diffuse.b% = FN_f4(1)
D3Dlight8.Position.x% = FN_f4(30*SIN(TIME/500))
D3Dlight8.Position.z% = FN_f4(30*COS(TIME/500))
D3Dlight8.Range% = FN_f4(200)
D3Dlight8.Attenuation0% = FN_f4(0.2)
l%(0) = D3Dlight8{}

e()=0,0,-6:REM Size of globe: originally -9
a()=0,0, 0
y()=600

REM My variables
I%=&00000020:REM Background colour of the window &00RRGGBB
inc=0:REM Angle of the globe. 0 is vertical, 0.4 is the earth's inclination
S=3.2:REM3.2 Position of the shadow
day%=90
sgn%=-1
clockx%=100
clocky%=920

DIMmonth%(12):REM Array to hold the number of days per month
month%()=31,28,31,30,31,30,31,31,30,31,30,31
month$="JanFebMarAprMayJunJulAugSepOctNovDec"

DIMrc{l%,t%,r%,b%}

dialog%=FN_newdialog("Parameters",322,-15,100,256,10,400)
PROC_static(dialog%,"Time:",100,10,10,30,12,0)
PROC_static(dialog%,"Season:",101,10,24,30,12,0)
PROC_editbox(dialog%,"",110,40,8,40,12,0)
PROC_editbox(dialog%,"",111,40,22,40,12,0)
PROC_showdialog(dialog%)

VDU23,23,2;0;0;0;
SYS"SetForegroundWindow",@hwnd%
ENDPROC


The keys are:
Numberpad +/- to tilt the globe on its axis
S/Ctrl+S to move day and night around the globe
Up/Down arrow to alter the date
Left/Right arrow to rotate the globe


Re: The circling sun
Post by KenDown on Aug 12th, 2015, 04:06am

Hmmmm. Just playing around with the solar system simulator, it does not appear to be 3D - the "planets" never pass behind the sun but alway appear in front of it.

A bit of a disappointment, that.
Re: The circling sun
Post by Torro on Aug 12th, 2015, 3:25pm

That's how this game works

some one posts some code. You then modify it and repost it
Re: The circling sun
Post by KenDown on Aug 12th, 2015, 3:38pm

Indeed. It just seemed odd when the topic is the 3D world that a 2D simulation is posted.