Author Topic: Perspective correct texture mapping problems...  (Read 11213 times)

0 Members and 1 Guest are viewing this topic.

Offline Dr_D

  • Atari ST
  • ***
  • Posts: 151
  • Karma: 29
    • View Profile
Hey guys. I was just messing around, and I'm having some problems here. Can anyone spot what I'm doing wrong? It could use tons and tons of optimizations, but I can't get the texture coords working properly now... I don't know what I've done. Thanks! :)

Code: [Select]
#include "fbgfx.bi"

type vec2f
    as single x, y
end type

type vec3f
    as single x, y, z
end type

type trgb
    as uinteger r,g,b
end type


const as integer scr_w = 640
const as integer scr_h = 480

screenres scr_w, scr_h, 32,,FB.GFX_HIGH_PRIORITY

declare sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byval p1 as vec3f, byval t1 as vec2f, byval cl1 as trgb, byval p2 as vec3f, byval t2 as vec2f, byval cl2 as trgb, byval p3 as vec3f, byval t3 as vec2f, byval cl3 as trgb, byref texture as FB.IMAGE ptr )   

dim as FB.IMAGE ptr image = imagecreate( 256, 256 )

if bload( "rock.bmp", image) <> 0 then
    for y as integer = 0 to 255
        for x as integer = 0 to 255
            dim as integer rgbc = (x and y)
            pset image,(x,y), rgb( rgbc, rgbc, rgbc )
        next
    next
end if


dim as vec3f p1, p2, p3
dim as vec2f t1, t2, t3
dim as trgb c1, c2, c3

t1 = type( 0, 0 )
t2 = type( 0, 255 )
t3 = type( 255, 255 )

c1= type(255,0,0)
c2= type(0,255,0)
c3= type(0,0,255)


do
    dim as double ttime = timer

    p1 = type( 320+350*sin(ttime), 240+350*cos(ttime), -10 )
    p2 = type( 320+350*sin(ttime+1.5), 240+350*cos(ttime+1.5), -10 )
    p3 = type( 320+350*sin(ttime+3.14), 240+350*cos(ttime+3.14), 0 )

    screenlock
    line(0,0)-(640,480),0,bf
   
    tgpcTri(0, p1, t1, c1, p2, t2, c2, p3, t3, c3, image )

    screensync
    screenunlock
   
    sleep 3,1
   
loop until inkey$ <> ""


sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byval p1 as vec3f, byval t1 as vec2f, byval cl1 as trgb, byval p2 as vec3f, byval t2 as vec2f, byval cl2 as trgb, byval p3 as vec3f, byval t3 as vec2f, byval cl3 as trgb, byref texture as FB.IMAGE ptr )   
   
    static as uinteger ptr dstptr
    static as uinteger ptr srcptr
   
    static as integer x1, x2, x3
    static as integer y1, y2, y3
    static as integer z1, z2, z3
    static as integer u1, u2, u3
    static as integer v1, v2, v3
    static as integer r1, r2, r3
    static as integer g1, g2, g3
    static as integer b1, b2, b3
    static as integer dw,dh,dbpp,dpitch
    static as integer sw,sh,sbpp,spitch
    static as integer scanlen, pu, pv
    static as integer dx1, dx2, dx3
    static as integer dy1, dy2, dy3
    static as integer dz1, dz2, dz3
    static as integer du1, du2, du3
    static as integer dv1, dv2, dv3
    static as integer dr1, dr2, dr3
    static as integer dg1, dg2, dg3
    static as integer db1, db2, db3
    static as integer col, r, g, b

    static as single sx, ex, sz, ez, su, eu, sv, ev, sr, er, sg, eg, sb, eb
    static as single xd1, xd2, xd3, lx, rx, recz
    static as single zd1, zd2, zd3, lz, rz, nz, zinc
    static as single ud1, ud2, ud3, lu, ru, nu, uinc
    static as single vd1, vd2, vd3, lv, rv, nv, vinc
    static as single rd1, rd2, rd3, lr, rr, nr, rinc
    static as single bd1, bd2, bd3, lb, rb, nb, binc
    static as single gd1, gd2, gd3, lg, rg, ng, ginc

   

    if dst = 0 then
        dstptr = screenptr
        screeninfo dw, dh,, dbpp, dpitch
    else
        dstptr = cast (uinteger ptr, dst+1 )
        dw = dst->width
        dh = dst->height
        dbpp = dst->bpp
        dpitch = dst->pitch
    end if

    srcptr =  cast (uinteger ptr, texture+1 )
    sw = texture->width
    sh = texture->height
    sbpp = texture->bpp
    spitch = texture->pitch   
   
   
    x1 = p1.x
    x2 = p2.x
    x3 = p3.x
   
    y1 = p1.y
    y2 = p2.y
    y3 = p3.y
   
    z1 = p1.z
    z2 = p2.z
    z3 = p3.z

    u1 = t1.x
    u2 = t2.x
    u3 = t3.x

    v1 = t1.y
    v2 = t2.y
    v3 = t3.y
   
    r1 = cl1.r
    r2 = cl2.r
    r3 = cl3.r
   
    g1 = cl1.g
    g2 = cl2.g
    g3 = cl3.g
   
    b1 = cl1.b
    b2 = cl2.b
    b3 = cl3.b


    if y2 < y1 then
        swap x1, x2
        swap y1, y2
        swap z1, z2
        swap u1, u2
        swap v1, v2
        swap r1, r2
        swap g1, g2
        swap b1, b2
    end if
   
    if y3 < y1 then
        swap x3, x1
        swap y3, y1
        swap z3, z1
        swap u3, u1
        swap v3, v1
        swap r3, r1
        swap g3, g1
        swap b3, b1
    end if
   
    if y3 < y2 then
        swap x3, x2
        swap y3, y2
        swap z3, z2
        swap u3, u2
        swap v3, v2
        swap r3, r2
        swap g3, g2
        swap b3, b2
    end if
   

    dx1 = x2 - x1
    dy1 = y2 - y1
    dz1 = z2 - z1
    du1 = u2 - u1
    dv1 = v2 - v1
    dr1 = r2 - r1
    dg1 = g2 - g1
    db1 = b2 - b1
    if dy1 <> 0 then
        xd1 = dx1 / dy1
        zd1 = dz1 / dy1
        ud1 = du1 / dy1
        vd1 = dv1 / dy1
        rd1 = dr1 / dy1
        gd1 = dg1 / dy1
        bd1 = db1 / dy1
    else
        xd1 = 0
        zd1 = 0
        ud1 = 0
        vd1 = 0
        rd1 = 0
        gd1 = 0
        bd1 = 0
    end if

   
    dx2 = x3 - x2
    dy2 = y3 - y2
    dz2 = z3 - z2
    du2 = u3 - u2
    dv2 = v3 - v2
    dr2 = r3 - r2
    dg2 = g3 - g2
    db2 = b3 - b2
    if dy2 <> 0 then
        xd2 = dx2 / dy2
        zd2 = dz2 / dy2
        ud2 = du2 / dy2
        vd2 = dv2 / dy2
        rd2 = dr2 / dy2
        gd2 = dg2 / dy2
        bd2 = db2 / dy2
    else
        xd2 = 0
        zd2 = 0
        ud2 = 0
        vd2 = 0
        rd2 = 0
        gd2 = 0
        bd2 = 0
    end if

   
    dx3 = x1 - x3
    dy3 = y1 - y3
    dz3 = z1 - z3
    du3 = u1 - u3
    dv3 = v1 - v3
    dr3 = r1 - r3
    dg3 = g1 - g3
    db3 = b1 - b3
    if dy3 <> 0 then
        xd3 = dx3 / dy3
        zd3 = dz3 / dy3
        ud3 = du3 / dy3
        vd3 = dv3 / dy3
        rd3 = dr3 / dy3
        gd3 = dg3 / dy3
        bd3 = db3 / dy3
    else
        xd3 = 0
        zd3 = 0
        ud3 = 0
        vd3 = 0
        rd3 = 0
        gd3 = 0
        bd3 = 0
    end if
   
    lx = x1
    rx = x1
    lz = z1
    rz = z1
    lu = u1
    ru = u1
    lv = v1
    rv = v1

    lr = r1
    rr = r1
    lg = g1
    rg = g1
    lb = b1
    rb = b1
   
    for y as integer = y1 to y2 - 1
       
        if y>-1 and y<dh then
           
            sx = lx
            ex = rx
            su = lu
            eu = ru
            sv = lv
            ev = rv
            sz = lz
            ez = rz

            sr = lr
            er = rr
            sg = lg
            eg = rg
            sb = lb
            eb = rb
           
            if sx>ex then
                swap sx, ex
                swap su, eu
                swap sv, ev
                swap sz, ez
                swap sr, er
                swap sg, eg
                swap sb, eb
            end if
           
            scanlen = (ex-sx)
            uinc = (eu-su) / scanlen
            vinc = (ev-sv) / scanlen
            zinc = (ez-sz) / scanlen
            rinc = (er-sr) / scanlen
            ginc = (eg-sg) / scanlen
            binc = (eb-sb) / scanlen

            nu = su/sz
            nv = sv/sz
            nz = 1.0/sz
            nr = sr
            ng = sg
            nb = sb

            for x as integer = sx to ex
           
               
                if x>-1 and x<dw then

                    recz = 1.0/nz
                   
                    pu = abs(nu*recz) MOD sw
                    pv = abs(nv*recz) MOD sh
                    col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
                    r = (col shr 16) and 255
                    g = (col shr 8) and 255
                    b = (col)  and 255

                    r+=(nr)
                    if r<0 then
                        r = 0
                    elseif r>255 then
                        r = 255
                    end if

                    g+=(ng)
                    if g<0 then
                        g = 0
                    elseif g>255 then
                        g = 255
                    end if

                    b+=(nb)
                    if b<0 then
                        b = 0
                    elseif b>255 then
                        b = 255
                    end if

                    *cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)
                   
                end if
               
                nu+=uinc
                nv+=vinc
                nz+=zinc
                nr+=rinc
                ng+=ginc
                nb+=binc
               
            next
           
        end if
       
        lx += xd1
        rx += xd3
        lu += ud1
        ru += ud3
        lv += vd1
        rv += vd3
        lz += zd1
        rz += zd3

        lr += rd1
        rr += rd3
        lg += gd1
        rg += gd3
        lb += bd1
        rb += bd3

    next
   
   
    lx = x2
    lz = z2
    lu = u2
    lv = v2
    lr = r2
    lg = g2
    lb = b2

    for y as integer = y2 to y3
       
        if y>-1 and y<dh then
           
            sx = lx
            ex = rx
            su = lu
            eu = ru
            sv = lv
            ev = rv
            sz = lz
            ez = rz

            sr = lr
            er = rr
            sg = lg
            eg = rg
            sb = lb
            eb = rb
           
            if sx>ex then
                swap sx, ex
                swap su, eu
                swap sv, ev
                swap sz, ez
                swap sr, er
                swap sg, eg
                swap sb, eb
            end if
           
            scanlen = (ex-sx)+1
            uinc = (eu-su) / scanlen
            vinc = (ev-sv) / scanlen
            zinc = (ez-sz) / scanlen
            rinc = (er-sr) / scanlen
            ginc = (eg-sg) / scanlen
            binc = (eb-sb) / scanlen

            nu = su/sz
            nv = sv/sz
            nz = 1.0/sz
            nr = sr
            ng = sg
            nb = sb
           
            for x as integer = sx to ex
               
                if x>-1 and x<dw then

                    recz = 1.0/nz
                   
                    pu = abs(nu*recz) MOD sw
                    pv = abs(nv*recz) MOD sh
                   
                    col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
                    r = (col shr 16) and 255
                    g = (col shr 8) and 255
                    b = (col)  and 255
                   
                    r+=(nr)
                    if r<0 then
                        r = 0
                    elseif r>255 then
                        r = 255
                    end if

                    g+=(ng)
                    if g<0 then
                        g = 0
                    elseif g>255 then
                        g = 255
                    end if

                    b+=(nb)
                    if b<0 then
                        b = 0
                    elseif b>255 then
                        b = 255
                    end if

                    *cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)'*cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
                   
                end if
               
                nu+=uinc
                nv+=vinc
                nz+=zinc
                nr+=rinc
                ng+=ginc
                nb+=binc

            next
           
           
        end if
       
        lx += xd2
        rx += xd3
        lu += ud2
        ru += ud3
        lv += vd2
        rv += vd3
        lz += zd2
        rz += zd3

        lr += rd2
        rr += rd3
        lg += gd2
        rg += gd3
        lb += bd2
        rb += bd3
    next
   
end sub
The Dr. is INsane!!!

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #1 on: January 25, 2010 »
Hi Dr_D,

I can't really see what your code is doing cos the forum has stuck it in a box the size of a postage stamp!  :-\

The idea of perspective correct mapping is you interpolate u/z, v/z and 1/z and for each pixel you divide the u/z by 1/z to get u, and v/z by 1/z to get v.

So there are a few things to check - make sure you are making u/z, v/z, 1/z properly at the corners and edges, and make sure all your increments have enough precision (floats should be ok).  If you can get that working then cool.

If you're still having trouble, let us know!

Jim
Challenge Trophies Won:

Offline Dr_D

  • Atari ST
  • ***
  • Posts: 151
  • Karma: 29
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #2 on: January 26, 2010 »
Thanks man... I actually had it working a while back, like shortly after fb first came around, but I've been through several computers and a hdd crash since then. This is good practice anyway. ;)
The Dr. is INsane!!!

Offline Dr_D

  • Atari ST
  • ***
  • Posts: 151
  • Karma: 29
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #3 on: February 24, 2010 »
I don't understand what's wrong here... Can anyone spot what the problem(s) might be? The interpolation across z, u and v is obviously wrong... Thanks again guys. :)

Code: [Select]
#include "fbgfx.bi"

type vec2f
as single x, y
end type

type vec3f
as single x, y, z
end type

type trgb
as uinteger r,g,b
end type

type tgpcTri_struct

dim as single x1, y1, z1
dim as single x2, y2, z2
dim as single x3, y3, z3
dim as single u1, v1
dim as single u2, v2
dim as single u3, v3
dim as fb.image ptr texture

end type


