home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Enigma Amiga Life 109
/
EnigmaAmiga109CD.iso
/
software
/
testi
/
corsoasm
/
sorgenti_3d
/
texture_wasb.txt
< prev
next >
Wrap
Text File
|
1998-03-18
|
8KB
|
228 lines
HAHAAA!! Non avrei mai pensato che avrei scritto un doc sul tmap; ce ne sono
così tanti su internet; se ne vuoi prendere uno interessante vai su
www.altavista.digital.com e ricerca "texture mapping" (rigorosamente con le
<">) e dovresti trovare un file di ~63k; prendilo è molto interessante
perchè spiega le basi; per il resto dovresti avere tutto quello che ti serve
:-)
Innanzitutto ce l'hai una routine di scanline? Se non ce l'hai leggi
qua altrimenti salta direttamente a dopo.
*** Scanline ***
Che cos'è una routine di scanline?
Dato che lo schermo è fatto di linee quando si deve riempire un poligono (di
qualsiasi forma), tale poligono deve essere "convertito" in linee
orizzontali in modo da riempire solo linee sullo schermo. Per esempio
un triangolo così verrà convertito in linee orizzontali
. .
/ \ --\ ...
/ \ --/ .....
/ \ .......
¯¯¯¯¯¯¯
Quindi per fillare un poligono bisogna sapere di quante linee orizzontali è
formato, più gli estremi delle linee. Per fare questo in genere si usano due
tabelle grandi quanto la lunghezza in linee dello schermo; una contiene gli
estremi di destra delle linee e l'altra per quelli di sinistra.
A questo punto ti starai chiedendo come fare le tabelle no? Bene è tutto
molto semplice, non devi far altro che interpolare la coordinata x lungo la
y (a me hanno consigliato di non usare l'algoritmo di bresenham perchè
quello normale di interpolazione è leggermente più veloce).
Allora riprendiamo il triangolo (considerando i vertici)
1->. p1=(25,0)
/ \ p2=(0,25)
/ \ p3=(50,25)
2->/ \<-3
¯¯¯¯¯¯¯
quindi nelle tabelle dovrai avere qualcosa così:
tab1 tab2 per fare le tabelle si fa ± così:
0 25 25
1 24 26 dx=(p2.x-p1.x)/(p2.y-p1.y)
2 23 27 poi
3 22 28 x=p1.x;
4 21 29 for y=p1.y to p2.y
5 20 30 if tab1[y]<>0 then tab1[y]=x else tab2[y]=p1.x
6 19 31 x=x+dx
: : : next
: : :
23 2 48
24 1 49
25 0 50
:
:
(altri valori che non c'interessano)
ci 6? A questo punto ti fai un ciclo che per ogni valore di y vede se c'e' da
tracciare una linea orizzontale (ovvero se tab1[y] e tab2[y] sono diversi
da 0) così hai gli estremi della linea e la sua coordinata y.
Nell'esempio fai un ciclo tipo:
for y=0 to 50
line (tab1[y],y,tab2[y],y)
next
ed è fatto! Hai riempito un triangolo1! :-))
Spero di essere stato abbastanza semplice nella spiegazione :-)
*** Texture Mapping ***
Allora cos'è il texture mapping? Non si tratta altro che riempire un
poligono invece di usare sempre lo stesso colore, una serie di colori presi
da un'altra immagine. Il problema sta nel prendere i colori nell'ordine
giusto e per questo ci sono vari algoritmi:
1) polygon grandients: calcola dei valori (tratti da alcuni calcoli
vettoriali) e li usa per calcolare il colore del pixel con le formule
u=k1+a/c
v=k2+b/c
colore = txt[u,v] -> abituati xchè le coordinate sulla texture sono
sempre individuate dalle variabili u,v :)
Questo è il metodo di texturare i poligoni in 3d; bel senso che la
texture viene vista come un piano 3d; è il metodo "perspective
correction" che (penso) venga usato negli acceleratori 3d via hardware :)
farlo via software è lentissimo!!
2) due div per scanline: calcola le u,v agli estremi della scanline (come
nella scanline, solo che invece di interpolare solo la x, qui si
interpolano anche le u,v sui lato del poligono) e poi si interpolano le
u,v lungo la scanline:
u=u0+du*(x-x0)
v=v0+dv*(x-x0)
dove
u0=u all'inizio della scanline u1=u alla fine
v0=v """"""""""""""""""""""" v1=v " "
du=(u1-u0)/(tab2[y]-tab1[y])
dv=(v1-v0)/ """"""""""""""
x-x0=differenza tra la x corrente (x) e la x all'inizio della scanline
>>>Funziona con qualsiasi poligono
3) due div per poligono: calcola gli incrementi dv/dx e du/dx per l'intero
poligono e le usa per interpolare le coordinate:
u=u0+du*(x-x0)
v=v0+dv*(x-x0)
du=(u1-u0)/(lunghezza della massima scanline)
dv=(v1-v0)/("""""""""""""""""""""""""""""""")
u1,u0,v1,v0: valori di u,v agli estremi della massima scanline
>>>> Funziona solo con triangoli
Questi due metodi sono i cosiddetti "texture mapping" a 2d perchè in
pratica si "scala" la texture tra i vertici dei poligoni, assegnando ad
ogni vertice del poligono un punto sulla texture e poi s'interpolano
linearmente le u,v lungo la scanline. Usando questi metodi si ha un
texture mapping molto veloce, ma aimè molto impreciso xchè si possono
notare delle distorsioni lungo la texture (soprattutto quando si usano
triangoli :( e io ne so qualcosa! Prova a vedere il tmap che ho fatto io
e noterai che quando ruota si nota che la texture viene "divisa" in due
lungo la diagonale della faccia!
Fondamentalmente queste sono le routine più famose per fare il texture
mapping; adesso ti faccio faccio vedere un esempio di un possibile ciclo di
texture mapping (pwr triangoli):
loop:
scanline(); <- calcola le tabelle delle scanline
tmap()
goto loop;
tmap()
calcola du/dy,dv/dy
interpola le u,v lungo il lato sinistro del triangolo
calcola du/dx,dv/dx per la scanline massima
for y=ymin to ymax (del triangolo)
u=u[y]
v=v[y]
for x=tab1[y] to tab2[y]
plot(x,y,txt[u,v])
u=u+du
v=v+dv
next x
next y
endproc tmap
Adesso sai ± o meno ciò che so anch'io sul tmap; si tratta solo di tradurre
il tutto in asm e incominciare a far girare qualcosa.... :)
Io adesso sono arrivato a fare l'env-mapping di oggetti molto più complessi
del "solito" cubo; mi faccio gli oggetti con imagine e poi li converto con
il tddd2raw+un'altro convertitore fatto da me e ho passato a Modem
un'esempio di env-map. Risultato? Sul mio misero a1200 le routine vanno a
1x1 in 5fps; sul suo a 50fps!!!! :))) Tutto si spiega dal fatto che lo 030
ha la data cache, e il suo amy ha la fast (importantissima).
Se hai qualcos'altro da chiedere, fai pure! :-)
Ps: ho rivisto ancora il rotator xchè volevo vedere alcune cose; a quanto
pare tu non conosci come si fanno le addizioni in decimale! Per questo
il rotator non è così preciso come vorresti; adesso ti spiego questo
"trucchetto" (spiegato a me da Hedgehog):
Quando devi interpolare qualsiasi cosa ti ritrovi a fare qualcosa del tipo:
x=a0+da/db*b
che si traduce in un ciclo
a=a0
loop:
a=a+da/db da/db è l'incremento di "a" quando ci si muove su "b"
:
goto loop
in assembler il tutto si traduce in:
; calcolo da/db
; a1,a0 valori da interpolare lungo b1,b0
move.w a1,d0
sub.w a0,d0 ; a1-a0
move.w b1,d1
sub.w b0,d1 ; b1-b0
swap d0 ; (a1-a0)<<16
divs.l d1,d0 ; da/db incremento shiftato di 16 per la parte decimale
; in modo tale che bit 31..16 15..0
; d0= intero decimale
move.l d0,dadb ; salva l'incremento
:
: altre istruzioni
:
move.w a0,d0 ; valore iniziale
swap d0 ; a0<<16
move.l dadb,d1
loop:
add.l d1,d0 ; (a+da/db)<<16
move.l d0,d2
swap d2 ; valore intero in d2.w che serve
:
:
dbra d4,loop
Il tutto si può semplificare (e soprattutto levare 1 o anche 2 istruzioni
nel loop) usando l'addx:
il calcolo di da/db va bene solo che prima di salvarlo fai uno "swap d0"
in modo da avere nella word alta la parte decimale, e nella word bassa la
parte intera (quella che più c'interessa); poi quando devi addizionare
l'icremento alla variabile corrente fai così:
add.l d1,d0
addx.w d3,d0 ; >>> in d3 ci deve essere 0!!! <<<
così in d0.w hai subito la variabile da usare e hai risparmiato uno swap!
(4 cicli su no 020) che non è male! ;))
L'addx serve perchè nel caso c'è il riporto dalla parte decimale, viene
addizionato (per questo d3 deve essere uguale a 0), così viene sfruttata la
parte decimale ;))
Non a caso, nel file con gl'inner loop più veloci trovi le addx invece che
delle add seguite da uno swap!
Pss: se vuoi, passalo pure questo doc, così magari divento più famoso! ;))
Amighevolmente,
/
\/\/ashburn / X-Zone & DeGeNeRaTiOn
Email: simon@digicolor.lognet.it
Snail:
Aversa Simone
Via F.Novati 27
26100 Cremona
Italy