Simple 3D model

Game development specific discussions.
Post Reply
Boromir
Posts: 463
Joined: Apr 30, 2015 19:28
Location: Oklahoma,U.S., Earth,Solar System
Contact:

Simple 3D model

Post by Boromir »

This is my first attempt at 3D. It doesn't work because the lines radius's don't shrink correctly.
I'd be happy if someone could show me how to get it working.



Code: Select all


Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   
Dim Shared As Double DtoR = Pi / 180   

screenres 640,480,32

dim as double xdx,xdy,ydx,ydy,zdx,zdy,anglex,angley,anglez,cx,cy,radiusx,radiusy,radiusz
cx = 320
cy = 240
radiusx=50
radiusy=50
radiusz=0

anglex=90
angley=0
anglez=90

do
    
    if anglex=180 then anglex=0
    if anglex=-180 then anglex=0
    if angley=180 then angley=0
    if angley=-180 then angley=0
    if anglez=180 then anglez=0
    if anglez=-180 then anglez=0
    screenlock
    cls
    xdx = cos(anglex*DtoR)*radiusx
    xdy = sin(anglex*DtoR)*radiusx
    ydx = cos(angley*DtoR)*radiusy
    ydy = sin(angley*DtoR)*radiusy
    zdx = cos(anglez*DtoR)*radiusz
    zdy = sin(anglez*DtoR)*radiusz
    
    line (cx-xdx,cy-xdy)-(xdx+cx,xdy+cy),rgb(0,255,0)
    line (cx-ydx,cy-ydy)-(ydx+cx,ydy+cy),rgb(0,255,0)
    line (cx-zdx,cy-zdy)-(zdx+cx,zdy+cy),rgb(0,255,0)
    
    paint (4, 478),rgb(0,255,0), rgb(0,0,0)
    IF MULTIKEY(&h4B) THEN anglex=anglex-1:angley=angley-1':anglez=anglez-1
    IF MULTIKEY(&h4D) THEN anglex=anglex+1:angley=angley+1':anglez=anglez+1
    if multikey(80) and radiusz>=-50 then radiusz=radiusz-1
    if radiusz>=50 then radiusz=-radiusz
    if radiusz<=-50 then radiusz=-radiusz
        
    
    
    print "angle y "+str(angley)
    print "angle x "+str(anglex)
    print "angle z "+str(anglez)   
    
    
    print "radius y "+str(radiusy)
    print "radius x "+str(radiusx)
    print "radius z "+str(radiusz)   
    
    screenunlock
    sleep 10, 1        
loop until multikey(&H01)


bluatigro
Posts: 660
Joined: Apr 25, 2012 10:35
Location: netherlands

Re: Simple 3D model

Post by bluatigro »

try this :

Code: Select all

sub lijn( x1 as single , y1 as single , z1 as single _
, x2 as single , y2 as single , z2 as single , kl as integer )
  if z1 < -900 or z2 < -900 then exit sub
  dim as single a1 , b1 , a2 , b2
  a1 = winx / 2 + x1 / ( z1 + 1000 ) * 1000 
  b1 = winy / 2 - y1 / ( z1 + 1000 ) * 1000
  a2 = winx / 2 + x2 / ( z2 + 1000 ) * 1000
  b2 = winy / 2 - y2 / ( z2 + 1000 ) * 1000
  line ( a1 , b1 ) - ( a2 , b2 ) , kl
end sub

winx and winy are the size of the screen in pixels

see sky car 3d [ line version ] on the ful how to use code
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Simple 3D model

Post by BasicCoder2 »

Boromir wrote:I'd be happy if someone could show me how to get it working.
I wouldn't have a clue how to "get it working" as I think you are going about it the wrong way.

Don't think in terms of lines think in terms of points in 3D space.

Thus in the example below set(x,y) becomes set3D(x,y,z) and line(x1,y1)-(x2,y2) becomes drawLine3D(x1,y1,z1,x2,y2,z2)

These routines are one way to project the 3D points onto a 2D screen.

You will find some examples here on how to do simple 3D graphics,
http://www.petesqbsite.com/sections/tut ... hics.shtml

Below I have modified a rotating cube demo to handle just the three lines of an x,y,z axis.

Code: Select all

'SCREEN VIEW
'             -Y      +Z
'              |     /
'              |    /
'              |   /
'              |  /
'              | /
'              |/
' - X ---------o----------> +X
'             /|
'            / |
'           /  |
'          /   |
'         /    |
'        /     |
'      -Z      |
'             +Y
'
'
'some useful defines
Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As Double DtoR = Pi / 180   ' degrees * DtoR = radians

screenres 500,500,32

sub set3D(x as double,y as double,z as double)
    circle (x+z\2+250,y-z\2+250),3,rgb(0,255,0)
    draw string (x+z\2+250,y-z\2+250),str(int(x+.5))+","+str(int(y+.5))+","+str(int(z+.5))
end sub

sub drawLine3D(x1 as double,y1 as double,z1 as double,x2 as double,y2 as double,z2 as double)
    line (x1+z1\2+250,y1-z1\2+250)-(x2+z2\2+250,y2-z2\2+250),rgb(255,0,0)
    set3D(x1,y1,z1)
    set3D(x2,y2,z2)
end sub

type LINE3D
    as double  x1(2)  'two points to a line
    as double  y1(2)
    as double  z1(2)
    as double rx1(2)
    as double ry1(2)
    as double rz1(2)
end type

dim shared as LINE3D L3D(3) 'three lines


for i as integer = 0 to 2  'three lines
    for j as integer = 0 to 1  'two points each
        read L3D(i).x1(j)
        read L3D(i).y1(j)
        read L3D(i).z1(j)
        L3D(i).rx1(j) = L3D(i).x1(j)
        L3D(i).ry1(j) = L3D(i).y1(j)
        L3D(i).rz1(j) = L3D(i).z1(j)
    next j
next i
    
sub rotatePointsZ(angle as double)
    dim as double px1,py1,pz1
    for i as integer = 0 to 2  ' three lines
        for j as integer = 0 to 1  ' two points each
            px1 = L3D(i).x1(j)
            py1 = L3D(i).y1(j)
            pz1 = L3D(i).z1(j)
            L3D(i).rx1(j) = (Cos(angle*DtoR) * px1 - Sin(angle*DtoR) * py1)
            L3D(i).ry1(j) = (Sin(angle*DtoR) * px1 + Cos(angle*DtoR) * py1)
        next j
    next i
    set3D(0,0,0) 'center of rotation
end sub

sub rotatePointsX(angle as double)
    dim as double px1,py1,pz1
    for i as integer = 0 to 2  ' three lines
        for j as integer = 0 to 1  ' two points each
            pz1 = L3D(i).z1(j)
            py1 = L3D(i).y1(j)
            px1 = L3D(i).x1(j)
            L3D(i).rz1(j) = (Cos(angle*DtoR) * pz1 - Sin(angle*DtoR) * py1)
            L3D(i).ry1(j) = (Sin(angle*DtoR) * pz1 + Cos(angle*DtoR) * py1)
        next j
    next i
    set3D(0,0,0)
end sub

sub rotatePointsY(angle as double)
    dim as double px1,py1,pz1
    for i as integer = 0 to 2  ' three lines
        for j as integer = 0 to 1  'two points each
            pz1 = L3D(i).z1(j)
            px1 = L3D(i).x1(j)
            py1 = L3D(i).y1(j) 
            L3D(i).rz1(j) = (Cos(angle*DtoR) * pz1 - Sin(angle*DtoR) * px1)
            L3D(i).rx1(j) = (Sin(angle*DtoR) * pz1 + Cos(angle*DtoR) * px1)
        next j
    next i
    set3D(0,0,0)
end sub

sub drawPolygons()
    for i as integer = 0 to 2  'three lines
        drawLine3D(L3D(i).rx1(0), L3D(i).ry1(0), L3D(i).rz1(0),  L3D(i).rx1(1) ,L3D(i).ry1(1) ,L3D(i).rz1(1) )
    next i
end sub

dim as double now1
now1 = timer
'rotate points around x,y axis center point 150,350
dim as double angle

'rotate around Z - AXIS
for angle = 0 to 360 step 10
    cls
    locate 2,2
    print "ANGLE ROTATION AROUND Z-AXIS =";angle
    rotatePointsZ(angle)
    drawPolygons()
    while timer-now1 < 0.1
        sleep 2
    wend
    now1 = timer