const as integer scr_w = 640
const as integer scr_h = 480

declare sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byref p1 as vec3f, byref t1 as vec2f, byref cl1 as trgb, byref p2 as vec3f, byref t2 as vec2f, byref cl2 as trgb, byref p3 as vec3f, byref t3 as vec2f, byref cl3 as trgb, byref texture as FB.IMAGE ptr )

screenres scr_w, scr_h, 32,,FB.GFX_HIGH_PRIORITY

dim as FB.IMAGE ptr image = imagecreate( 256, 256 )

if bload( "textures.bmp", image) <> 0 then
   
    line image,(0,0)-(255,255),&hffffffff, bf

    for i as integer = 0 to 255 step 16
'for x as integer = 0 to 255 step 16
line image,(0,i)-(255,i), &hff0000ff
            line image,(i,0)-(i,255), &hff0000ff
'next
next

end if




dim as vec3f p1, p2, p3, p4
dim as vec2f t1, t2, t3, t4
dim as trgb c1, c2, c3, c4

t1 = type( 0, 0 )
t2 = type( 0, 255 )
t3 = type( 255, 255 )
t4 = type( 255, 0 )

c1= type(0,0,0)
c2= type(0,0,0)
c3= type(0,0,0)
c4= type(0,0,0)

dim as tgpcTri_struct tri1, tri2
tri1.texture = image

dim as double otime = timer

do
dim as single ttime = 5.53

p1 = type( 320f+250f*sin(ttime),          240f+250f*cos(ttime), 1 )
p2 = type( 320f+250f*sin(ttime+1.5),      240f+250f*cos(ttime+1.5), 1 )
p3 = type( 320f+75f*sin(ttime+3.14),     240f+75f*cos(ttime+3.14), 10 )
p4 = type( 320f+75f*sin(ttime+3.14+1.5), 240f+75f*cos(ttime+3.14+1.5), 10 )


tri1.x1 = p1.x
tri1.x2 = p2.x
tri1.x3 = p3.x

tri1.y1 = p1.y
tri1.y2 = p2.y
tri1.y3 = p3.y

tri1.z1 = p1.z
tri1.z2 = p2.z
tri1.z3 = p3.z

tri1.u1 = t1.x
tri1.u2 = t2.x
tri1.u3 = t3.x

tri1.v1 = t1.y
tri1.v2 = t2.y
tri1.v3 = t3.y


tri2.x1 = p3.x
tri2.x2 = p4.x
tri2.x3 = p1.x

tri2.y1 = p3.y
tri2.y2 = p4.y
tri2.y3 = p1.y

tri2.z1 = p3.z
tri2.z2 = p4.z
tri2.z3 = p1.z

tri2.u1 = t3.x
tri2.u2 = t4.x
tri2.u3 = t1.x

tri2.v1 = t3.y
tri2.v2 = t4.y
tri2.v3 = t1.y



screenlock

line(0,0)-(640,480),0,bf

tgpctri(0, p1, t1, c1, p2, t2, c2, p3, t3, c3, image )
tgpctri(0, p3, t3, c3, p4, t4, c4, p1, t1, c1, image )

    locate 1,1
    print ttime
screensync

screenunlock

sleep 3,1

loop until inkey$ <> ""


sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byref p1 as vec3f, byref t1 as vec2f, byref cl1 as trgb, byref p2 as vec3f, byref t2 as vec2f, byref cl2 as trgb, byref p3 as vec3f, byref t3 as vec2f, byref cl3 as trgb, byref texture as FB.IMAGE ptr )

dim as integer x1, x2, x3
dim as integer y1, y2, y3
dim as single  z1, z2, z3
dim as single  u1, u2, u3
dim as single  v1, v2, v3
dim as integer r1, r2, r3
dim as integer g1, g2, g3
dim as integer b1, b2, b3

dim as uinteger ptr dstptr
dim as uinteger ptr srcptr
dim as integer dw,dh,dbpp,dpitch
dim as integer sw,sh,sbpp,spitch

dim as single scanlen
dim as integer pu, pv
dim as single dx1, dx2, dx3
dim as single dy1, dy2, dy3
dim as single dz1, dz2, dz3
dim as single du1, du2, du3
dim as single dv1, dv2, dv3
dim as single dr1, dr2, dr3
dim as single dg1, dg2, dg3
dim as single db1, db2, db3

dim as single sz, ez, su, eu, sv, ev, sr, er, sg, eg, sb, eb
dim as integer sx, ex

dim as single xd1, xd2, xd3, lx, rx
    dim as single recz

dim as single zd1, zd2, zd3, lz, rz, nz, zinc
dim as single ud1, ud2, ud3, lu, ru, nu, uinc
dim as single vd1, vd2, vd3, lv, rv, nv, vinc
dim as single rd1, rd2, rd3, lr, rr, nr, rinc
dim as single bd1, bd2, bd3, lb, rb, nb, binc
dim as single gd1, gd2, gd3, lg, rg, ng, ginc
dim as single idz1, idz2, idz3

dim as integer col
dim as integer r, g, b

if dst = 0 then
dstptr = screenptr
screeninfo dw, dh,, dbpp, dpitch
else
dstptr = cast (uinteger ptr, dst+1 )
dw = dst->width
dh = dst->height
dbpp = dst->bpp
dpitch = dst->pitch
end if

srcptr =  cast (uinteger ptr, texture+1 )
sw = texture->width
sh = texture->height
sbpp = texture->bpp
spitch = texture->pitch


x1 = int(p1.x)
x2 = int(p2.x)
x3 = int(p3.x)

y1 = int(p1.y)
y2 = int(p2.y)
y3 = int(p3.y)

z1 = p1.z
z2 = p2.z
z3 = p3.z

u1 = t1.x
u2 = t2.x
u3 = t3.x

v1 = t1.y
v2 = t2.y
v3 = t3.y

r1 = cl1.r
r2 = cl2.r
r3 = cl3.r

g1 = cl1.g
g2 = cl2.g
g3 = cl3.g

b1 = cl1.b
b2 = cl2.b
b3 = cl3.b


if y2 < y1 then
swap x1, x2
swap y1, y2
swap z1, z2
swap u1, u2
swap v1, v2
swap r1, r2
swap g1, g2
swap b1, b2
end if

if y3 < y1 then
swap x3, x1
swap y3, y1
swap z3, z1
swap u3, u1
swap v3, v1
swap r3, r1
swap g3, g1
swap b3, b1
end if

if y3 < y2 then
swap x3, x2
swap y3, y2
swap z3, z2
swap u3, u2
swap v3, v2
swap r3, r2
swap g3, g2
swap b3, b2
end if

idz1 = 1/z1
idz2 = 1/z2
idz3 = 1/z3

dx1 = x2 - x1
dy1 = y2 - y1
dz1 = idz2 - idz1 '((1/z2) - (1/z1))
du1 = (u2*idz2) - (u1*idz1)
dv1 = (v2*idz2) - (v1*idz1)
'dr1 = r2 - r1
'dg1 = g2 - g1
'db1 = b2 - b1
if dy1 <> 0 then
xd1 = dx1 / dy1
zd1 = dz1 / dy1
ud1 = du1 / dy1
vd1 = dv1 / dy1
'rd1 = dr1 / dy1
'gd1 = dg1 / dy1
'bd1 = db1 / dy1
else
xd1 = 0
zd1 = 0
ud1 = 0
vd1 = 0
'rd1 = 0
'gd1 = 0
'bd1 = 0
end if


