1. 3D Landscapes - a closer look

Hi Michael,

Great looking demo.

I've been playing around with 3D projections, and thought
a couple of bits might interest you.

When viewing objects a bit closer, introducing perspective gives a
good effect. The severity of the effect is regulated by the distance
between the view point and the projection plane ( integer d, in this
instance ).

The perspective looks OK, but it still needs a hidden line checking
routine. Try playing around with the 'd' variable.

I wrote a simple landscape generator to demonstrate it. I don't understand
all that fractal stuff, it just picks a bunch of random numbers.

BTW: To slightly reduce your polygon drawing overhead, you could call the
machine_proc() directly (see graphics.e), but obviously you really want
an asm routine that draws lists of triangles to a vscreen.

Hope this helps.

Graeme.


--- snip ---


-- 3D perspective demo. G.Burke 2/97
include get.e
include graphics.e
include machine.e
constant p2= 3.141592653589/2

sequence map,sine,cosine,ang,points,os,pal
integer d,k,zsize,size,s2,z2,zoom

size=power(2,7)+1
s2=floor(size/2)

os={512,200}            -- screen offset for origin
zoom=4                  -- simple dimension multiplier
ang={.001,0.7,3.2}      -- initail angles in radians
d=80                    -- "perspective factor" (dist vp->pp)
zsize=25                -- mountain height

z2=floor(zsize/2)

