bollen tekenen (3D)

download de
kerstballen
generator

Inleiding

Dit artikel beschrijft hoe je in Delphi 3 dimensionale bollen kunt tekenen.
Er is een testprogramaatje toegevoegd en het hele Delphi-7 project kan gedownload worden.
(kijk onderaan deze pagina)

Opmerkelijk genoeg is er geen ingewikkelde wiskunde nodig: de stelling van Pythagoras en lineaire functies volstaan.
Er zijn een paar schuifjes toegevoegd om de lichtinval en intensiteit van de kleuren in te stellen.
Het artikel beschrijft die ook.
Een kleur kiezen gebeurt met één van de zeven speedbuttons, die in een array staan dat op runtime gecreëerd wordt.

fig.1 hieronder toont een verkleind beeld van het 3D bollen programma.


De kleuren

De kleuren op de bol veranderen lineair van het punt met de grootste intensiteit naar de randen.
Dit suggereert prima een driedimensionaal effect.
Het is onnatuurlijk om een kleur te veranderen van bijvoorbeeld rood naar blauw.
Alleen de intensiteit moet veranderen.
Daarom hoeven we alleen de intensiteit te berekenen, die loopt van 0 (donker) naar 255 (licht).
Daarna bepaalt een 3 bits code welke kleuren er meedoen.
colorcode bit -0- selecteert rood, bit -1- groen en bit -2- blauw.
Op design time is de colorcode opgeborgen in de tag property van de bijbehorende speed button.
Zie figuur 2.




Het tekenen van de bol

Dat gebeurt in bitmap Smap. (S - Sphere)

Alle pixels worden doorlopen van links naar rechts en boven naar onder.
Per pixel wordt getest of de positie binnen of buiten de bol ligt.
Zie figuur 3



Bekijk eens punt P(x,y). rx en ry zijn de horizontale- en vertikale afstanden tot middelpunt M.
    rx := x – centerX
    ry := y - centerY
Stelling van Pythagoras, bepaalt of P binnen de cirkel ligt als :
    MP = sqrt(rx*rx + ry*ry) <= radius.
Variabelen Xposition en Yposition zijn de posities van de X- en Y-schuifjes
en ook de coördinaten op de bol waar de lichtintensiteit maximaal is.

Om het rekenwerk te versimpelen wordt even aangenomen dat middelpunt M op (0,0) ligt.
Relatief t.o.v. M zijn focusX en focusY de coördinaten met maximale intensiteit (focuspunt):
    focusX := Xposition – centerX
    focusY := Yposition – centerY
We berekenen de kleur van pixel (rx, ry) .
Als (px,py) de afstand is tot het focuspunt dan:
    px := rx – focusX
    py := ry – focusY
Afstand d tot het focuspunt is:
    d := sqrt(px*px + py*py);
De intensiteit verandert van focuspunt naar de rand van de bol, gerekend over een lijn door M.
Variabelen CCint en BCint bevatten de intensiteit (0..255) van focuspunt en rand.
Een goed 3D effect wordt verkregen door de intensiteit lineair te laten verlopen (opmerkelijk).
Per pixellengte verandert de intensiteit met de waarde (max intensity - min.intensity)/(focus - border) dus:
    colorstep := (CCint - BCint-1)/(radius + sqrt(focusX*focusX+focusY*focusY));
Dit levert de kleurintensiteit voor punt P :
    col := CCint - trunc(d * colorStep);
De echte kleur voor pixel P wordt dan:
    color := colorcode2color(col,colorcode,true);
De schakelaar "true" geeft aan dat rood en blauw verwisseld moeten worden,
wegens het pf32 bit format van de bitmap.
De scanline[..] property wordt slechts twee keer gebruikt om de pointer naar pixel[0,0] te krijgen
en de afstand tussen twee lijnen te berekenen.
Dit maakt zeer snel tekenen mogelijk. De properties pixels[..] en scanline[..] zijn erg traag.



De schuifjes

Die worden getekend in paintboxen.
Xbox controleert de horizontale focus positie, Ybox de vertikale positie.
CCbox controleert de centrum-intensiteit, BCbox de rand-intensiteit.

De volgende condities kunnen op een schuifje van toepassing zijn:

type TSlidestatus = (stIdle,stOnSpot,stLocked);

var slidestatus : Tslidestatus;

slidestatus = stIdle geeft aan dat er geen aktie plaatsvindt. De muiswijzer staat niet boven een pijltje.
slidestatus = stOnSpot geeft aan dat de muiswijzer boven een pijltje staat.
slidestatus = stLocked geeft aan dat muiswijzer "onSpot" staat met muisknop ingedrukt.

Als de muisknop wordt ingedrukt bij status slidestatus = stOnSpot dan wordt de slidestatus stLocked.
Daarna kan de pijlpositie veranderen met mousemove events.

slidestatus wordt weer stIdle na een mouseUp event. Deze methode is van toepassing op alle pijltjes.
De mouseDown en mouseMove events methods zijn gescheiden per paintbox.

In de source code zien we ook de variabele Offset.
Offset is niet strikt nodig omdat de pijltjes maar klein zijn.
Fig. 5 hieronder demonstreert de noodzaak als er een groter object verplaatst wordt.



een rechthoek kan horizontaal worden verschoven.
X is de muispointer bij een mouseDown event.
Door te berekenen:
    Offset := X – position
en later X te corrigeren in geval van mouseMove events:
    X := X – Offset
simuleren we dat het object precies in het midden was aangeklikt.
X is de positie van het object.

Tekenen van de pijltjes.

Bekijk figuur 6. voor het tekenen van een horizontaal pijltje.


Het startpunt van de tekening is tevens de positie van het pijltje.
Penbewegingen voor de X- en Y-richtingen staan in een apart array[1..7].
Zie procedure paintRightArrow voor details.
Merk op, dat een oud pijltje eerst gewist moet worden voordat een nieuw in de paintbox kan worden getekend.

Er kan natuurlijk een klasse worden gemaakt om bollen te tekenen, maar hier is daarvan afgezien.

Het project

Klik [ hier ] voor het gehele Delphi-7 project.