dx2 = x3 - x2
dy2 = y3 - y2
dz2 = idz3-idz2 '((1/z3) - (1/z2))
du2 = (u3*idz3) - (u2*idz2)
dv2 = (v3*idz3) - (v2*idz2)
'dr2 = r3 - r2
'dg2 = g3 - g2
'db2 = b3 - b2
if dy2 <> 0 then
xd2 = dx2 / dy2
zd2 = dz2 / dy2
ud2 = du2 / dy2
vd2 = dv2 / dy2
'rd2 = dr2 / dy2
'gd2 = dg2 / dy2
'bd2 = db2 / dy2
else
xd2 = 0
zd2 = 0
ud2 = 0
vd2 = 0
'rd2 = 0
'gd2 = 0
'bd2 = 0
end if


dx3 = x1 - x3
dy3 = y1 - y3
dz3 = idz1-idz3'((1/z1) - (1/z3))
du3 = (u1*idz1) - (u3*idz3)
dv3 = (v1*idz1) - (v3*idz3)
'dr3 = r1 - r3
'dg3 = g1 - g3
'db3 = b1 - b3
if dy3 <> 0 then
xd3 = dx3 / dy3
zd3 = dz3 / dy3
ud3 = du3 / dy3
vd3 = dv3 / dy3
'rd3 = dr3 / dy3
'gd3 = dg3 / dy3
'bd3 = db3 / dy3
else
xd3 = 0
zd3 = 0
ud3 = 0
vd3 = 0
'rd3 = 0
'gd3 = 0
'bd3 = 0
end if

lx = x1
rx = x1
lz = idz1'1/z1
rz = idz1'1/z1
lu = u1*idz1'/z1
ru = u1*idz1'/z1
lv = v1*idz1'/z1
rv = v1*idz1'/z1

'lr = r1
'rr = r1
'lg = g1
'rg = g1
'lb = b1
'rb = b1

for y as integer = y1 to y2 - 1

if y>-1 and y<dh then

sx = lx
ex = rx
su = lu/lz
eu = ru/rz
sv = lv/lz
ev = rv/rz
sz = 1/lz
ez = 1/rz

'sr = lr
'er = rr
'sg = lg
'eg = rg
'sb = lb
'eb = rb

if sx>ex then
swap sx, ex
swap su, eu
swap sv, ev
swap sz, ez
'swap sr, er
'swap sg, eg
'swap sb, eb
end if

nz = 1/sz
nu = su*nz
nv = sv*nz
'nr = sr
'ng = sg
'nb = sb

scanlen = (ex-sx)'+1
uinc = ((eu/ez)-(su/sz)) / scanlen
vinc = ((ev/ez)-(sv/sz)) / scanlen
zinc = ((1/ez)-(1/sz)) / scanlen
'rinc = (er-sr) / scanlen
'ginc = (eg-sg) / scanlen
'binc = (eb-sb) / scanlen



for x as integer = sx to ex


if x>-1 and x<dw then

recz = 1/nz

pu = abs(nu*recz)' MOD sw
pv = abs(nv*recz)' MOD sh
col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
                    'col = point(pu, pv,texture)
r = (col shr 16) and 255
g = (col shr 8) and 255
b = (col)  and 255

*cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)
                    'pset(x,y),rgb(r,g,b)

end if

nu+=uinc
nv+=vinc
nz+=zinc
'nr+=rinc
'ng+=ginc
'nb+=binc

next

end if

lx += xd1
rx += xd3
lu += ud1
ru += ud3
lv += vd1
rv += vd3
lz += zd1
rz += zd3

'lr += rd1
'rr += rd3
'lg += gd1
'rg += gd3
'lb += bd1
'rb += bd3

next


lx = x2
lz = idz2 '1/z2

lu = u2*idz2'/z2

lv = v2*idz2'/z2

'lr = r2
'lg = g2
'lb = b2


'exit sub

for y as integer = y2 to y3

if y>-1 and y<dh then

sx = lx
ex = rx
sz = 1/lz
ez = 1/rz
su = lu/lz
eu = ru/rz
sv = lv/lz
ev = rv/rz


'sr = lr
'er = rr
'sg = lg
'eg = rg
'sb = lb
'eb = rb

if sx>ex then
swap sx, ex
swap su, eu
swap sv, ev
swap sz, ez
'swap sr, er
'swap sg, eg
'swap sb, eb
end if

nz = 1/sz
nu = su*nz
nv = sv*nz
'nr = sr
'ng = sg
'nb = sb

scanlen = (ex-sx)'+1
uinc = ((eu/ez)-(su/sz)) / scanlen
vinc = ((ev/ez)-(sv/sz)) / scanlen
zinc = ((1/ez)-(1/sz)) / scanlen
'rinc = (er-sr) / scanlen
'ginc = (eg-sg) / scanlen
'binc = (eb-sb) / scanlen


for x as integer = sx to ex

if x>-1 and x<dw then

recz = 1/nz

pu = abs(nu*recz)' MOD sw
pv = abs(nv*recz)' MOD sh

col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
                    'col = point(pu, pv,texture)
r = (col shr 16) and 255
g = (col shr 8) and 255
b = (col)  and 255

*cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)'*cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
                    'pset(x,y),rgb(r,g,b)

end if

nu+=uinc
nv+=vinc
nz+=zinc
'nr+=rinc
'ng+=ginc
'nb+=binc

next


end if

lx += xd2
rx += xd3
lu += ud2
ru += ud3
lv += vd2
rv += vd3
lz += zd2
rz += zd3

'lr += rd2
'rr += rd3
'lg += gd2
'rg += gd3
'lb += bd2
'rb += bd3
next

end sub




The Dr. is INsane!!!

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #4 on: February 24, 2010 »
It looks like you're making this way too complicated, you've got far too many divide by z going on. I take it you've got affine mapping working so go back to that and use that as a starting point.

You only need to divide u and v by z and divide 1 by z for each vertex right at the start of your tri sub.

Then inside your inner loop you multiply the interpolated u/z and v/z values by the reciprocal of the interpolated 1/z value.

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: Perspective correct texture mapping problems...
« Reply #5 on: February 24, 2010 »
A general suggestion:

Use a single structure holding all vertex-attributes:
Code: [Select]
type Vertex
   as single x, y, z
   as single u, v
end type

Send pointers of vertices to your triangle-filler.
When swapping two vertices you can simply swap their pointers instead of actually moving data around:
Code: [Select]
if v2->y < v1->y then
  swap v1, v2
end if

If your triangles have constant winding you can even send a list of vertex-pointers.
Now just find the index of the topmost vertex from the list.
All bigger indices are on the left side of the triangle and the smaller indices on the right.
There's no reason to swap anything.
Challenge Trophies Won:

Offline Dr_D

  • Atari ST
  • ***
  • Posts: 151
  • Karma: 29
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #6 on: February 24, 2010 »
Thanks for the suggestions. This is all based off code from relsoft's tutorial, but I haven't been able to get the perspective mapping to work properly. I'm going to try again and again until i get it right. ;)
The Dr. is INsane!!!