procedure border_color(integer color)
    sequence regs
    regs=repeat(0,10)
    regs[REG_AX]=#0B00
    regs[REG_BX]=color
    regs=dos_interrupt(#10,regs)
end procedure

if graphics_mode(261) then
end if

-- INSERT YOUR FAVOURITE LANDSCAPE PALETTE HERE
-- pal=
-- all_palette(pal)

border_color(0)

function num()
    return (rand(2000)-1000)/1000
end function


procedure genmap()
    sequence temp,r
    position(1,1)
    puts(1,"Generating map               ")
    r={}
    for y=1 to 16 do
        temp={}
        for x=1 to 16 do
            temp=temp&num()*zsize
        end for
        r=append(r,temp)
    end for
    map=r
    for l= 1 to 4 do
        r={}
        for y=1 to length(map) do
            temp={}
            for x=1 to length(map[1])-1 do
                temp=temp&map[y][x]&(map[y][x]+map[y][x+1])/2+num()
            end for
            r=append(r,temp&map[y][length(map[1])])
        end for
        map=r r={}
        for y=1 to length(map)-1 do
            temp={}
            for x=1 to length(map[1]) do
                temp=temp&(map[y][x]+map[y+1][x])/2+num()
            end for
            r=append(append(r,map[y]),temp)
        end for
        map=append(r,map[length(map)])
    end for
    position(1,1)
    puts(1,"Leveling sea                 ")
    for y=1 to length(map) do
        for x=1 to length(map[1]) do
            if map[y][x]<0.5 then
                map[y][x]=1/zsize+0.1
            end if
        end for
    end for
end procedure

function transform(sequence point)
    atom a,b,c
    a=point[1]*cosine[1]+point[2]*sine[1]
    b=point[2]*cosine[1]-point[1]*sine[1]
    c=point[3]*cosine[2]-a*sine[2]
    a=d-(a*cosine[2]+point[3]*sine[2])
    return floor({((b*cosine[3]+c*sine[3])*d)/a,((c*cosine[3]-b*sine[3])*d)/a})
end function

procedure dotrans()
    position(1,1)
    puts(1,"Calculating screen points.                ")
    points=repeat(repeat({0,0},size),size)
    sine=sin(ang)
    cosine=cos(ang)
    for y=1 to size do
        for x=1 to size do
            points[y][x]=zoom*transform({(x-s2),(y-s2),map[y][x]-z2})+os
            if points[y][x][1]>1023
                or points[y][x][2]>767
                or points[y][x][2]<0
                or points[y][x][1]<0 then
                points[y][x]={0,0}
            end if
        end for
    end for
end procedure

function sgn(atom sn)
    if sn>0 then
        return 1
    elsif sn=0 then
        return 0
    else
        return-1
    end if
end function

procedure draw()
    integer n,y1,y2,x1,x2
    position(1,1)
    puts(1,"                                 ")
    n=bits_to_int((transform({-1,-1,0})>=transform({1,1,0}))&0&0)

    if n=3 then
        x1=1 x2=s2 y2=1 y1=size-1
    elsif n=2 then
        x2=1 x1=size-1 y1=1 y2=s2
    elsif n=1 then
        x1=1 x2=size-1 y1=1 y2=s2
    else
        x1=1 x2=s2 y1=1 y2=size-1
    end if

    clear_screen()
    puts(1,"<ESC> exit <SPACE> rotate 90 <N> new map")
    if n=0 or n=3 then
        for x=x1 to x2 by sgn(x2-x1) do
            for y=y1 to y2 by sgn(y2-y1) do
                if compare(points[y][x],{0,0})!=0
                        and compare(points[y+1][x],{0,0})!=0
                        and compare(points[y][x+1],{0,0})!=0
                        and compare(points[y+1][x+1],{0,0})!=0 then
                    n=floor((map[y][x]/zsize)*220)
                    polygon(n,1,{points[y][x],points[y][x+1],points[y+1][x+1]})
                    polygon(n,1,{points[y][x],points[y+1][x],points[y+1][x+1]})
                end if
                if compare(points[y][size-x],{0,0})!=0
                    and compare(points[y+1][size-x],{0,0})!=0
                    and compare(points[y][size-x+1],{0,0})!=0
                    and compare(points[y+1][size-x+1],{0,0})!=0 then
n=floor((map[y][size-x]/zsize)*220)
                end if
            end for
        end for
    else
        for y=y1 to y2 by sgn(y2-y1) do
            for x=x1 to x2 by sgn(x2-x1) do
                if compare(points[y][x],{0,0})!=0
                        and compare(points[y+1][x],{0,0})!=0
                        and compare(points[y][x+1],{0,0})!=0
                        and compare(points[y+1][x+1],{0,0})!=0 then
                    n=floor((map[y][x]/zsize)*220)
                    polygon(n,1,{points[y][x],points[y][x+1],points[y+1][x+1]})
                    polygon(n,1,{points[y][x],points[y+1][x],points[y+1][x+1]})
                end if
                if compare(points[size-y][x],{0,0})!=0
                    and compare(points[size-y+1][x],{0,0})!=0
                    and compare(points[size-y][x+1],{0,0})!=0
                    and compare(points[size-y+1][x+1],{0,0})!=0 then
n=floor((map[size-y][x]/zsize)*220)
                end if
            end for
        end for
    end if
end procedure

genmap()
dotrans()
draw()
while 1 do
    k=wait_key()
    if k=27 then
        exit
    elsif k=32 then
        ang[1]=ang[1]+p2
        dotrans()
        draw()
    elsif k='n' or k='N' then
        genmap()
        dotrans()
        draw()
    end if
end while

--- snip ---

Pass this on to Bill Oney next time you see him, will you?  ;->

new topic     » topic index » view message » categorize

2. Re: 3D Landscapes - a closer look

>I'll take a look at your thing.  I already do all the perspective
>calculations on mine, and I'm drawing back to front, so I don't have to
>worry about the hidden line problems.

If you are including perspective as against just rotation around each
axis, then as soon as you drop below satellite view you must also draw
from both edges of the screen inwards as well as from back to front to
ensure you are *eventually* displaying the correct polygon. This is the
method my 'thing' uses.

This is compounded when you are looking at the map from an odd angle
as you would have to find the central line of vision and display points,
in order, from most distant to this line, to the closest.

For example: if you are looking north up a city street, you see the east
face of the buildings on the west side of the road and the west face of
the buildings on the east side of the road. If you are drawing from back
to front and left to right, a building on the west side of the road will
be drawn correctly but the east face of a building on the east side of
the road (out of view) will be drawn over the top of the building's roof.
If you are looking up a street that points south south-west, you have to
work out which buildings are on which side of the road.

>If you set wire=0 it will draw
>wireframe with hidden lines. (actually I draw a black filled poly then a
>colored unfilled poly, so whatever was behind the current polygon is
>erased.  Looks nice and clean, especially in 1024x768.

Looks great, but that's not the point, the point is that drawing several
hundred polygons, then drawing over the top of them can hardly be called
speed optomization. Surely to have any hope of doing any of this in
real-time, you'd have to first work out which bits can be seen, before you
bother drawing them. I'm assuming that this exercise is eventually leading
to more than just pretty fractal distractions.
(and they are very pretty - don't get me wrong smile

>In my first few positings I had the perspective D and screen position MY
>positive instead of negative, which made the perspectives look wrong.   It
>was a typo in the book I got the routine from.  Ish.  Ya get some weird
>perspective views by changing these values.  If I get around to it, I'll
>do a version where you can place the camera and target and it will give
>you a perspective view from the surface, which will look much cooler.
>I want to get a fast texture mapping thing working first though.


Sounds great, I look forward to it.

Graeme

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu