Elikkä, teen pientä, ylhäältä kuvattua SDL-peliä, jossa kenttä koostuu tileistä. Ruohon, lattian, hiekan etc rajoja on tuska piirrellä erikseen, joten ajattelin saada ne blendautumaan toisiinsa kenttää ladatessa. Tekniikalla on nimikin, jostain D3D-tutoriaalista muistaisin lukeneeni, mutten muista tähän hätään.
No, homma ei sitten ollutkaan ihan heppoinen. Nyt selaan tilet vuorotellen läpi, blittaan temppipintaan vuorossa olevan tilen ja tarkistan sen naapurit. Jos naapuri on eri tyyppiä, otan sopivan alffa-maskin talteen maskifilusta (http://88.195.62.183/home/upload/up/blendfile.
* http://88.195.62.183/home/upload/up/blend1.png - käydään läpi vain ylä-, ala- ja sivunaapurit, ei siis kulmia.
* http://88.195.62.183/home/upload/up/blend2.png - käydään läpi kaikki 8 naapuria.
Homma kusee (muun muassa) siihen, että monta kertaa päällekkäin blittaillessa läpinäkyvien osien alffat menee miten sattuu. Apua kaipais. Kai tähän joku valmiskin keino on olemassa, vaikkakaan nopealla googletuksella en löytänyt.
Opera kirjoitti:
Virhe!
Palvelimeen ei saatu yhteyttäYritit päästä osoitteeseen http://88.195.62.183/home/upload/up/blend1.png, joka on tällä hetkellä saavuttamattomissa. Varmista, että www-osoite (URL) on kirjoitettu pisteineen oikein ja kokeile sitten sivun päivittämistä.
Varmista, että Internet-yhteys on aktiivinen ja katso, toimivatko muut samaa yhteyttä käyttävät ohjelmat oikein.
Joo, omalla servulla noi ja netti takkuaa. Refreshin spämmiminen voipi auttaa.
Ei kannata blitata kuvia miten sattuu. Kannattaa miettiä tarkemmin, miten haluat tiilien blendaantuvan. Blendaushan toimii ainakin tässä tapauksessa siten, että toisen kuvan päälle piirretään jotakin, mikä visuaalisesti tarkoittaa käytännössä sitä, että viimeisenä blitattu kuva näyttää olevan päällimmäisenä. Piirtojärjestyksellä on siis merkitystä.
Sanoisin, että helpoin tapa ratkaista ongelma on jakaa tilet eri "tasoille", vaikka tilen id:n mukaan. Eli tile #5 piirretään aina tile #3:n päälle, eikä koskaan toisinpäin. Voit käydä jokaisen tilen läpi ja blitata ensin itse tilen ja sen jälkeen katsoa, mitkä sen naapureista piirtyisivät tilen päälle ja sen jälkeen blitata ne sopivalla maskilla oikeassa järjestyksessä.
Esim: kenttä:
111122111 000222211 003122111
Viimeisen rivin neljäs tile piirrettäisiin seuraavasti:
1. Blitataan tile 1.
2. Blitataan tile 2 maskilla, joka näyttää suurinpiirtein tältä:
#### .### ..## ...#
3. Blitataan tile 3 maskilla
#... ##.. ##.. #...
(Huom: tileä 0 ei blitata lainkaan)
Maskien muodot kannattaa miettiä huolella ja maskien lisäksi voi käyttää jopa erikseen piirrettyjä reunakuvia, jolloin lopputuloksen pitäisi olla aika hieno (kuten Warcraft II :) ). Ainut ongelma on se, että jos kaikki kahdeksan naapuria ottaa huomioon, niin yläviistosta kuvatua peliä varten joutuu kulmia piirtämään 256 kpl per tile.
Juu kiits, tuo auttoi isosti. Alunperin koitin blendiä molemmilta puolilta, niin, että tiilien rajakohdassa olisi kumpaakin puolta 50%. Maskien muotojen kanssa vaan on tappelemista, mutta kai tuosta jotain siedettävää sikiää.
Jos haluat päästä maskien kanssa mahdollisimman helpolla, niin kannattaa kokeilla jakaa ruutu neljään osaan ja sovittaa maskien palaset jokaiseen erikseen kolmen lähimmän naapuriruudun perusteella:
Kenttä:
123 322 333
Suurennos/keskimmäisen ruudun jaottelu osiin
112233 112233 33AB22 33CD22 333333 333333
Maskin palasten muodot (tilen 3 blittaukseen):
A B C D #. .# #. .. #. .. ## ##
Koko maski:
#..# #... #... ####
Jokaiseen palaseen siis vaikuttavat ainoastaan kolme lähintä naapuriruutua ja maskeja tarvitaan viisi erilaista, esim A-ruudulle:
.. #. ## #. ## .. .. .. #. #.
Symmetriaan maksimaalisesti turvauduttaessa maskin palasia täytyy piirtää ainoastaan kolme. Tällöin piirtämisessä nähtävä vaiva on sen verran pieni, että kannattaa harkita erilaisia maskeja (tai maskattuja bittikarttakulmia) eri materiaaleille, jolloin hiekat ja nurmikot saa hienosti leviämään viereisten tilejen päälle ja kulmikkaat betoniseinät pysymään omissa ruuduissaan.
Esitänpä toisen lähestymistavan.
Joka ruudulla on neljä kulmaa. Tällöin materiaaleja voi olla eri kulmissa seuraavasti:
aa ; aa aa ab ; aa ab ; ab aa ; ab bb ba ; bc ca ; cd
Muut tilanteet ovat symmetrisiä jonkin näistä kanssa. Nyt tarvitaan siis maskit näitä tilanteita varten, yksi maski kunkin tapauksen kutakin materiaalia varten niin, että lopputulos on haluttu. Jos täysin tasapuolinen blendaus kelpaa, maskit voi generoida dynaamisesti ohjelman käynnistyessä. Lähtökohdaksi voidaan ottaa, että runsain materiaali (yllä a) piirretään ensin ilman maskia, muut sitten maskeineen sen päälle.
Dynaamisessa generoinnissa lasketaan joka pikselille ensin kunkin kulman vaikutus, summataan sitten samaa materiaalia olevien kulmien vaikutukset ja muokataan arvoja lopuksi niin, että ne kertovatkin lopullisen osuuden sijaan sen, paljonko tiettyä materiaalia pitää lisätä entisten piirustusten päälle, jotta määrä on oikea sen jälkeen, kun päälle piirretään vielä loput kuvat. Esimerkiksi jos kaikkia neljää materiaalia on määrä tulla yhtä paljon, ensimmäistä laitetaan ensin läpinäkymättömästi, toista puolet, kolmatta kolmannes ja neljättä neljännes.
Tässä jonkinlaista koodia, josta toivottavasti selviää jotain. Tarkka toteutus jää omiin käsiisi, mutta tätä sovellettaessa täytyy siis vielä tallentaa saatu maski jonnekin ja piirtovaiheessa tunnistaa, mitä maskia käytetään ja miten päin. Ei välttämättä ole lainkaan hassumpi ajatus luoda hieman ylimääräisiäkin kulman_tile-taulukon yhdistelmiä, se voi nimittäin säästää vaivaa oikean vaihtoehdon valinnassa ja pyörittelyssä.
/* // Eri yhdistelmät aiemman listauksen mukaan, kulmat kiertävässä järjestyksessä eri_kulman_tilet[][4] = { {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 1}, {0, 1, 0, 1}, {0, 1, 1, 2}, {0, 1, 2, 1}, {0, 1, 2, 3}, }; */ for (yi = 0; yi < h; ++yi) { float y = (yi + 0.5) / h; for (xi = 0; xi < w; ++xi) { float x = (xi + 0.5) / w; float kulmapaino[4] = { 1 / etaisyys(0, 0, x, y), 1 / etaisyys(0, 1, x, y), 1 / etaisyys(1, 0, x, y), 1 / etaisyys(1, 1, x, y), }; float tilepaino[4] = {0}; for (i = 0; i < 4; ++i) { tilepaino[kulman_tile[i]] += kulmapaino[i]; } float maski[4], summa = 0; for (i = 0; i < 4; ++i) { summa += tilepaino[i]; maski[i] = tilepaino[i] / summa; } } }
Lähestymistavan hyvä puoli: Tallentamalla joka ruudulle neljä kulmaa päästään eroon ajonaikaisista tarkistuksista, onko jossakin tuo mainittu tiiliseinä, jota ei pidäkään blendata. Tarvitsee vain merkitä ruutuihin oikeat kulmat.
Noissa on ideaa. Koitan Metabolixin tapaa huomenna ja toivottavasti saan jotain tulostakin pastettavaksi. Tosin kyllä tää monimutkaisemmaksi menee kuin millä olin toivonut pääseväni :)
Jooh, tulokset jäivät vähän laihoiksi. Koittanen uudelleen kun löydän aikaa, eka yritys kaatui purkkakoodiin ja suunnittelumokaan. Jos kuva toimii, vasemmalla "paras" yritys, ja siinäkin skippasin tarkoituksella maskien pyörittelyn. Pyörittely aiheuttaa oikean puolen valkoiset viivat, joista syytän SDL_gfx:n rotozoomeria, vaikkei sen kai pitäisi tuollaista saada aikaan? Noh, teen tuon ajatuksella loppuun joskus. Kiitokset ideoista.
Hm, sattuipa minullekin pieni ajatusvirhe, jonka huomaan noista kuvistasi. Etäisyyden laskeminen materiaalista ei käykään aivan noin, vaan tietenkin esimerkiksi vierekkäisten kulmien ollessa samaa ainetta täytyisi koko sivusta tulla samanlainen. Taisit saada esittämäni implementaation yksittäisten tilejen kohdalla toimimaan, reunat vain eivät sovi yhteen (eli materiaalit vierekkäisissä tileissä eivät osu kohdakkain) ja ajatukseni ei toimi. Pahoittelen tapahtunutta virhettä. :( Täytynee palata pohdiskelemaan tuota. Jotain osviittaa oikeasta algoritmista kulmapainojen laskentaan voisi saada selvittämällä, miten esimerkiksi OpenGL yhdistelee kolmion eri kulmien värit. (OpenGL:llä tämä koko homma menisikin todella helposti.)
Sain korjattua aamusella logiikkavirheet testidemosta, tällaisin tuloksin. Eli juu, reunat eivät mene kaikin kohdin yhteen, mutta oikeilla jäljillä ollaan. OpenGL:ää voisi tosiaan harkita, vaikken sillä olekaan mitään matopeliä isompaa tehnyt. No, tähän hätään os:n alkuperäinen ehdotus on aivan riittävä.
EDIT: jaaha, serverissä jotain häikkää näemmä. Kuva ei välttämättä aukea, muttei siinä mitään erikoista ole.
Aihe on jo aika vanha, joten et voi enää vastata siihen.