Offline Dr_D

  • Atari ST
  • ***
  • Posts: 151
  • Karma: 29
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #7 on: February 25, 2010 »
Sorry to reply again so soon... I'm really not trying to drive you guys nuts. :p Anyway, I really don't understand what I'm doing wrong though... I removed the tries for color interpolation for now, and cleaned it up a bit because if I can get the perspective texture correction down, the colors will be easy using the same method. Also, I renamed a few vars to something more understandable. If I read everything I've looked at right, this should be working... so I must not have read it right. Thanks for taking time to look at it. :)


Code: [Select]
#include "fbgfx.bi"

type vec2f
as single x, y
end type

type vec3f
as single x, y, z
end type

type trgb
as uinteger r,g,b
end type

type tgpcTri_struct

dim as single x1, y1, z1
dim as single x2, y2, z2
dim as single x3, y3, z3
dim as single u1, v1
dim as single u2, v2
dim as single u3, v3
dim as fb.image ptr texture

end type


const as integer scr_w = 640
const as integer scr_h = 480

declare sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byref p1 as vec3f, byref t1 as vec2f, byref cl1 as trgb, byref p2 as vec3f, byref t2 as vec2f, byref cl2 as trgb, byref p3 as vec3f, byref t3 as vec2f, byref cl3 as trgb, byref texture as FB.IMAGE ptr )

screenres scr_w, scr_h, 32,,FB.GFX_HIGH_PRIORITY

dim as FB.IMAGE ptr image = imagecreate( 256, 256 )

if bload( "texture.bmp", image) <> 0 then
   
    line image,(0,0)-(255,255),&hffffffff, bf

    for i as integer = 0 to 255 step 16
line image,(0,i)-(255,i), &hff0000ff
        line image,(i,0)-(i,255), &hff0000ff
next

end if




dim as vec3f p1, p2, p3, p4
dim as vec2f t1, t2, t3, t4
dim as trgb c1, c2, c3, c4

t1 = type( 0, 0 )
t2 = type( 0, 255 )
t3 = type( 255, 255 )
t4 = type( 255, 0 )

c1= type(0,0,0)
c2= type(0,0,0)
c3= type(0,0,0)
c4= type(0,0,0)

dim as tgpcTri_struct tri1, tri2
tri1.texture = image

dim as double otime = timer

do
dim as single ttime = 5.53

p1 = type( 320f+250f*sin(ttime),          240f+250f*cos(ttime), 1 )
p2 = type( 320f+250f*sin(ttime+1.5),      240f+250f*cos(ttime+1.5), 1 )
p3 = type( 320f+75f*sin(ttime+3.14),     240f+75f*cos(ttime+3.14), 10 )
p4 = type( 320f+75f*sin(ttime+3.14+1.5), 240f+75f*cos(ttime+3.14+1.5), 10 )


tri1.x1 = p1.x
tri1.x2 = p2.x
tri1.x3 = p3.x

tri1.y1 = p1.y
tri1.y2 = p2.y
tri1.y3 = p3.y

tri1.z1 = p1.z
tri1.z2 = p2.z
tri1.z3 = p3.z

tri1.u1 = t1.x
tri1.u2 = t2.x
tri1.u3 = t3.x

tri1.v1 = t1.y
tri1.v2 = t2.y
tri1.v3 = t3.y


tri2.x1 = p3.x
tri2.x2 = p4.x
tri2.x3 = p1.x

tri2.y1 = p3.y
tri2.y2 = p4.y
tri2.y3 = p1.y

tri2.z1 = p3.z
tri2.z2 = p4.z
tri2.z3 = p1.z

tri2.u1 = t3.x
tri2.u2 = t4.x
tri2.u3 = t1.x

tri2.v1 = t3.y
tri2.v2 = t4.y
tri2.v3 = t1.y



screenlock

line(0,0)-(640,480),0,bf

tgpctri(0, p1, t1, c1, p2, t2, c2, p3, t3, c3, image )
tgpctri(0, p3, t3, c3, p4, t4, c4, p1, t1, c1, image )

screensync

screenunlock

sleep 3,1

loop until inkey$ <> ""


sub tgpcTri ( byref dst as FB.IMAGE ptr = 0, byref p1 as vec3f, byref t1 as vec2f, byref cl1 as trgb, byref p2 as vec3f, byref t2 as vec2f, byref cl2 as trgb, byref p3 as vec3f, byref t3 as vec2f, byref cl3 as trgb, byref texture as FB.IMAGE ptr )

dim as integer x1, x2, x3
dim as integer y1, y2, y3
dim as single  z1, z2, z3
dim as single  u1, u2, u3
dim as single  v1, v2, v3

dim as uinteger ptr dstptr
dim as uinteger ptr srcptr
dim as integer dw,dh,dbpp,dpitch
dim as integer sw,sh,sbpp,spitch

dim as integer scanlen
dim as integer pu, pv
dim as single xlen1, xlen2, xlen3
dim as single ylen1, ylen2, ylen3
dim as single zlen1, zlen2, zlen3
dim as single ulen1, ulen2, ulen3
dim as single vlen1, vlen2, vlen3

dim as single sz, ez, su, eu, sv, ev
dim as integer sx, ex

dim as single xd1, xd2, xd3, lx, rx
    dim as single recz

dim as single zd1, zd2, zd3, lz, rz, nz, zinc
dim as single ud1, ud2, ud3, lu, ru, nu, uinc
dim as single vd1, vd2, vd3, lv, rv, nv, vinc


    'reciprocal variables
    dim as single u1dz1, u2dz2, u3dz3
    dim as single v1dz1, v2dz2, v3dz3
dim as single idz1, idz2, idz3

dim as integer col
dim as integer r, g, b

if dst = 0 then
dstptr = screenptr
screeninfo dw, dh,, dbpp, dpitch
else
dstptr = cast (uinteger ptr, dst+1 )
dw = dst->width
dh = dst->height
dbpp = dst->bpp
dpitch = dst->pitch
end if

srcptr =  cast (uinteger ptr, texture+1 )
sw = texture->width
sh = texture->height
sbpp = texture->bpp
spitch = texture->pitch

    'assign vertices and uv coordinates to temp variables
x1 = int(p1.x)
x2 = int(p2.x)
x3 = int(p3.x)

y1 = int(p1.y)
y2 = int(p2.y)
y3 = int(p3.y)

z1 = p1.z
z2 = p2.z
z3 = p3.z

u1 = t1.x
u2 = t2.x
u3 = t3.x

v1 = t1.y
v2 = t2.y
v3 = t3.y

if y2 < y1 then
swap x1, x2
swap y1, y2
swap z1, z2
swap u1, u2
swap v1, v2
end if

if y3 < y1 then
swap x3, x1
swap y3, y1
swap z3, z1
swap u3, u1
swap v3, v1
end if

if y3 < y2 then
swap x3, x2
swap y3, y2
swap z3, z2
swap u3, u2
swap v3, v2
end if
   
    'reciprocals for each z... trying to speed it up a bit without confusing myself any more