next angle

'rotate around X - AXIS
for angle = 0 to 360 step 10
    cls
    locate 2,2
    print "ANGLE ROTATION AROUND X-AXIS =";angle
    rotatePointsX(angle)
    drawPolygons()
    while timer-now1 < 0.1
        sleep 2
    wend
    now1 = timer
next angle

'rotate around Y - AXIS
for angle = 0 to 360 step 10
    cls
    locate 2,2
    print "ANGLE ROTATION AROUND Y-AXIS =";angle
    rotatePointsY(angle)
    drawPolygons()
    while timer-now1 < 0.1
        sleep 2
    wend
    now1 = timer
next angle


sleep

'DATA BASE OF THREE LINES
data 0,100,0    'start point of line
data 0,-100,0   'end point of line
data -100,0,0
data +100,0,0
data 0,0,100
data 0,0,-100
Last edited by BasicCoder2 on Jun 21, 2015 13:12, edited 1 time in total.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Simple 3D model

Post by MrSwiss »

@BasicCoder2,
Just a hint:
the use of C-style definition of arrays is BASE 0 (zero), so your array (below) holds 3 Doubles (points) to a line ...
x1(0), x1(1) and x1(2) ... it is better to use BASIC- style definition like x1(1 to 2) or x1(0 to 1) to get what you want.

The same applies to Dim Shared As LINE3D L3D() array dimensions ...

You won't get any errors this way but it's a waste of resources to have arrays "larger than needed".
It also "invalidates" your comments.
BasicCoder2 wrote:type LINE3D
as double x1(2) 'two points to a line
as double y1(2)
as double z1(2)
as double rx1(2)
as double ry1(2)
as double rz1(2)
end type

dim shared as LINE3D L3D(3) 'three lines
Let me add a simple calculation:
your L3D(3) array holds (for each defined Double in Type) 3 * 4 Doubles = 12 Doubles, instead of the 2 * 3 = 6 Doubles you'd expect ...
this equals to: "50% of allocated memory is for nothing".
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Simple 3D model

Post by BasicCoder2 »

@MrSwiss,
Yes this was pointed out to me once before. For me it is an ingrained way of thinking. Physically an address (or index to the first item from an address) is zero not one. That is how it is in the computer hardware and how it is with machine code instructions no matter how it is represented at a "higher level". I assume then that dim as integer (1 to 2) still physically stores the first item at index = 0 and the second item at index = 1 and thus a subtraction of one is required before the compiler generates the actual machine code that everything must ultimately reduces to.

I could just write my array declarations as,

Code: Select all

dim as integer items(0)
items(0) = 6
items(1) = 4
print items(0),items(1)
sleep
However I do take on board what you say and have used the items(1 to 2) declaration which sometimes can make the code more readable, particularly for those unaware of how it all works at a lower level and are used to numbering items 1 to n.

FreeBasic does have C ways as well. Same action, print a string array, two ways to address the items.

Code: Select all

dim as string myText
myText = "THIS IS A TEST STRING"
print
for i as integer = 1 to len(myText)
    print mid(myText,i,1);
next i
print
dim as any ptr i
for i as integer = 0 to len(myText)-1
    print chr(myText[i]);
next i
print
sleep
.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Simple 3D model

Post by MrSwiss »

@BasicCode2,
your example code won't work, because you'd blow the array (upper) bound:
BasicCoder2 wrote:I could just write my array declarations as,

Code:

Code: Select all

    dim as integer items(0)
    items(0) = 6
    items(1) = 4    ' <-- this will throw a compiler error
    print items(0),items(1)
    sleep
You'd have to do a ReDim of items array before that will work:

Code: Select all

dim as integer items(0)
    items(0) = 6
ReDim Preserve items(1)    ' or ReDim Preserve items(0 to 1)
' without the additional 'preserve' you'd loose the items(0) preset value ...
    items(1) = 4
    print "" & items(0) & " " & items(1)
sleep : end
another way would be:

Code: Select all

  Dim as integer items()    ' uninitialised, unsized array
  Redim items(1)    ' now size it to hold 2 integers
  ...
  sleep : end
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Simple 3D model

Post by BasicCoder2 »

MrSwiss wrote:@BasicCode2,your example code won't work, because you'd blow the array (upper) bound:
I did run it before posting and it seemed to work ok. There was no compiler error.
.
grindstone
Posts: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: Simple 3D model

Post by grindstone »

There really is no compiler error, but I strongly recommend NOT to access an array beyond its defined boundaries, for this could have the same side effects as accessing an unallocated memory area by a pointer.

Regards
grindstone
fxm
Moderator
Posts: 12082
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Simple 3D model

Post by fxm »

Yes, because dangerous!
That code compiles without option '-exx', but attention to the result:

Code: Select all

dim as integer post
dim as integer items(0)
items(0) = 6
items(1) = 4
post = 1234
print items(0),items(1)
sleep

Code: Select all

 6             1234
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Simple 3D model

Post by BasicCoder2 »

I am just confused as to how the declarations are being translated. I assumed that dim as integer items(1 to 2) only assigned two locations but there appears to be a zero location as well?
So if I use dim as integer items(1 to 2) the reality is three locations are assigned so the first location goes to waste?
Whereas if I used dim as integer items(2) then only two locations are assigned.

Code: Select all

dim as integer items1(2)   'locations 0 to 1
items1(0) = 3
items1(1) = 5
print items1(0),items1(1)

dim as integer post,items2(1 to 2)   'three locations even if only two are used?
items2(0)=33
post = 123     'see if this is the same locations as items2(0)
items2(1) = 6
items2(2) = 7
print items2(0),items2(1),items2(2)

sleep
fxm
Moderator
Posts: 12082
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Simple 3D model

Post by fxm »

No.

dim as integer items1(2)
is equivalent to:
dim as integer items1(0 to 2)
and allocates 3 integers (items1(0), items1(1) and items1(2))

dim as integer items2(1 to 2)
allocates only 2 integers (items2(1) and items2(2))

Example (always compiling without option '-exx'):

Code: Select all

type UDT
  post as integer
  items(1 to 2) as integer
end type

dim u as UDT
u.items(0)=33
u.post = 123     'see if this is the same locations as items(0)
u.items(1) = 6
u.items(2) = 7
print u.items(0),u.items(1),u.items(2)
sleep

Code: Select all

 123           6             7
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Simple 3D model

Post by MrSwiss »

BasicCoder2 wrote:I am just confused as to how the declarations are being translated. I assumed that dim as integer items(1 to 2) only assigned two locations but there appears to be a zero location as well?
You are still confusing BASIC-/C-style array dimensioning:

Code: Select all

In C-style, always BASE 0:    ' you are only specifying the upper bound of the array, lower bound is implicitly 0 
Dim As ULong xzy(0) equals 1 x ULong
Dim As ULong xzy(1) equals 2 x ULong
Dim As ULong xzy(2) equals 3 x ULong
...
the same in BASIC-style BASE 0:
Dim As ULong xzy(0 To 0) equals 1 x ULong
Dim As ULong xzy(0 To 1) equals 2 x ULong
Dim As ULong xzy(0 To 2) equals 3 x ULong
the same in BASIC-style BASE 1:
Dim As ULong xzy(1 To 1) equals 1 x ULong
Dim As ULong xzy(1 To 2) equals 2 x ULong
Dim As ULong xzy(1 To 3) equals 3 x ULong
Hope this clears the confusion ...
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Simple 3D model

Post by BasicCoder2 »

@fxm and MrSwiss,
Thanks for clearing that up.
Clearly I have been misunderstanding the nomenclature when declaring the dimensions of a BASIC array.
In future I will have to think of dim as integer array(n) as dim as integer array(0 to n)
I checked with my old MS-DOS QBASIC manual and indeed that is how it has always been.
You could start with 1 instead of 0 by using OPTION BASE 1
Back in my old MS-DOS days I mostly coded in Assembler and then later in C.
The reason I converted to FreeBASIC was for readability compared with C and FreeBASIC's easy to use graphics.
In the old days it was easy enough to program the graphic card directly compared with the modern hardware that comes with an overlay of complex software.
.
fxm
Moderator
Posts: 12082
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Simple 3D model

Post by fxm »

'Option Base N' exists always in FreeBASIC, but is only supported in the -lang fblite and -lang qb dialects.
Post Reply