idz1 = 1/z1
idz2 = 1/z2
idz3 = 1/z3
   
    'uv's divided by z
    u1dz1 = u1/z1
    u2dz2 = u2/z2
    u3dz3 = u3/z3

    v1dz1 = v1/z1
    v2dz2 = v2/z2
    v3dz3 = v3/z3


    'calculate the interpolation for the top left leg
    'of course the actual loops will change on flat bottom || top triangles
    'i think that's my problem with this whole method

xlen1 = x2 - x1
ylen1 = y2 - y1
zlen1 = idz2 - idz1
ulen1 = u2dz2 - u1dz1
vlen1 = v2dz2 - v1dz1
   
if ylen1 <> 0 then

xd1 = xlen1 / ylen1
zd1 = zlen1 / ylen1
ud1 = ulen1 / ylen1
vd1 = vlen1 / ylen1

else

xd1 = 0
zd1 = 0
ud1 = 0
vd1 = 0

end if


    'calculate the interpolation for the right leg
xlen2 = x3 - x2
ylen2 = y3 - y2
zlen2 = idz3 - idz2
ulen2 = u3dz3 - u2dz2
vlen2 = v3dz3 - v2dz2

if ylen2 <> 0 then

xd2 = xlen2 / ylen2
zd2 = zlen2 / ylen2
ud2 = ulen2 / ylen2
vd2 = vlen2 / ylen2

else

xd2 = 0
zd2 = 0
ud2 = 0
vd2 = 0

end if

   
    'calculate the interpolation for the bottom left leg
xlen3 = x1 - x3
ylen3 = y1 - y3
zlen3 = idz1 - idz3
ulen3 = u1dz1 - u3dz3
vlen3 = v1dz1 - v3dz3

if ylen3 <> 0 then

xd3 = xlen3 / ylen3
zd3 = zlen3 / ylen3
ud3 = ulen3 / ylen3
vd3 = vlen3 / ylen3

else

xd3 = 0
zd3 = 0
ud3 = 0
vd3 = 0

end if

   
    'enter the actual rendering loops finally...
    'everything starts at pointA, the top(and left) of the triangle
lx = x1
rx = x1
lz = idz1
rz = idz1
lu = u1dz1
ru = u1dz1
lv = v1dz1
rv = v1dz1

for y as integer = y1 to y2 - 1

if y>-1 and y<dh then

sx = lx
ex = rx
su = lu
eu = ru
sv = lv
ev = rv
sz = lz
ez = rz

if sx>ex then
swap sx, ex
swap su, eu
swap sv, ev
swap sz, ez
end if

nz = sz
nu = su
nv = sv

scanlen = ex-sx
uinc = (eu-su) / scanlen
vinc = (ev-sv) / scanlen
zinc = (ez-sz) / scanlen

for x as integer = sx to ex

if x>-1 and x<dw then
                   
recz = 1/nz
pu = abs(nu*recz)
pv = abs(nv*recz)

'col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
                    col = point(pu, pv,texture)
r = (col shr 16) and 255
g = (col shr 8) and 255
b = (col)  and 255

'*cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)
                    pset(x,y),rgb(r,g,b)

end if

nu+=uinc
nv+=vinc
nz+=zinc

next

end if

lx += xd1
rx += xd3
lu += ud1
ru += ud3
lv += vd1
rv += vd3
lz += zd1
rz += zd3

next


    'bottom half
    'set the left side to pointB
lx = x2
lz = idz2
lu = u2dz2
lv = v2dz2

for y as integer = y2 to y3

if y>-1 and y<dh then

sx = lx
ex = rx
sz = lz
ez = rz
su = lu
eu = ru
sv = lv
ev = rv

if sx>ex then
swap sx, ex
swap su, eu
swap sv, ev
swap sz, ez
end if

nz = sz
nu = su
nv = sv

scanlen = ex-sx
uinc = (eu-su) / scanlen
vinc = (ev-sv) / scanlen
zinc = (ez-sz) / scanlen

for x as integer = sx to ex

if x>-1 and x<dw then

recz = 1/nz

pu = abs(nu*recz)
pv = abs(nv*recz)

'col = *cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
                    col = point(pu, pv,texture)
r = (col shr 16) and 255
g = (col shr 8) and 255
b = (col)  and 255

'*cast(uinteger ptr, cast( ubyte ptr, dstptr) + y * dpitch + x * dbpp ) = rgb(r,g,b)'*cast(uinteger ptr, cast( ubyte ptr, srcptr) + pv * spitch + pu * sbpp )
                    pset(x,y),rgb(r,g,b)

end if

nu+=uinc
nv+=vinc
nz+=zinc

next

end if

lx += xd2
rx += xd3
lu += ud2
ru += ud3
lv += vd2
rv += vd3
lz += zd2
rz += zd3

next

end sub
The Dr. is INsane!!!

Offline Dr_D

  • Atari ST
  • ***
  • Posts: 151
  • Karma: 29
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #8 on: February 25, 2010 »
lol, n/m... that last one works. sorry guys, i found my mistake now. it can't just accept a random value for z, it actually needs the correct projection values.  :updance:
The Dr. is INsane!!!

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #9 on: February 25, 2010 »
I take it you're using abs to stop your tex coords going out of range, there is a better way that also allows for texture wrapping.

Hint: It requires the texture sizes to be powers of 2.

Offline Dr_D

  • Atari ST
  • ***
  • Posts: 151
  • Karma: 29
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #10 on: February 25, 2010 »
Heh, yeah, I started AND'ing the coords instead. :p to make it compatible with what i want to use it for, it' sgoping to  have to work with negative coordinates as well, without mirroring it. That doesn't really matter right now though. I want to figure out how sub-pixel/texel rendering works next. I've read a few docs, but the method just hasn't sunk in yet I guess.
The Dr. is INsane!!!

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #11 on: February 25, 2010 »
ANDing deals with negative values fine.

Sub pixel, just realise that the first pixel of your scanline is often not actually the start of your scanline, there is a small fraction of a pixel before it that you're missing out and therefore a small part of your texture is missed out too, that goes for the end of the scanline and also for the top and bottom of your triangles.

Make sure you understand your filling convention too, along with how the floats are being rounded for the start and end of inner and outer loops and for tex coords inside the inner loop.

And have a think about your deltas.

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #12 on: February 28, 2010 »
Truncating all your x,y floats towards 0 when rendering is enough to ensure you never get cracking, though Stonemonkey is bang on to say that that's not perfect - it's very good though.  There's no need to perspective correct your r,g,b imho, there's enough error in the fact your using Gouraud and the RGB colour-space to make it irrelevant, just perspective correct the u,v, which is really important.

Jim
Challenge Trophies Won:

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: Perspective correct texture mapping problems...
« Reply #13 on: February 28, 2010 »
I want to figure out how sub-pixel/texel rendering works next. I've read a few docs, but the method just hasn't sunk in yet I guess.
I once posted an image here which shows the gaps between the interpolated edges and the drawn pixels.
It assumes rounding floating-point coordinates to next bigger integers.
Challenge Trophies Won:

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #14 on: March 01, 2010 »
I want to figure out how sub-pixel/texel rendering works next. I've read a few docs, but the method just hasn't sunk in yet I guess.
I once posted an image here which shows the gaps between the interpolated edges and the drawn pixels.
It assumes rounding floating-point coordinates to next bigger integers.
Good pic, I tend to round down but whichever way you decide to go, pick a point on the pixel and use that to determiine if a pixel is inside or outside the triangle, don't use the whole pixel area.

It's also possible to set the rounding mode of the CPU  in freebasic with a bit of inline asm. I found that handy since the rounding standard of NEAREST but xx.5 is rounded up or down depending on whether xx is even or odd to be a bit of a pain.

Offline Dr_D

  • Atari ST
  • ***
  • Posts: 151
  • Karma: 29
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #15 on: March 02, 2010 »
well, i've been testing a bit more, but it's still misfiring. i've been trying to follow this tutorial, but it doesn't seem to be very thorough. it seems like it's close at times, but then you can see how it goes wild. if anyone could steer my nose the proper way i'd appreciate it. thanks. ;)



Code: [Select]
#include "fbgfx.bi"

type vec2f
as single x, y
declare constructor()
declare constructor( byval x as single, byval y as single )
declare sub rotate( byval rad as single )
declare sub translate( byval x as single, byval y as single )
end type


declare sub Triangle( byref dst as FB.IMAGE ptr = 0, byref p1 as vec2f, byref p2 as vec2f, byref p3 as vec2f, byval col as uinteger )
declare sub bpset( byval x as integer, byval y as integer, byval col as uinteger )

const as integer sw = 1024
const as integer sh = 768
const as integer pix_size = 10
const as integer tri_size = 128\pix_size
const as integer swc = (sw\pix_size)\2, shc = (sh\pix_size)\2

screenres sw,sh,32



dim as double ttime = timer
dim as single rad

do

ttime = timer
rad = sin(ttime/10)

dim as vec2f p1, p2, p3

p1.translate(-tri_size, tri_size)
p2.translate(-tri_size, -tri_size)
p3.translate(tri_size,-tri_size)

p1.rotate(rad)
p2.rotate(rad)
p3.rotate(rad)

p1.translate(swc,shc)
p2.translate(swc,shc)
p3.translate(swc,shc)


screenlock
cls

for y as integer = 0 to shc*2
for x as integer = 0 to swc*2
line(x*pix_size, y*pix_size)-step(pix_size-1, pix_size-1),&hff333333,b
next
next

   triangle( 0, p1, p2, p3, &hff0000ff )

screensync
screenunlock

sleep 3,1

loop until multikey(FB.SC_ESCAPE)



constructor vec2f()
end constructor

constructor vec2f( byval x as single, byval y as single )
this.x = x
this.y = y
end constructor

sub vec2f.rotate( byval rad as single )
dim as vec2f t
t.x = this.x * cos(rad) - this.y * sin(rad)
t.y = this.y * cos(rad) + this.x * sin(rad)
this = t
end sub

sub vec2f.translate( byval x as single, byval y as single )
this.x += x
this.y += y
end sub


function sub_pix( byval inval as single ) as single

dim as single retval
dim as const single  half = 0.5

asm
  fld dword ptr[inval]
  fld dword ptr[inval]
  fsub dword ptr [half]
  frndint
  fsubp   st(1), st
  fld1
  fsubrp  st(1), st
  fstp dword ptr[retval]
end asm

return retval

end function


sub Triangle( byref dst as FB.IMAGE ptr = 0, byref p1 as vec2f, byref p2 as vec2f, byref p3 as vec2f, byval col as uinteger )

dim as uinteger ptr dstptr, dptr1
dim as integer x,y
dim as integer dw,dh, dpitch, dbpp
dim as single dx1,dx2,dx3,dy1,dy2,dy3,sx,ex
dim as single d1, d2, d3, lx, rx

if dst = 0 then
dstptr = screenptr
screeninfo dw,dh,,dbpp, dpitch
else
dstptr = cast( uinteger ptr, dst + 1)
dw = dst->width
dh = dst->height
dbpp = dst->bpp
dpitch = dst->pitch
end if

'reverse for normal coordinate system
dim as single y1 = (dh\pix_size) - p1.y
dim as single y2 = (dh\pix_size) - p2.y
dim as single y3 = (dh\pix_size) - p3.y

dim as single x1 = p1.x
dim as single x2 = p2.x
dim as single x3 = p3.x

if y2 < y1 then
swap y1, y2
swap x1, x2
end if

if y3 < y1 then
swap y3, y1
swap x3, x1
end if

if y3 < y2 then
swap y3, y2
swap x3, x2
end if

dx1 = x2 - x1
dy1 = y2 - y1
if dy1 <> 0 then
d1 = dx1 / dy1
else
d1 = 0
end if

dx2 = x3 - x2
dy2 = y3 - y2
if dy2 <> 0 then
d2 = dx2 / dy2
else
d2 = 0
end if

dx3 = x1 - x3
dy3 = y1 - y3
if dy3 <> 0 then
d3 = dx3 / dy3
else
d3 = 0
end if

'lx = x1
'rx = x1
lx = x1' + (d1*sub_pix(y1))
rx = x1' + (d3*sub_pix(y3))
y = y1

while y<y2

if y>-1 and y<dh then

sx = lx + (d1*sub_pix(y1))
ex = rx + (d3*sub_pix(y3))

if sx>ex then
swap sx,ex
end if

if sx<0 then
sx = 0
end if

if ex>dw-1 then
ex=dw-1
end if

x = sx
'dptr1 = cast(uinteger ptr, cast(ubyte ptr, dstptr) + y * dpitch + x * dbpp)

while x<ex

'*dptr1 = col
'dptr1+=1
line(x*pix_size,y*pix_size)-step(pix_size-1,pix_size-1),col,bf
x+=1

wend

end if

lx += d1
rx += d3
y+=1

wend


lx = x2 + (d2*sub_pix(y2))
'rx = constant slope
y = y2

while y<=y3

if y>-1 and y<dh then

sx = lx + (d2*sub_pix(y2))
ex = rx + (d3*sub_pix(y3))

if sx>ex then
swap sx,ex
end if

if sx<0 then
sx = 0
end if

if ex>dw-1 then
ex=dw-1
end if

x = sx
'dptr1 = cast(uinteger ptr, cast(ubyte ptr, dstptr) + y * dpitch + x * dbpp)

while x<ex

'*dptr1 = col
'dptr1+=1
line(x*pix_size,y*pix_size)-step(pix_size-1,pix_size-1),col,bf
x+=1

wend

end if

lx += d2
rx += d3
y+=1

wend

end sub

The Dr. is INsane!!!

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: Perspective correct texture mapping problems...
« Reply #16 on: March 02, 2010 »
Quote
Code: [Select]
   y = y1
   while y<y2
       sx = lx + (d1*sub_pix(y1))
       ex = rx + (d3*sub_pix(y3))
You're now re-applying the subpixel correction every scanline.
You just have to do it once to compensate the gap between "y1" and "y" (and again for the other edge when y reaches y2).
What you do every scanline is the texel-correction to compensate the gap between "sx" and "lx":
Code: [Select]
fracX= sub_pix(leftX);
u = leftU + (deltaU * fracX);
v = leftV + (deltaV * fracX);
(deltaU and deltaV are the deltas across the scanline)
Challenge Trophies Won:

Offline Dr_D

  • Atari ST
  • ***
  • Posts: 151
  • Karma: 29
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #17 on: March 02, 2010 »
well, i was doing the calculations right before the scanline loops start, one for lx and rx at the top loop, and one only for lx at the bottom loop, but it still didn't seem to work. the code here is just posting it out of frustration after testing several different methods. :\
The Dr. is INsane!!!

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: Perspective correct texture mapping problems...
« Reply #18 on: March 03, 2010 »
Here's a small excerpt from an affine texture-mapper I wrote in C somewhen in the mid 90's.
Input for the polyfiller is an array of vertices:
Code: [Select]
struct Vertex
{
  float x,y;
  float u,v;
};
You would typically work with fixed-point coordinates in screen-space but the code looks a bit less obscure with floats.

Starting at the top-most vertex "topVtx" I track along the left and right edge.
Since all polygons are defined in counter-clockwise order, topVtx[1] is to the left and topVtx[-1] is to the right.
Imagine some additional code to make sure that vertices [-1] and [+1] actually exist.
ceil() rounds to the next bigger integer but can be replaced with any other rounding-function.

Left side:
Code: [Select]
leftVtx  = topVtx;

// deltas along left edge
invHeight= 1.0 / (leftVtx[1].y - leftVtx[0].y);
leftDx = (leftVtx[1].x - leftVtx[0].x) * invHeight;
leftDu = (leftVtx[1].u - leftVtx[0].u) * invHeight;
leftDv = (leftVtx[1].v - leftVtx[0].v) * invHeight;

// subpixel correction
// this is the difference between the vertex' y-coordinate and the integer scanline
diffY = ceil(leftVtx[0].y) - leftVtx[0].y;
leftX = leftVtx[0].x + diffY * leftDx;
leftU = leftVtx[0].u + diffY * leftDu;
leftV = leftVtx[0].v + diffY * leftDv;

// proceed to next edge
leftVtx++;
(you can skip this calculation if both vertices are in the same scanline)

The same is done for the right edge but as the deltas across the scanline are constant, you just need to keep track of the x-position:
Code: [Select]
rightVtx  = topVtx;

invHeight= 1.0 / (rightVtx[-1].y - rightVtx[0].y);
rightDx = (rightVtx[-1].x - rightVtx[0].x) * invHeight;

diffY = ceil(rightVtx[0].y) - rightVtx[0].y;
rightX = rightVtx[0].x + diffY * rightDx;

rightVtx++;

Now draw vertical scanlines until either rightVtx.y or leftVtx.y is reached.
Here each scanline has an interpolated floating-point starting-position so the difference between leftX and the integer pixel position needs to be fixed:
Code: [Select]
// integer pixel-positions of scanline-start and -end
x1 = ceil(leftX);
x2 = ceil(rightX);

// subtexel correction
diffX = x1 - leftX;
u = leftU + diffX * deltaU;
v = leftV + diffX * deltaV;

// fill scanline
for (x=x1; x<x2; x++)
{
  ...
}

Afterwards keep track of the edges:
Code: [Select]
// left side
leftX += leftDx;
leftU += leftDu;
leftV += leftDv;

// right side
rightX += rightDx;

As I process clipped polygons (resulting in arbitrary convex polygons) I don't use the typical top-half/bottom-half triangle approach but recalculate the deltas for left and right on-the-fly whenever the scanline-counter reaches one of them.
« Last Edit: March 03, 2010 by hellfire »
Challenge Trophies Won:

Offline Dr_D

  • Atari ST
  • ***
  • Posts: 151
  • Karma: 29
    • View Profile
Re: Perspective correct texture mapping problems...
« Reply #19 on: March 04, 2010 »
Man, this is crazy... Mine still doesn't work properly. I understand what's going on, or so I think, but it makes no sense for it to do this... it almost works, damn it. Can you see what's going on? I even switched to use reciprocals for the slope calculations, as yours does. It wont matter right now, but it's a nice optimization for the one with actual texturing and shading. Thanks again for the help. ;)


Code: [Select]
function sub_pix( byval inval as single ) as single

return 1f - (ceil(inval) - inval)

end function


sub triangle( byref dst as FB.IMAGE ptr = 0, byref p1 as vec2f, byref p2 as vec2f, byref p3 as vec2f, byval col as uinteger )

dim as uinteger ptr dstptr, dptr1
dim as integer sx, ex
dim as integer dw,dh, dpitch, dbpp
dim as single d1, d2, d3, lx, rx, invheight

if dst = 0 then
dstptr = screenptr
screeninfo dw,dh,,dbpp, dpitch
else
dstptr = cast( uinteger ptr, dst + 1)
dw = dst->width
dh = dst->height
dbpp = dst->bpp
dpitch = dst->pitch
end if

'reverse for normal coordinate system
dim as single y1 = (dh\pix_size) - p1.y
dim as single y2 = (dh\pix_size) - p2.y
dim as single y3 = (dh\pix_size) - p3.y

dim as single x1 = p1.x
dim as single x2 = p2.x
dim as single x3 = p3.x

if y2 < y1 then
swap y1, y2
swap x1, x2
end if

if y3 < y1 then
swap y3, y1
swap x3, x1
end if

if y3 < y2 then
swap y3, y2
swap x3, x2
end if

if y2>y1 then
invheight = 1f/(y2-y1)
else
invheight = 1f
end if
d1 = (x2 - x1) * invheight

if y3<>y2 then
invheight = 1f/(y3-y2)
else
invheight = 1f
end if
d2 = (x3 - x2) * invheight

if y1<>y3 then
invheight = 1f/(y1-y3)
else
invheight = 1f
end if
d3 = (x1 - x3) * invheight

lx = x1 + (d1*sub_pix(y1))
rx = x1 + (d3*sub_pix(y3))


locate 1,1
print d1, d1, d3

for y as integer = y1 to y2-1

if y>-1 and y<dh then

sx = ceil(lx)
ex = ceil(rx)

if sx>ex then
swap sx,ex
end if

if sx<0 then
sx = 0
end if

if ex>dw-1 then
ex=dw-1
end if

dptr1 = cast(uinteger ptr, cast(ubyte ptr, dstptr) + y * dpitch + sx * dbpp)

for x as integer = sx to ex

'*dptr1 = col
dptr1+=1
line(x*pix_size,y*pix_size)-step(pix_size-1,pix_size-1),col,bf

next

end if

lx += d1
rx += d3
'y+=1

next


lx = x2 + (d2*sub_pix(y2))
'rx = constant slope

for y as integer = y2 to y3

if y>-1 and y<dh then

sx = ceil(lx)
ex = ceil(rx)

if sx>ex then
swap sx,ex
end if

if sx<0 then
sx = 0
end if

if ex>dw-1 then
ex=dw-1
end if

'x = sx
dptr1 = cast(uinteger ptr, cast(ubyte ptr, dstptr) + y * dpitch + sx * dbpp)

for x as integer = sx to ex

'*dptr1 = col
dptr1+=1
line(x*pix_size,y*pix_size)-step(pix_size-1,pix_size-1),col,bf

next

end if

lx += d2
rx += d3

next

end sub
The Dr. is INsane!!!