Hirdetés

2024. június 9., vasárnap

Gyorskeresés

Útvonal

Fórumok  »  Szoftverfejlesztés  »  Vektorok es matrixok (téma lezárva)

Hozzászólások

(#1) 3man


3man
csendes tag

A neten 3d grafika temaju peldaprogramokat boven lehet talalni, de ezek nem mindig erthetoek a matematikai hatter hianyaban, ami neheziti a megertesuket es az alkalmazhatosagukat.
Nem kozvetlenul a 3d hardware programozasarol akarok itt irni, hanem ennek hattereben megbuvo elmeleteket szeretnem szemleletesen es interaktivan bemutatni.
Ezert nem is profiknak irok, hanem kezdoknek.

(#2) 3man


3man
csendes tag

Hogy meglegyen az interaktivitas, egy keretprogram lesz a bemutatohoz, aminek a draw_function() fuggvenyet fogom a tovabbiakban modositani.
Ez linuxon es winen is mukodik. Ha megsem, akkor a masodik sort aktivva kell tenni.

//ha win alatt megse lenne a WIN32 ledefinialva:
//#define WIN32

#define x_size 1200

#define y_size 800

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <math.h>

void draw_function();

#ifndef WIN32
//linux

#include <X11/Xlib.h>

#include <assert.h>

#include <unistd.h>

Display *dpy;

Window w;

GC gc;

int __gxx_personality_v0;

void pixel(int x ,int y,int r,int g,int b)

{

r&=0xff;

g&=0xff;

b&=0xff;

XSetForeground(dpy,gc,(r<<16)+(g<<8)+b);

XDrawPoint(dpy, w, gc, x,y);

}

int main()

{

dpy = XOpenDisplay((0));

w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0,0, x_size, y_size, 0,0,0);

XSelectInput(dpy, w, StructureNotifyMask);

XMapWindow(dpy, w);

gc = XCreateGC(dpy, w, 0, (0));

XSetForeground(dpy,gc,0);

while(1) { XEvent e; XNextEvent(dpy, &e); if (e.type == MapNotify)break; }

draw_function();

XFlush(dpy);

getchar();

return 0;

}

#else

//win

#include <windows.h>

HWND game_window;

char game_class[]="demowindow";

HDC hdc;

void pixel(int x,int y,int r,int g,int b)

{

r&=0xff;

g&=0xff;

b&=0xff;

SetPixel(hdc,x,y,(b<<16)+(g<<8)+(r));

}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

switch (uMsg)

{

case WM_DESTROY:

PostQuitMessage(0);

break;

case WM_KEYDOWN:

switch (wParam)

{

case VK_ESCAPE:

PostQuitMessage(0);

break;

}

break;

default:

return DefWindowProc(hwnd, uMsg, wParam, lParam);

}

return 0;

}

//int main()//vagy igy
//{ HINSTANCE hInstance=0;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

{

WNDCLASSEX clas;

MSG msg;

int style;

RECT rect;

int time;

int elapsed;

clas.cbSize = sizeof(WNDCLASSEX);

clas.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

clas.lpfnWndProc = WindowProc;

clas.cbClsExtra = 0;

clas.cbWndExtra = 0;

clas.hInstance = hInstance;

clas.hIcon = NULL;

clas.hCursor = NULL;

clas.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

clas.lpszMenuName = NULL;

clas.lpszClassName = game_class;

clas.hIconSm = 0;

RegisterClassEx(&clas);

style = WS_CAPTION|WS_SYSMENU|WS_MAXIMIZEBOX|WS_MINIMIZEBOX;

game_window = CreateWindowEx(0, game_class, "demo", style,0,0, 1,1, NULL, NULL, hInstance, 0);

hdc=GetDC(game_window);

rect.left = rect.top = 0;

rect.right = x_size;

rect.bottom = y_size;

SetWindowPos(game_window, NULL, 0,0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE|SWP_NOZORDER);

ShowWindow(game_window, nCmdShow);

draw_function();

return 0;

}

#endif

void draw_function()

{

for(int y=0;y<y_size;y++)

for(int x=0;x<x_size;x++) pixel(x,y,x,y,x+y);

}

(#3) 3man


3man
csendes tag

Szukseg lesz vektorokra, amin kesobb reszletesen is vegigmegyek.
Ezt az osztalyt valasztottam, mert hasonlo a shaderek nyelvehez. Ha ebben a formaban ismeri meg az ember, akkor kesobb a shaderekkel mar nem lesz annyi gondja.

vektor osztaly

Ezt be kell masolni valahova elore, vagy kulon fileban tarolni, kinek hogy tetszik.

Szukseg lesz meg vonalrajzolasra,

void line(int x1,int y1,int x2,int y2,int r,int g,int b)
{
XSetForeground(dpy,gc,(r<<16)+(g<<8)+b);
XDrawLine(dpy, w, gc, x1,y1,x2,y2);
}

void linev(float3 par1,float3 par2,float3 color)
{
int x1=x_size/2+(int)par1.x;
int y1=y_size/2-(int)par1.y;
int x2=x_size/2+(int)par2.x;
int y2=y_size/2-(int)par2.y;
int r=(int)(color.r*255.0);
int g=(int)(color.g*255.0);
int b=(int)(color.b*255.0);

line(x1,y1,x2,y2,r,g,b);
}

Es maris lehet ismerkedni a vektorok mukodesevel.

[ Szerkesztve ]

(#4) 3man


3man
csendes tag

Kepeket nem fogok linkelni, mindent a programon keresztul lehet majd latni. Aki nem forditja le, az nem fogja erteni, mirol van szo. Ez most egy kenyszer, de igazabol ennek csak igy van ertelme. A programozast nem lehet ugy megismerni, hogy nem muveli az ember.
A peldaprogramokban lehet valtoztani a parametereket, es meg lehet figyelni, mi hogy valtozik. A vektorosztaly osszes elemet megprobalom vizualisan bemutatni.

Az elso, a vektorok osszeadasa es kivonasa. Meg lehet figyelni, hogy mi tortenik osszaadaskor. Az osztalyban le van definialva, hogy kell vektorokat osszeadni.
Ez valojaban egyszeru osszeadas, csak eppen az osszes vektorelemre el kell vegezni.
Az azonos szinu vektorok ugyan azt a vektort jelolik, csak eltolva.

void draw_function()

{
float3 origo=float3(0,0,0);
float3 vec1=float3(200,10,0);
float3 vec2=float3(300,200,0);
float3 vec3=vec1+vec2;

// float3 vec3=vec2-vec1; //kivonas

linev(origo,vec1,float3(1,0,0));

linev(origo,vec2,float3(0,1,0));

linev(origo,vec3,float3(0,0,1));

linev(vec2,vec3 ,float3(1,1,0));

}

[ Szerkesztve ]

(#5) 3man


3man
csendes tag

A kivonast aktivva teve {a ket //-t kiszedve} egy fontos reszlet mukodese figyelheto meg. Ez a kivonas valojaban egy vektort huz a vec1-bol a vec2-be. Ekkor ez a ket vektor egy-egy poziciot jelol ki a terben.
Amit mondtam, az konnyen belathato az alabbi sorral.

linev(vec1,vec1+vec3,float3(0,0,1));

A elindulva a vec1(piros) poziciobol a vec3(kek) iranyaba a vec2-be(zold) jutok.

Ezt az egyszeru dolgot jol meg kell jegyezni. Amennyire jelentektelennek tunik, annyira hasznos lesz meg kesobb.

(#6) 3man


3man
csendes tag

A szorzas osztas skalarral vagy vektorral vegul is skalazasa a vektornak.
Skalarnal 1-nel nagyobbal megszorozva a vektort hosszabb lesz, kisebb szamnal ertelemszeruen rovidebb. Ha vektort vektorral szorzok, akkor komponensenkent lehet skalazni a vektort.

float3 vec3=vec2*0.5;//vektor szorozva skalar
float3 vec3=vec2*float3(0.9,1.0,1.0);//vektor szor vektor

A Length() a vektor hosszat adja. Mint latszik a definiciobol, a distance ugyan ezt szamolja, csak meg van adva egy f helyvektor, amit kivon eloszor az adott vektorbol. Ez nem mas, mint ket pont tavolsaga.
Mert ket pont kozt huzhato vektor az a kulombseguk, es ennek a hossza a tavolsaguk.

Az SqLength() az a sqr(Length()) vagyis a negyzetre emelt hossz. Sokszor ezt erdemes hasznalni, ha fontos a sebesseg, hiszen nincs benne gyokvonas. Mert akarmilyen gyors a hardware, ez idoigenyes. Ahogy a szogfuggvenyek kiszamolasa is. {sin,cos, tan}

A distance2D es a SqLength2D az elobbiek 2 dimenzios valtozata, nincs benne az y koordinata.A magassagot legtobbszor, hagyomanybol, az y koordinataban szokas felvenni.

[ Szerkesztve ]

(#7) 3man


3man
csendes tag

A vektor osztaly legtobbszor hasznalt fuggvenyei kovetkeznek.
Ezek a Normalize(), dot() es a cross().

Az elso {a Normalize()} mint latszik a definiciojabol, elosztja az osszes elemet a vektor hosszaval.
Ezzel elerheto, hogy a vektor hossza 1 legyen.
1 dimenzioban ez trivialis. x/x=1.

A dot mar ismeros, hiszen a Length() fuggvenyben is ez a kifejezes van a gyok alatt, csak ott a vektor onmagaval van (pont)szorozva.
Length(f) = sqrt(f.dot(f))

Ezt erdemes kozelebbrol is megvizsgalni, mert ez egy igazan sokmindenre hasznalhato valami .

float3 origo=float3(0,0,0);
float3 vecx=float3(1,0,0);
float3 vecy=float3(0,1,0);
float3 vec1=float3(300,200,0);
float dx=vecx.dot(vec1);
float dy=vecy.dot(vec1);

linev(origo,vec1,float3(1,0,0));

A vec1-nek(piros) ket komponenset kapom meg, ha pontszorzatat veszem az adott koordinata-tengellyel.
Ezek skalarok, amibol a zold es a kek vektorokat ugy kapom, hogy az adott koordinata-tengely vektorat megszorzom ezzel a skalarra,

linev(origo,vecx*dx,float3(0,1,0));
linev(origo,vecy*dy,float3(0,0,1));

Ezzel a ket vektorral, osszeadva oket, visszakapom az eredeti vektort.{vec1}

float3 vec3=vecx*dx+vecy*dy;
linev(origo,vec3,float3(1,1,0));

Ez valojaban egy koordinata transzformacio volt.

(#8) 3man


3man
csendes tag

Ez igazan akkor lesz szembetuno, ha elforgatom a koordinata rendszer.

float3 origo=float3(0,0,0);
float3 vecx=float3(11,-2,0);
float3 vecy=float3(2,11,0);
float3 vec1=float3(300,200,0);
vecx.Normalize();
vecy.Normalize();
float dx=vecx.dot(vec1);
float dy=vecy.dot(vec1);

linev(origo,vecx*400.0,float3(0.5,0.5,0.5));

linev(origo,vecy*400.0,float3(0.5,0.5,0.5));

linev(origo,vecx*-400.0,float3(0.5,0.5,0.5));

linev(origo,vecy*-400.0,float3(0.5,0.5,0.5));

linev(origo,vec1,float3(1,0,0));

linev(origo,vecx*dx,float3(0,1,0));

linev(origo,vecy*dy,float3(0,0,1));

float3 vec3=vecx*dx+vecy*dy;
linev(origo,vec3,float3(1,1,0));

Tehat a vecx es vecy vektorokkal es a dx,dy skalarral vissza tudom szamolni az eredeti vektort. Ez az utolso sor, a vec3(sarga) vektor. Ez teljesen fedi a vec1-et.

A masik koordinata rendszerben pedig igy nez ki a vektor. (vilagoskek)

vecx=float3(1,0,0);
vecy=float3(0,1,0);
linev(origo,vecx*400.0,float3(0.5,0.5,0.5));

linev(origo,vecy*400.0,float3(0.5,0.5,0.5));

linev(origo,vecx*-400.0,float3(0.5,0.5,0.5));

linev(origo,vecy*-400.0,float3(0.5,0.5,0.5));

vec3=float3(dx,dy,0);
linev(origo,vec3,float3(0,1,1));

(#9) 3man


3man
csendes tag

A cross() fuggvenyt meg nem tudom, hogy fogom bemutatni, mert minden 2d vektor {keresz}szorzata kilep a 3.dimenzioba. Lehet hogy elobb majd en is kilepek oda.

(#10) 3man


3man
csendes tag

Ja bocs, az osztalyt modositottam, hogy jobban hasonlitson a shaderek nyelvere.
Igy .x helyett lehet .r hasznalni, ahogy a fragment/pixel-shaderekben.

union {
struct{
float x;
float y;
float z;
};
struct{
float r;
float g;
float b;
};
float xyz[3];
};

(#11) 3man


3man
csendes tag

A wines resz nem jo volt. Mivel en linuxon vagyok, most detult ki. Ime a mukodokepes verzio.

#else

#include <windows.h>

HWND game_window;

char game_class[]="demowindow";

HDC hdc;

void pixel(int x,int y,int r,int g,int b)

{

r&=0xff;

g&=0xff;

b&=0xff;

SetPixel(hdc,x,y,(b<<16)+(g<<8)+(r));

}

void line(int x1,int y1,int x2,int y2,int r,int g,int b)

{

SelectObject( hdc, CreatePen( PS_SOLID, 0, RGB(r,g,b) ) );

MoveToEx(hdc,x1,y1,0);

LineTo(hdc,x2,y2);

}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

switch (uMsg)

{

case WM_DESTROY:

PostQuitMessage(0);

exit(0);

break;

case WM_KEYDOWN:

switch (wParam)

{

case VK_ESCAPE:

PostQuitMessage(0);

exit(0);

break;

}

break;

default:

return DefWindowProc(hwnd, uMsg, wParam, lParam);

}

return 0;

}

//int main()//vagy igy

//{ HINSTANCE hInstance=0;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

{

WNDCLASSEX clas;

MSG msg;

int style;

RECT rect;

int time;

int elapsed;

clas.cbSize = sizeof(WNDCLASSEX);

clas.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

clas.lpfnWndProc = WindowProc;

clas.cbClsExtra = 0;

clas.cbWndExtra = 0;

clas.hInstance = hInstance;

clas.hIcon = NULL;

clas.hCursor = NULL;

clas.hbrBackground = (HBRUSH)(COLOR_WINDOW+3);

clas.lpszMenuName = NULL;

clas.lpszClassName = game_class;

clas.hIconSm = 0;

RegisterClassEx(&clas);

style = WS_CAPTION|WS_SYSMENU|WS_MAXIMIZEBOX|WS_MINIMIZEBOX;

game_window = CreateWindowEx(0, game_class, "demo", style,0,0, 1,1, NULL, NULL, hInstance, 0);

hdc=GetDC(game_window);

rect.left = rect.top = 0;

rect.right = x_size;

rect.bottom = y_size;

SetWindowPos(game_window, NULL, 0,0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE|SWP_NOZORDER);

ShowWindow(game_window, nCmdShow);

draw_function();

while(1)

{

//Are there any messages waiting?

while (PeekMessage(&msg, game_window, 0, 0, PM_NOREMOVE))

{

//yes! read it.

if (GetMessage(&msg, game_window, 0,0) < 0)

break;

//pass the message to WindowProc

TranslateMessage(&msg);

DispatchMessage(&msg);

}

};

return 0;

}

#endif

(#12) 3man


3man
csendes tag

Az elobbi koordinata transzformaciot kibovitve z koordinataval eljutottam a matrixokig. Az A1, A2 es az A3 ugyan azt irja le. Ez egy matrix szorzasa egy vektorral. Ez a koordinata transzformacio, ami felbonthato pontszorzatokra.
Tehat minden matrix egy egyenletrendszert ir le.
A cg 4 dimenzios matrixokat hasznal. Ez azert szukseges, mert 3 vektorral csak a koordinata tengelyek adhatoak meg. A 4. vektor az origoja ennek a koordinata rendszernek. Tehat a vilagkoordinata rendszer, ami 0,0,0 pozicioban van, igy nez ki:
[1,0,0,0]//x tengely
[0,1,0,0]//y tengely
[0,0,1,0]//z tengely
[0,0,0,1]//origo
Az utolso egyes a matrix muveletek miatt kell hogy ott legyen.

void draw_function()

{

float3 origo=float3(0,0,0);

float3 vecx=float3(11,-2,0);

float3 vecy=float3(2,11,0);

float3 vecz=float3(0,0,1);

float3 vec1=float3(300,200,0);
float3 vec2;

vecx.Normalize();

vecy.Normalize();

vec2.x=vecx.dot(vec1);//A1

vec2.y=vecy.dot(vec1),
vec2.z=vecz.dot(vec1);

printf("%f %f %f \n",vec2.x,vec2.y,vec2.z);
vec2.x=vecx.x*vec1.x+vecx.y*vec1.y+vecx.z*vec1.z;//A2

vec2.y=vecy.x*vec1.x+vecy.y*vec1.y+vecy.z*vec1.z;

vec2.z=vecz.x*vec1.x+vecz.y*vec1.y+vecz.z*vec1.z;

printf("%f %f %f \n",vec2.x,vec2.y,vec2.z);
/*
[vecx.x vecx.y vecx.z]//A3

[vecy.x vecy.y vecy.z]

[vecz.x vecz.y vecz.z]

*/

linev(origo,vecx*400.0,float3(0.5,0.5,0.5));

linev(origo,vecy*400.0,float3(0.5,0.5,0.5));

linev(origo,vecx*-400.0,float3(0.5,0.5,0.5));

linev(origo,vecy*-400.0,float3(0.5,0.5,0.5));

linev(origo,vec1,float3(1,0,0));

linev(origo,vecx*vec2.x,float3(0,1,0));

linev(origo,vecy*vec2.y,float3(0,0,1));

float3 vec3=vecx*vec2.x+vecy*vec2.y+vecz*vec2.z;//B1

linev(origo,vec3,float3(1,1,0));

printf("%f %f %f \n",vec3.x,vec3.y,vec3.z);
vec3.x=vecx.x*vec2.x+vecy.x*vec2.y+vecz.x*vec2.z;//B2

vec3.y=vecx.y*vec2.x+vecy.y*vec2.y+vecz.y*vec2.z;

vec3.z=vecx.z*vec2.x+vecy.z*vec2.y+vecz.z*vec2.z;

printf("%f %f %f \n",vec3.x,vec3.y,vec3.z);
/*
[vecx.x vecy.x vecz.x]//B3

[vecx.y vecy.y vecz.y]

[vecx.z vecy.z vecz.z]

*/

vecx=float3(1,0,0);

vecy=float3(0,1,0);

linev(origo,vecx*400.0,float3(0.5,0.5,0.5));

linev(origo,vecy*400.0,float3(0.5,0.5,0.5));

linev(origo,vecx*-400.0,float3(0.5,0.5,0.5));

linev(origo,vecy*-400.0,float3(0.5,0.5,0.5));

vec3=float3(vec2.x,vec2.y,0);

linev(origo,vec3,float3(0,1,1));

}

(#13) 3man


3man
csendes tag

Erdemes megfigyelni a kulombseget az A3 es a B3 matrixok kozott. A foatlora tukrozve vannak az A3 elemei.
A B3 matrix az A3 transzponaltja.

Matrix Transpose operator
A transzponálás, a mátrix elemeinek a főátlóra történő tükrözése

Ez a koordinata rendszerek kozti oda-vissza valtas lenyege.
Ha negy dimenzios a matrix, akkor az origo is hozzaadodik az eredmenyhez, ami egy eltolast jelent.

(#14) 3man


3man
csendes tag

A matrix forma nagyon szep, csak epp a lenyeget, a mukodesi mechanismust rejti el a szemunk elol.

Egy vektort igy konvertalok at egy koordinata rendszerbe.
vec2.x=vecx.dot(vec1);
vec2.y=vecy.dot(vec1),
vec2.z=vecz.dot(vec1);
A pontszorzat, ha az egyik vektor egysegvektor es egy siknak a normalja, akkor a pont es a sik tavolsagat adja meg.
Az xy sik normalja a (0,0,1) . Trivialis, hogy ekkor a dot() a vektor z koordinatajat fogja visszaadni, hiszen a tobbi koordinata 0-val van megszorozva.
Tehat a felirt harom egyenlet egy helyvektor 3 siktoli tavolsagat adja meg.

Amikor ezt a vektort vissza akarom konvertalni az eredeti koordinata rendszerbe, akkor ez tortenik.
vec3=vecx*vec2.x+vecy*vec2.y+vecz*vec2.z;

Ez meg egyszerubb. A vecx iranyban elviszem a pontot vec2.x ertekkel, ami egy skalar. Nyilvan az elobb az elso pontszorzat ekkora tavolsagot adott az yz siktol.
Ezutan az y tengely iranyaban is elmozgatom a pontot vec2,y-al, majd z tengelyben is.

A pont visszakerult a helyere.
Igazabol az opengl-t es a directx-et ezek tudasa nelkul is lehet hasznalni, hiszen a fuggvenyek akarmilyen matrixot kiszamolnak nekunk.

Na de mennyivel mas, amikor az ember erti is, mit csinal a gep.

(#15) 3man


3man
csendes tag

Es vegul a cross() fuggveny. A vec2 a monitor sikjara meroleges, ez csak egy zold pontnak latszik.
A kek szinu vec3 eredmeny mindket bemeno vektorra meroleges lesz. Az {origo vec1 vec2} harmas vektor egy sikot jelol ki, ennek a normalja a vec3.
Ha az egyik vektor elojelet megforditom, vagy felcserelem a szorzasi sorrendet, akkor a sik masik oldala fele fog mutatni a vec3.

float3 origo=float3(0,0,0);

float3 vec1=float3(300,200,0);
float3 vec2=float3(0,0,1);

float3 vec3=vec1.cross(vec2);

linev(origo,vec1,float3(1,0,0));
linev(origo,vec2,float3(0,1,0));
linev(origo,vec3,float3(0,0,1));

vec2=float3(0,0,-1);

vec3=vec1.cross(vec2);
linev(origo,vec3,float3(1,1,0));

(#16) 3man


3man
csendes tag

Most az alapok utan kicsit melyebbre merulok.
A bumpmap, normalmap es a parallax technikak egyik nelkulozhetetlen segedeszkoze a tangens-ter. Ennek bemutatasahoz egy egyszeru 2d matrix osztalyt hoztam ossze. A reszleteket a megadott linkeken megtalalja akit erdekel.

A tangens ter a haromszogre rahuzott map iranyultsagat adja meg. A szamitas az alabbi feltetelbol indul ki.
Ha a haromszog egyik (vec1) csucsabol T (tangens) iranyban U.x erteket lepek, azutan B (bitangens/binormal) iranyban U.y erteket, akkor eljutok a vec2 re.
Ugyan ez V.x V.y-al vegigjatszva a vec3-ra jutok, ami a harmadik csucsa a haromszognek. Ez a kiindulo egyenlet.

U=txcoord2-txcoord1;// a haromszog csucsainak map koordinatai
V=txcoord3-txcoord1;
V1=vec2-vec1;//a haromszog csucsai
V2=vec3-vec1;

A kiindulo egyenlet:
vec2=vec1+T*U.x + B*U.y
vec3=vec1+T*V.x + B*V.y

vec1-et levonva ezt kapom
V1=T*U.x + B*U.y
V2=T*V.x + B*V.y

Matrix alakba felirva
[V1,V2]=[U,V][T,B]

Az [U,V] inverzevel beszorzom a ket oldalt.
[V1,V2][U,V]^-1=[T,B]
es meg is kaptam a tangens vektorokat.

Az algoritmus csak 2 dimenzioban jo, 3d-hez modositani kell.

void pixelv(float3 par1,float3 color)

{

int x1=x_size/2+(int)par1.x;

int y1=y_size/2-(int)par1.y;

int r=(int)(color.r*255.0);

int g=(int)(color.g*255.0);

int b=(int)(color.b*255.0);

pixel(x1,y1,r,g,b);

}

class matrix2D
{
public:
float a,b;
float c,d;

matrix2D() {a=b=c=d=0;};
matrix2D(float s1,float s2,float s3,float s4) {a=s1;b=s2;c=s3;d=s4;};
matrix2D(float3 vc1,float3 vc2)
{
a=vc1.x; b=vc1.y;
c=vc2.x; d=vc2.y;
};
matrix2D operator* (float f)
{
matrix2D m(a,b,c,d);
m.a*=f;m.b*=f;
m.c*=f;m.d*=f;
return m;
}
float3 operator* (float3 f)
{
float3 vec;
vec.x=f.x*a + f.y*c;
vec.y=f.x*b + f.y*d;
vec.z=0;
return vec;
}
matrix2D Transpose()//http://en.wikipedia.org/wiki/Transpose
{
matrix2D m;

m.a=a; m.b=c;
m.c=b; m.d=d;

return m;
}
matrix2D Adjugate()//http://en.wikipedia.org/wiki/Adjugate_matrix
{
matrix2D m;

m.a=d; m.b=-b;
m.c=-c;m.d=a;

return m;
}
float Determinant()//http://en.wikipedia.org/wiki/Determinant
{
return a*d-b*c;
}
matrix2D Inverse()//http://en.wikipedia.org/wiki/Invertible_matrix
{
matrix2D m=Adjugate()*(1.0/Determinant());

return m;
}

};
void draw_function()

{
float3 vec1=float3(0,0,0);
float3 vec2=float3(300,200,0);
float3 vec3=float3(-50,150,0);

float3 txcoord1=float3(0,0,0);
float3 txcoord2=float3(1,0,0);
float3 txcoord3=float3(0,1,0);

float3 U=txcoord2-txcoord1;
float3 V=txcoord3-txcoord1;
matrix2D uvSpace=matrix2D(U,V);
uvSpace=uvSpace.Inverse();

float3 V1=vec2-vec1;
float3 V2=vec3-vec1;

float3 T=V1*uvSpace.a + V2*uvSpace.b;
float3 B=V1*uvSpace.c + V2*uvSpace.d;

matrix2D TanSpace=matrix2D(T,B);
TanSpace=TanSpace.Inverse();

for(int y=-250;y<250;y++)
for(int x=-400;x<400;x++)
{
float3 screen=float3(x,y,0);
float3 temp=screen-vec1;
float3 txcoord=txcoord1 + TanSpace*temp;

pixelv(screen,txcoord);
}
linev(vec1,vec1+T*4,float3(0.0,0.0,0.5));
linev(vec1,vec1+B*4,float3(0.0,0.0,0.5));
linev(vec1,vec1-T*4,float3(0.0,0.0,0.5));
linev(vec1,vec1-B*4,float3(0.0,0.0,0.5));

linev(vec1,vec2,float3(1,1,1));
linev(vec1,vec3,float3(1,1,1));
}

(#17) 3man


3man
csendes tag

Ideje atlepni a 3. dimenzioba. Ehhez kell definialni egy view matrixot, ami a kamera terbeli iranyat adja meg. Ehhez jarna egy projection matrix is, ami a perspektivat adna meg, de mivel most egy sugar koveteshez {raytrace} hasonlo modon fogok szamolni, erre nem lesz szukseg.
Egy uj utasitas lep a kepbe, a lerp(). Linear_interpolation,
vagyis a linearis interpolacio. Ezzel a shaderek nyelvehez tartozo utasitassal ket vektor kozt egy vonalon barmelyik pontot egyszeruen megkapjuk, csak egy 0 es 1 kozti szamot kell megadni.
A view matrix definialasahoz szukseges a szem(eyes) pozicioja, es hogy hova akarunk nezni (lookat). A float3(0,1,0) a felfele iranyt adja meg a terben.Ez termeszetesen modosithato, de mindig normalizalni kell.
Az view x iranyat a cross segitsegevel lehet megkapni. Az eredmeny vektor iranyara a linken megtalalhato kez-szabaly ervenyes.
Cross_product

Az osszes tengely kiszamitasa utan vegigmegyek a kepernyo pixelein. A screen koordinatabol felveheto egy sugar(ray), aminek a metszespontjat kell megtalalni egy sikkal (plane). A sik alabbol az xz sik, de ha aktivva teszem a ket sort, akkor megadhato a sik normalja.
A jelenlegi grafikai megjelenitok (meg) nem igy dolgoznak, a folyamat forditott. A bemeno ertek egy haromszog sarkainak 3d koordinataja, amibol egy 2d kepernyo koordinatat kell kiszamolni.

float3 lerp(float3 par1,float3 par2,float sc)
{
return par1 + (par2-par1)*sc;
}

void draw_function()

{
float3 LookAt=float3(0,0,0);
float3 Eyes=float3(350,250,130);
float3 ViewMatrix_z=LookAt-Eyes;
ViewMatrix_z.Normalize();
float3 ViewMatrix_x=ViewMatrix_z.cross(float3(0,1,0));
float3 ViewMatrix_y=ViewMatrix_x.cross(ViewMatrix_z);

for(int y=-y_size/2;y<y_size/2;y++)
for(int x=-x_size/2;x<x_size/2;x++)
{
float3 screen=float3(x,y,300);
float3 ray=ViewMatrix_x*screen.x + ViewMatrix_y*screen.y+ ViewMatrix_z*screen.z;
ray.Normalize();

float3 plane_origo=float3(0,0,0);
float dist=(plane_origo.y-Eyes.y)/ray.y;

//float3 plane_normal=float3(10,200,120).Normalize();
//dist=plane_normal.dot(plane_origo-Eyes)/plane_normal.dot(ray);

float3 plane=Eyes + ray*dist;

plane.y=0.0;
float3 color=plane*0.002;
if(dist<0.0) color=lerp(float3(0,1,1),float3(0,0,1),ray.y);

pixelv(screen,color);
}
}

[ Szerkesztve ]

(#18) 3man


3man
csendes tag

A szamitogepes jatekok ket fontos eleme a fenyek es a mappok. Ezek hatarozzak meg leginkabb a latvanyt.
Uj utasitas lep be, a saturate(). Ez 0 es 1 koze limitalja az erteket. Shaderekben ezzel helyettesitheto v=min(max(v,0),1)

A form_to_tex2D segitsegevel felepitek egy teszmappot. Ez egy 2 dimenzios kepnek felel meg, ami majd a magassag map lesz a parallaxhoz.Ebbol a create_normalmap() egy normalmappot general , ami termeszetesen a normalokat fogja tarolni.

normal=normal*0.5+float3(0.5,0.5,0.5);
Ez a sor eltunteti a negativ ertekeket, de ugy, hogy kesobb vissza lehessen hozni oket. Igy
float3 normal=(normal_map-float3(0.5,0.5,0.5))*(-2.0);

A shaderekben hasonloan lehet elerni a texturakat a programbol.
float3 normal_map=tex2D[1][txcoord_hw];

Igazan erdekes akkor tortenik, amikor aktivalom ezt a sort.
//#define enable_lighting
A felulet bevilagitodik, es nem is akar hogy. A normalmappot, mint egyszeru bumpot hasznalja a program. Lehetne meg onarnyekot szamolni a feluletre, talan majd kesobb.

float saturate(float par)
{
if(par>1.0) return 1.0;
if(par<0.0) return 0.0;
return par;
}

const int map_size=512;
float3 tex2D[4][map_size*map_size];

void form_to_tex2D(int xcenter,int ycenter,int size,int type)
{
size/=2;

for(int y=ycenter-size;y<ycenter+size;y++)
for(int x=xcenter-size;x<xcenter+size;x++)
{
int kx=abs(x-xcenter);
int ky=abs(y-ycenter);
float z=tex2D[0][y*map_size+x].r;

switch(type)
{
case 0:
z=0.0;
break;
case 1:
z=1.0;
break;
case 2:
z=1.0-(float)((kx>ky)? kx:ky)/50.0 ;
break;
case 3:
float rad=sqrt(kx*kx+ky*ky)/50.0;
if(rad<1.0)
z=1.0-rad ;
break;
}
tex2D[0][y*map_size+x]=float3(z,z,z);
}
}
void create_normalmap()
{
for(int y=0;y<map_size-1;y++)
for(int x=0;x<map_size-1;x++)
{
float scale=30.0;
float3 pixel =float3(x ,tex2D[0][y*map_size+x].r*scale, y);
float3 pixel_u=float3(x+1,tex2D[0][y*map_size+x+1].r*scale, y);
float3 pixel_v=float3(x ,tex2D[0][y*map_size+x+map_size].r*scale, y+1);

float3 temp=(pixel_u-pixel);
float3 normal=temp.cross(pixel_v-pixel);
normal.Normalize();

normal=normal*0.5+float3(0.5,0.5,0.5);

tex2D[1][y*map_size+x]=normal;
}
}
void mapsetup()
{
form_to_tex2D(map_size/2,map_size/2,map_size,1);
form_to_tex2D(map_size/2,map_size/2,map_size-100,0);

form_to_tex2D(180,180,100,2);
form_to_tex2D(320,320,100,2);
form_to_tex2D(180,320,100,3);
form_to_tex2D(320,180,100,3);

create_normalmap();
}

//#define enable_lighting

void draw_function()

{
float3 LookAt=float3(0,0,0);
float3 Eyes=float3(350,250,130);
float3 ViewMatrix_z=LookAt-Eyes;
ViewMatrix_z.Normalize();
float3 ViewMatrix_x=ViewMatrix_z.cross(float3(0,1,0));
float3 ViewMatrix_y=ViewMatrix_x.cross(ViewMatrix_z);

float3 light_position=float3(-300,320,-200);
mapsetup();

for(int y=-y_size/2;y<y_size/2;y++)
for(int x=-x_size/2;x<x_size/2;x++)
{
float3 screen=float3(x,y,300);
float3 ray=ViewMatrix_x*screen.x + ViewMatrix_y*screen.y + ViewMatrix_z*screen.z;
ray.Normalize();

float3 plane_origo=float3(0,0,0);
float3 plane_normal=float3(0,1,0).Normalize();
float dist=plane_normal.dot(plane_origo-Eyes)/plane_normal.dot(ray);

float3 plane=Eyes + ray*dist;

plane.y=0.0;
float3 color=plane*0.002;
float3 txcoord=plane*0.002;

int txcoord_hw=(((int)(txcoord.z*map_size))&(map_size-1))*map_size + (((int)(txcoord.x*map_size))&(map_size-1));
float3 height_map=tex2D[0][txcoord_hw];
float3 normal_map=tex2D[1][txcoord_hw];
color=normal_map;

#ifdef enable_lighting
float3 normal=(normal_map-float3(0.5,0.5,0.5))*(-2.0);
float3 plane2light=light_position-plane;
plane2light.Normalize();

float diffuse_light=saturate(plane2light.dot(normal));
color*=diffuse_light;

float3 eyes2plane=plane-Eyes;
eyes2plane.Normalize();
float3 reflection_dir=eyes2plane - normal*normal.dot(eyes2plane)*2.0;
float3 light_color=float3(1.0,0.9,0.5);
float specular_light=pow(saturate(reflection_dir.dot(plane2light)),20.0);
color=lerp(color,light_color,specular_light);
#endif

if(dist<0.0) color=lerp(float3(0,1,1),float3(0,0,1),ray.y);//sky_color

pixelv(screen,color);
}
}

(#19) 3man


3man
csendes tag

Elerkezett az egyik leglatvanyosabb minosegi ugras a programban. Erdemes ezeket a sorokat sorba, egyenkent aktivalni, hogy latszodjon ez az ugras.
#define enable_lighting
//#define enable_parallax
//#define enable_parallax_shadow

Es ezt mind csak egy 2 dimenzios kepbol allitja elo a program. Ez a rovid kod ray.Normalize(); sortol kezdodoen szinte teljesen megegyezik egy fragment shaderrel.
A videokartya sebessegenek nagysaga itt latszik meg igazan, hiszen ez a program a processzoron fut, es kb 1-2 masodperc alatt szamol egy kepet. Ez framgent shaderbe atultetve egy mai grafikai megjeleniton legalabb 100 kepet rajzolna ki masodpercenkent, ami hatalmas ugras a kozponti egyseg teljesitmenyehez kepest.
A parallax mukodeset majd kesobb reszletezem.

float3 lerp(float3 par1,float3 par2,float sc)
{
return par1 + (par2-par1)*sc;
}

float saturate(float par)
{
if(par>1.0) return 1.0;
if(par<0.0) return 0.0;
return par;
}

const int map_size=512;
float3 tex2D[4][map_size*map_size];

void form_to_tex2D(int xcenter,int ycenter,int size,int type)
{
size/=2;

for(int y=ycenter-size;y<ycenter+size;y++)
for(int x=xcenter-size;x<xcenter+size;x++)
{
int kx=abs(x-xcenter);
int ky=abs(y-ycenter);
float z=tex2D[0][y*map_size+x].r;

switch(type)
{
case 0:
z=0.0;
break;
case 1:
z=1.0;
break;
case 2:
z=1.0-(float)((kx>ky)? kx:ky)/50.0 ;
break;
case 3:
float rad=sqrt(kx*kx+ky*ky)/50.0;
if(rad<1.0)
z=1.0-rad ;
break;
}
tex2D[0][y*map_size+x]=float3(z,z,z);
}
}
void create_normalmap()
{
for(int y=0;y<map_size-1;y++)
for(int x=0;x<map_size-1;x++)
{
float scale=30.0;
float3 pixel =float3(x ,tex2D[0][y*map_size+x].r*scale, y);
float3 pixel_u=float3(x+1,tex2D[0][y*map_size+x+1].r*scale, y);
float3 pixel_v=float3(x ,tex2D[0][y*map_size+x+map_size].r*scale, y+1);

float3 temp=(pixel_u-pixel);
float3 normal=temp.cross(pixel_v-pixel);
normal.Normalize();

normal=normal*0.5+float3(0.5,0.5,0.5);

tex2D[1][y*map_size+x]=normal;
}
}
void mapsetup()
{
form_to_tex2D(map_size/2,map_size/2,map_size,1);
form_to_tex2D(map_size/2,map_size/2,map_size-100,0);

form_to_tex2D(180,180,100,2);
form_to_tex2D(320,320,100,2);
form_to_tex2D(180,320,100,3);
form_to_tex2D(320,180,100,3);

create_normalmap();
}

int get_texture_addr(float3 txcoord_)
{
return (((int)(txcoord_.y*map_size))&(map_size-1))*map_size + (((int)(txcoord_.x*map_size))&(map_size-1));
}

#define enable_lighting
//#define enable_parallax
//#define enable_parallax_shadow

void draw_function()

{
float3 LookAt = float3(0,0,0);
float3 Eyes = float3(350,250,130);
float3 ViewMatrix_z = LookAt-Eyes;
ViewMatrix_z.Normalize();
float3 ViewMatrix_x = ViewMatrix_z.cross(float3(0,1,0));
float3 ViewMatrix_y = ViewMatrix_x.cross(ViewMatrix_z);

float3 light_position = float3(-300,320,-200);
mapsetup();

for(int y=-y_size/2;y<y_size/2;y++)
for(int x=-x_size/2;x<x_size/2;x++)
{
float3 screen = float3(x,y,300);
float3 ray = ViewMatrix_x*screen.x + ViewMatrix_y*screen.y + ViewMatrix_z*screen.z;
ray.Normalize();

float3 plane_origo = float3(0,0,0);
float3 plane_normal = float3(0,10,0).Normalize();
float3 plane_tangent = plane_normal.cross(float3(0,0,1));
float3 plane_bitangent = plane_tangent.cross(plane_normal);

float dist = plane_normal.dot(plane_origo-Eyes) / plane_normal.dot(ray);
float3 plane_ray_intersection = Eyes + ray*dist;
float dist_=dist;

float map_scale=0.002;
float3 color = plane_ray_intersection*map_scale;
float3 temp = plane_ray_intersection - plane_origo;
float3 txcoord = float3(plane_tangent.dot(temp),plane_bitangent.dot(temp),0)*map_scale;

#ifdef enable_parallax
float3 plane_origo2 = plane_origo-plane_normal*80.0;
dist = plane_normal.dot(plane_origo2-Eyes) / plane_normal.dot(ray);
float3 plane_ray_intersection2 = Eyes + ray*dist;

temp = plane_ray_intersection2-plane_origo2;
float3 txcoord2 = float3(plane_tangent.dot(temp),plane_bitangent.dot(temp),0)*map_scale;
float3 txcoord3;

int parallax_step = 64;
float position = 1.0, delta_position=-1.0/(float)parallax_step;
for(int i=0;i<6;i++)
{
float3 height_map;

for(int j=0;j<parallax_step+1;j++)
{
txcoord3 = lerp(txcoord2,txcoord,position);
height_map = tex2D[0][get_texture_addr(txcoord3)];

if(position <= 0.0) break;
if(height_map.r > position) break;
position += delta_position;
}
if(position<0.0) {txcoord3 = txcoord2;break;}

if(height_map.r>position) {position -= delta_position;delta_position*=0.5;}
else
break;
}
plane_ray_intersection = lerp(plane_ray_intersection2,plane_ray_intersection,position);
txcoord=txcoord3;
#endif

float parallax_shadow=1;
#ifdef enable_parallax_shadow
float3 light_ray=plane_ray_intersection-light_position;
light_ray.Normalize();

dist = plane_normal.dot(plane_origo-light_position) / plane_normal.dot(light_ray);
float3 plane_ray_intersection4 = light_position + light_ray*dist;

dist = plane_normal.dot(plane_origo2-light_position) / plane_normal.dot(light_ray);
float3 plane_ray_intersection5 = light_position + light_ray*dist;

temp = plane_ray_intersection4 - plane_origo;
float3 txcoord4 = float3(plane_tangent.dot(temp),plane_bitangent.dot(temp),0)*map_scale;
temp = plane_ray_intersection5 - plane_origo;
float3 txcoord5 = float3(plane_tangent.dot(temp),plane_bitangent.dot(temp),0)*map_scale;

parallax_step=64;
delta_position = 1.0/(float)parallax_step;
position += delta_position;
{
float3 height_map;

for(int j=0;j<parallax_step+1;j++)
{
txcoord5 = lerp(txcoord5,txcoord4,position);
height_map = tex2D[0][get_texture_addr(txcoord5)];

if(position >= 1.0) break;
if(height_map.r > position) {parallax_shadow=0;break;}
position += delta_position;
}
}
#endif

int txcoord_hw = get_texture_addr(txcoord);
float3 normal_map = tex2D[1][txcoord_hw];
color = normal_map;

#ifdef enable_lighting
normal_map = (normal_map-float3(0.5,0.5,0.5))*(-2.0);
float3 normal = plane_tangent*normal_map.x + plane_normal*normal_map.y + plane_bitangent*normal_map.z;
float3 plane2light = light_position - plane_ray_intersection;
plane2light.Normalize();

float diffuse_light = saturate(plane2light.dot(normal));
color *= diffuse_light*parallax_shadow;

float3 eyes2plane = plane_ray_intersection - Eyes;
eyes2plane.Normalize();
float3 reflection_dir = eyes2plane - normal*normal.dot(eyes2plane)*2.0;
float3 light_color = float3(1.0,1.0,1.0);
float specular_light = pow(saturate(reflection_dir.dot(plane2light)),20.0);
color = lerp(color,light_color,specular_light)*parallax_shadow;
#endif

if(dist_<0.0) color = lerp(float3(0,1,1),float3(0,0,1),ray.y);//sky_color

pixelv(screen,color);
}
}

(#20) 3man


3man
csendes tag

//ha win alatt megse lenne a WIN32 ledefinialva:
//#define WIN32


#define x_size 1200
#define y_size 800



#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>




void draw_function();


#ifndef WIN32

#include <X11/Xlib.h>
#include <assert.h>
#include <unistd.h>


Display *dpy;
Window w;
GC gc;
int __gxx_personality_v0;


void pixel(int x ,int y,int r,int g,int b)
{
r&=0xff;
g&=0xff;
b&=0xff;
XSetForeground(dpy,gc,(r<<16)+(g<<8)+b);
XDrawPoint(dpy, w, gc, x,y);
}
void line(int x1,int y1,int x2,int y2,int r,int g,int b)
{
XSetForeground(dpy,gc,(r<<16)+(g<<8)+b);
XDrawLine(dpy, w, gc, x1,y1,x2,y2);
}
int main()
{
dpy = XOpenDisplay((0));
w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0,0, x_size, y_size, 0,0,0);


XSelectInput(dpy, w, StructureNotifyMask);
XMapWindow(dpy, w);


gc = XCreateGC(dpy, w, 0, (0));
XSetForeground(dpy,gc,0);


while(1) { XEvent e; XNextEvent(dpy, &e); if (e.type == MapNotify)break; }



draw_function();



XFlush(dpy);
getchar();

return 0;
}

#else

#include <windows.h>

HWND game_window;
char game_class[]="demowindow";
HDC hdc;


void pixel(int x,int y,int r,int g,int b)
{
r&=0xff;
g&=0xff;
b&=0xff;
SetPixel(hdc,x,y,(b<<16)+(g<<8)+(r));
}
void line(int x1,int y1,int x2,int y2,int r,int g,int b)
{
SelectObject( hdc, CreatePen( PS_SOLID, 0, RGB(r,g,b) ) );

MoveToEx(hdc,x1,y1,0);
LineTo(hdc,x2,y2);
}


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
exit(0);
break;


case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
exit(0);
break;
}
break;


default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}





//int main()//vagy igy
//{ HINSTANCE hInstance=0;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX clas;
MSG msg;
int style;
RECT rect;
int time;
int elapsed;



clas.cbSize = sizeof(WNDCLASSEX);
clas.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
clas.lpfnWndProc = WindowProc;
clas.cbClsExtra = 0;
clas.cbWndExtra = 0;
clas.hInstance = hInstance;
clas.hIcon = NULL;
clas.hCursor = NULL;
clas.hbrBackground = (HBRUSH)(COLOR_WINDOW+3);
clas.lpszMenuName = NULL;
clas.lpszClassName = game_class;
clas.hIconSm = 0;


RegisterClassEx(&clas);


style = WS_CAPTION|WS_SYSMENU|WS_MAXIMIZEBOX|WS_MINIMIZEBOX;



game_window = CreateWindowEx(0, game_class, "demo", style,0,0, 1,1, NULL, NULL, hInstance, 0);

hdc=GetDC(game_window);



rect.left = rect.top = 0;
rect.right = x_size;
rect.bottom = y_size;


SetWindowPos(game_window, NULL, 0,0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE|SWP_NOZORDER);
ShowWindow(game_window, nCmdShow);


draw_function();
while(1)
{
while (PeekMessage(&msg, game_window, 0, 0, PM_NOREMOVE))
{
if (GetMessage(&msg, game_window, 0,0) < 0)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
};

return 0;
}

#endif

class float3
{
public:
inline float3(){};
inline float3(const float x,const float y,const float z) : x(x),y(y),z(z) {}
inline ~float3(){};
inline float3 operator+ (const float3 &f) const{
return float3(x+f.x,y+f.y,z+f.z);
}
inline float3 operator+ (const float f) const{
return float3(x+f,y+f,z+f);
}
inline void operator+= (const float3 &f){
x+=f.x;
y+=f.y;
z+=f.z;
}

inline float3 operator- (const float3 &f) const{
return float3(x-f.x,y-f.y,z-f.z);
}
inline float3 operator- () const{
return float3(-x,-y,-z);
}
inline float3 operator- (const float f) const{
return float3(x-f,y-f,z-f);
}
inline void operator-= (const float3 &f){
x-=f.x;
y-=f.y;
z-=f.z;
}

inline float3 operator* (const float3 &f) const{
return float3(x*f.x,y*f.y,z*f.z);
}
inline float3 operator* (const float f) const{
return float3(x*f,y*f,z*f);
}
inline void operator*= (const float3 &f){
x*=f.x;
y*=f.y;
z*=f.z;
}
inline void operator*= (const float f){
x*=f;
y*=f;
z*=f;
}

inline float3 operator/ (const float3 &f) const{
return float3(x/f.x,y/f.y,z/f.z);
}
inline float3 operator/ (const float f) const{
return float3(x/f,y/f,z/f);
}
inline void operator/= (const float3 &f){
x/=f.x;
y/=f.y;
z/=f.z;
}
inline void operator/= (const float f){
x/=f;
y/=f;
z/=f;
}

inline bool operator== (const float3 &f) const {
return ((x==f.x) && (y==f.y) && (z==f.z));
}
inline float& operator[] (const int t) {
return xyz[t];
}
inline const float& operator[] (const int t) const {
return xyz[t];
}

inline float dot (const float3 &f) const{
return x*f.x + y*f.y + z*f.z;
}
inline float3 cross(const float3 &f) const{
float3 ut;
ut.x=y*f.z-z*f.y;
ut.y=z*f.x-x*f.z;
ut.z=x*f.y-y*f.x;
return ut;
}
inline float distance(const float3 &f) const{
return (float)sqrt((x-f.x)*(x-f.x)+(y-f.y)*(y-f.y)+(z-f.z)*(z-f.z));
}
inline float distance2D(const float3 &f) const{
return (float)sqrt((x-f.x)*(x-f.x)+(z-f.z)*(z-f.z));
}
inline float Length() const{
return (float)sqrt(x*x+y*y+z*z);
}
inline float3& Normalize()
{
float l=(float)sqrt(x*x+y*y+z*z);
if(l!=0){
x=x/l;
y=y/l;
z=z/l;
}
return *this;
}
inline float SqLength() const{
return x*x+y*y+z*z;
}
inline float SqLength2D() const{
return x*x+z*z;
}
union {
struct{
float x;
float y;
float z;
};
struct{
float r;
float g;
float b;
};
float xyz[3];
};

static float maxxpos;
static float maxzpos;

bool CheckInBounds();
};


void linev(float3 par1,float3 par2,float3 color)
{
int x1=x_size/2+(int)par1.x;
int y1=y_size/2-(int)par1.y;
int x2=x_size/2+(int)par2.x;
int y2=y_size/2-(int)par2.y;
int r=(int)(color.r*255.0);
int g=(int)(color.g*255.0);
int b=(int)(color.b*255.0);


line(x1,y1,x2,y2,r,g,b);
}
void pixelv(float3 par1,float3 color)
{
int x1=x_size/2+(int)par1.x;
int y1=y_size/2-(int)par1.y;
int r=(int)(color.r*255.0);
int g=(int)(color.g*255.0);
int b=(int)(color.b*255.0);


pixel(x1,y1,r,g,b);
}




float3 lerp(float3 par1,float3 par2,float sc)
{
return par1 + (par2-par1)*sc;
}


float saturate(float par)
{
if(par>1.0) return 1.0;
if(par<0.0) return 0.0;
return par;
}

const int map_size=512;
float3 tex2D[4][map_size*map_size];

void form_to_tex2D(int xcenter,int ycenter,int size,int type)
{
size/=2;

for(int y=ycenter-size;y<ycenter+size;y++)
for(int x=xcenter-size;x<xcenter+size;x++)
{
int kx=abs(x-xcenter);
int ky=abs(y-ycenter);
float z=tex2D[0][y*map_size+x].r;

switch(type)
{
case 0:
z=0.0;
break;
case 1:
z=1.0;
break;
case 2:
z=1.0-(float)((kx>ky)? kx:ky)/50.0 ;
break;
case 3:
float rad=sqrt(kx*kx+ky*ky)/50.0;
if(rad<1.0)
z=1.0-rad ;
break;
}
tex2D[0][y*map_size+x]=float3(z,z,z);
}
}
void create_normalmap()
{
for(int y=0;y<map_size-1;y++)
for(int x=0;x<map_size-1;x++)
{
float scale=30.0;
float3 pixel =float3(x ,tex2D[0][y*map_size+x].r*scale, y);
float3 pixel_u=float3(x+1,tex2D[0][y*map_size+x+1].r*scale, y);
float3 pixel_v=float3(x ,tex2D[0][y*map_size+x+map_size].r*scale, y+1);

float3 temp=(pixel_u-pixel);
float3 normal=temp.cross(pixel_v-pixel);
normal.Normalize();

normal=normal*0.5+float3(0.5,0.5,0.5);

tex2D[1][y*map_size+x]=normal;
}
}
void mapsetup()
{
form_to_tex2D(map_size/2,map_size/2,map_size,1);
form_to_tex2D(map_size/2,map_size/2,map_size-100,0);

form_to_tex2D(180,180,100,2);
form_to_tex2D(320,320,100,2);
form_to_tex2D(180,320,100,3);
form_to_tex2D(320,180,100,3);

create_normalmap();
}

int get_texture_addr(float3 txcoord_)
{
return (((int)(txcoord_.y*map_size))&(map_size-1))*map_size + (((int)(txcoord_.x*map_size))&(map_size-1));
}

#define enable_lighting
//#define enable_parallax
//#define enable_parallax_shadow


void draw_function()

{
float3 LookAt = float3(0,0,0);
float3 Eyes = float3(350,250,130);
float3 ViewMatrix_z = LookAt-Eyes;
ViewMatrix_z.Normalize();
float3 ViewMatrix_x = ViewMatrix_z.cross(float3(0,1,0));
float3 ViewMatrix_y = ViewMatrix_x.cross(ViewMatrix_z);

float3 light_position = float3(-300,320,-200);
mapsetup();



for(int y=-y_size/2;y<y_size/2;y++)
for(int x=-x_size/2;x<x_size/2;x++)
{
float3 screen = float3(x,y,300);
float3 ray = ViewMatrix_x*screen.x + ViewMatrix_y*screen.y + ViewMatrix_z*screen.z;
ray.Normalize();

float3 plane_origo = float3(0,0,0);
float3 plane_normal = float3(0,10,0).Normalize();
float3 plane_tangent = plane_normal.cross(float3(0,0,1));
float3 plane_bitangent = plane_tangent.cross(plane_normal);


float dist = plane_normal.dot(plane_origo-Eyes) / plane_normal.dot(ray);
float3 plane_ray_intersection = Eyes + ray*dist;
float dist_=dist;

float map_scale=0.002;
float3 color = plane_ray_intersection*map_scale;
float3 temp = plane_ray_intersection - plane_origo;
float3 txcoord = float3(plane_tangent.dot(temp),plane_bitangent.dot(temp),0)*map_scale;





#ifdef enable_parallax
float3 plane_origo2 = plane_origo-plane_normal*80.0;
dist = plane_normal.dot(plane_origo2-Eyes) / plane_normal.dot(ray);
float3 plane_ray_intersection2 = Eyes + ray*dist;

temp = plane_ray_intersection2-plane_origo2;
float3 txcoord2 = float3(plane_tangent.dot(temp),plane_bitangent.dot(temp),0)*map_scale;
float3 txcoord3;


int parallax_step = 64;
float position = 1.0, delta_position=-1.0/(float)parallax_step;
for(int i=0;i<6;i++)
{
float3 height_map;

for(int j=0;j<parallax_step+1;j++)
{
txcoord3 = lerp(txcoord2,txcoord,position);
height_map = tex2D[0][get_texture_addr(txcoord3)];

if(position <= 0.0) break;
if(height_map.r > position) break;
position += delta_position;
}
if(position<0.0) {txcoord3 = txcoord2;break;}

if(height_map.r>position) {position -= delta_position;delta_position*=0.5;}
else
break;
}
plane_ray_intersection = lerp(plane_ray_intersection2,plane_ray_intersection,position);
txcoord=txcoord3;
#endif




float parallax_shadow=1;
#ifdef enable_parallax_shadow
float3 light_ray=plane_ray_intersection-light_position;
light_ray.Normalize();

dist = plane_normal.dot(plane_origo-light_position) / plane_normal.dot(light_ray);
float3 plane_ray_intersection4 = light_position + light_ray*dist;

dist = plane_normal.dot(plane_origo2-light_position) / plane_normal.dot(light_ray);
float3 plane_ray_intersection5 = light_position + light_ray*dist;

temp = plane_ray_intersection4 - plane_origo;
float3 txcoord4 = float3(plane_tangent.dot(temp),plane_bitangent.dot(temp),0)*map_scale;
temp = plane_ray_intersection5 - plane_origo;
float3 txcoord5 = float3(plane_tangent.dot(temp),plane_bitangent.dot(temp),0)*map_scale;



parallax_step=64;
delta_position = 1.0/(float)parallax_step;
position += delta_position;
{
float3 height_map;

for(int j=0;j<parallax_step+1;j++)
{
txcoord5 = lerp(txcoord5,txcoord4,position);
height_map = tex2D[0][get_texture_addr(txcoord5)];

if(position >= 1.0) break;
if(height_map.r > position) {parallax_shadow=0;break;}
position += delta_position;
}
}
#endif






int txcoord_hw = get_texture_addr(txcoord);
float3 normal_map = tex2D[1][txcoord_hw];
color = normal_map;



#ifdef enable_lighting
normal_map = (normal_map-float3(0.5,0.5,0.5))*(-2.0);
float3 normal = plane_tangent*normal_map.x + plane_normal*normal_map.y + plane_bitangent*normal_map.z;
float3 plane2light = light_position - plane_ray_intersection;
plane2light.Normalize();

float diffuse_light = saturate(plane2light.dot(normal));
color *= diffuse_light*parallax_shadow;

float3 eyes2plane = plane_ray_intersection - Eyes;
eyes2plane.Normalize();
float3 reflection_dir = eyes2plane - normal*normal.dot(eyes2plane)*2.0;
float3 light_color = float3(1.0,1.0,1.0);
float specular_light = pow(saturate(reflection_dir.dot(plane2light)),20.0);
color = lerp(color,light_color,specular_light)*parallax_shadow;
#endif


if(dist_<0.0) color = lerp(float3(0,1,1),float3(0,0,1),ray.y);//sky_color

pixelv(screen,color);
}
}

[ Szerkesztve ]

(#21) 3man


3man
csendes tag

A bitangent kifejezes inkabb a gorbek vilagahoz tartozik, a feluleteknel a binormal a helyesebb, emiatt ezt atneveztem.
A parallax arnyekban volt egy kis hiba, emiatt volt reces a szele, es bekerult az ambient hatterfeny is.

Igertem, hogy a parallax mukodeserol irok valamit. Ez a latszat ellenere egy eleg egyszeru algoritmus. Felveszek egy sikot 80 egyseg melyen a megadott sikhoz(plane-hez) kepest. Meghatarozom mindket feluleten a ray vektor metszespontjat. Ez a cos szog segitsegevel lehetseges. Ha a plane normal {0,1,0} akkor a metszespont tavolsaga a szemtol(eyes) dist=(plane_origo.y-eyes.y)/ray.y .
Hogy hol itt a cosinus? Ket vektor dot() szorzata, ha mindket vektor egysegvektor (normalizalt), akkor a koztuk levo szog cosinusat adja meg. A ray normalizalt, a plane normal pedig {0,1,0}, tehat a ray y koordinataja annak a szognek a cosinusa, amit az y koordinatatengellyel bezar a ray altal megadott egyenes.
Innen mar minden ertheto. cos(alfa)=ray.y=(plane_origo.y-eyes.y)/dist, mivel a sik, a dist*ray es az eyes.y egy derekszogu haromszoget ad.
Ezutan mar csak a kiindulopont(eyes) es a sugar(ray) ismereteben fel kell venni a metszespontot.
plane_ray_intersection = Eyes + ray*dist.

Ezekre a metszespontokra meghatarozhato egy u,v map koordinata a tangens ter segitsegevel.
float3 temp = plane_ray_intersection - plane_origo;
float3 txcoord = float3(plane_tangent.dot(temp),plane_binormal.dot(temp),0)*map_scale;
A plane_normal.dot(temp) ertelemszeruen kimarad, mert txcoord valojaban 2 dimenzios ahogy egy sik is, de az adott osztaly csak 3 d vektorokat kezel, emiatt most 3 dimenzios ez is.

A tovabbiakban a parallax kereso algoritmus ezt a ket txcoord erteket hasznalja es a position-t, ami 1-tol indul lefele delta_position lepesekkel. A cel, megkeresni azt a map poziciot, ahol a map altal tarol magassag(height) erteke ala megy a position, ami szinten egy magassagot jelol. Amikor a position =1 akkor a felso plane sikjaban van, amikor 0, akkor az alsoeban. A mapban tarolt magassag is 0-tol 1-ig valtozik. A 0 itt is az also plane-t jeloli. A position-nak meg egy funkcioja van, interpolal a ket txcoord kozott. Egyertelmu, hogy amikor fent van (1), akkor a felso plane txcoord-ja az aktualis, amikor lent (0), akkor az also plane-e.
Ez egy ferde egyenes hataroz meg a map tangens-tereben. Ha beleutkozik a mapba, akkor visszalep es csokkenti a delta_position erteket, majd tovabb keres.
Egy adott keresesi melyseg utan megall az algoritmus, es egy egyszeru interpolacioval meghatarozza az uj plane_ray_intersection-t, ami a ket plane kozt lesz valahol a 3d terben. Az txcoord3 pedig az uj map koordinata lesz.

A parallax arnyek ugyan igy mukodik, csak az irany nem a ray, hanem a light_ray, es az eyes helyett az iranyvektor kiindulasi pontja a light_position, a fenyforras pozicioja. Nem a felso (1) poziciobol indul a kereses, hanem onnan, amit az elobbi algoritmus mar kiszamolt. Innen megy a felso sik fele addig, amig bele nem utkozik a map valamelyik pixelebe.
if(height_map.r > position) {parallax_shadow=0;break;}
Ekkor az aktualis pixel arnyekban lesz, a szorzoja 0.
Magyarul csak a txcoord modosul a kamera iranyatol fuggoen, es ez adja azt a hatast, mintha egy 3 dimenzios testet neznenk. Ezert parallax az algoritmus neve.

A zold vektoros rajz a displacement mapping technikat szemleltetne. Ez haromszogekre (most negyszogek) epul, es a height map, amit az elobb a parallax hasznalt, most a racs egyik koordinatajat(a magassagot) fogja meghatarozni.

const int map_size=512;
float3 tex2D[4][map_size*map_size];

void form_to_tex2D(int xcenter,int ycenter,int size,int type)
{
size/=2;

for(int y=ycenter-size;y<ycenter+size;y++)
for(int x=xcenter-size;x<xcenter+size;x++)
{
int kx=abs(x-xcenter);
int ky=abs(y-ycenter);
float z=tex2D[0][y*map_size+x].r;
float rad;

switch(type)
{
case 0:
z=0.0;
break;
case 1:
z=1.0;
break;
case 2:
z=1.0-(float)((kx>ky)? kx:ky)/50.0 ;
break;
case 3:
rad=sqrt(kx*kx+ky*ky)/50.0;
if(rad<1.0)
z=1.0-rad ;
break;
case 4:
rad=sqrt(kx*kx+ky*ky)/50.0;
if(rad<1.0)
z=sqrt(1.0-rad*rad );
break;
}
tex2D[0][y*map_size+x]=float3(z,z,z);
}
}
void create_normalmap()
{
for(int y=0;y<map_size-1;y++)
for(int x=0;x<map_size-1;x++)
{
float scale=30.0;
float3 pixel =float3(x ,tex2D[0][y*map_size+x].r*scale, y);
float3 pixel_u=float3(x+1,tex2D[0][y*map_size+x+1].r*scale, y);
float3 pixel_v=float3(x ,tex2D[0][y*map_size+x+map_size].r*scale, y+1);

float3 temp=(pixel_u-pixel);
float3 normal=temp.cross(pixel_v-pixel);
normal.Normalize();

normal=normal*0.5+float3(0.5,0.5,0.5);

tex2D[1][y*map_size+x]=normal;
}
}
void mapsetup()
{
form_to_tex2D(map_size/2,map_size/2,map_size,1);
form_to_tex2D(map_size/2,map_size/2,map_size-100,0);

form_to_tex2D(180,180,100,2);
form_to_tex2D(320,320,100,2);
form_to_tex2D(180,320,100,3);
form_to_tex2D(320,180,100,4);

create_normalmap();
}

int get_texture_addr(float3 txcoord_)
{
return (((int)(txcoord_.y*map_size))&(map_size-1))*map_size + (((int)(txcoord_.x*map_size))&(map_size-1));
}

#define enable_lighting
#define enable_parallax
#define enable_parallax_shadow

#define projection
//#define sky_color_reflection





void draw_function()

{
float3 LookAt = float3(0,0,0);
float3 Eyes = float3(350,350,130);
float3 ViewMatrix_z = LookAt-Eyes;
ViewMatrix_z.Normalize();
float3 ViewMatrix_x = ViewMatrix_z.cross(float3(0,1,0));
float3 ViewMatrix_y = ViewMatrix_x.cross(ViewMatrix_z);

float3 light_position = float3(-300,250,-200);
mapsetup();




//http://en.wikipedia.org/wiki/Displacement_mapping
int step=8;
for(int y=-map_size*2;y<map_size*2;y+=step)
for(int x=-map_size*2;x<map_size*2;x+=step)
{
int mask=map_size*map_size-1;//2^x !
float scale=80.0;
//displacement normal iranya =float3(0,1,0);
float3 triangle_vec1=float3(x ,-scale +tex2D[0][(y*map_size+x)&mask].r*scale, y);
float3 triangle_vec2=float3(x+step,-scale +tex2D[0][(y*map_size+x+step)&mask].r*scale, y);
float3 triangle_vec3=float3(x ,-scale +tex2D[0][(y*map_size+x+map_size*step)&mask].r*scale, y+step);


float3 screen_coord1;
float3 screen_coord2;
float3 screen_coord3;

triangle_vec1-=Eyes;
triangle_vec2-=Eyes;
triangle_vec3-=Eyes;

screen_coord1.x=ViewMatrix_x.dot(triangle_vec1);
screen_coord1.y=ViewMatrix_y.dot(triangle_vec1);
screen_coord1.z=ViewMatrix_z.dot(triangle_vec1);

screen_coord2.x=ViewMatrix_x.dot(triangle_vec2);
screen_coord2.y=ViewMatrix_y.dot(triangle_vec2);
screen_coord2.z=ViewMatrix_z.dot(triangle_vec2);

screen_coord3.x=ViewMatrix_x.dot(triangle_vec3);
screen_coord3.y=ViewMatrix_y.dot(triangle_vec3);
screen_coord3.z=ViewMatrix_z.dot(triangle_vec3);

#ifdef projection
scale=1.0/300.0;
screen_coord1.x/=(screen_coord1.z*scale);
screen_coord1.y/=(screen_coord1.z*scale);
screen_coord2.x/=(screen_coord2.z*scale);
screen_coord2.y/=(screen_coord2.z*scale);
screen_coord3.x/=(screen_coord3.z*scale);
screen_coord3.y/=(screen_coord3.z*scale);
#endif

if(screen_coord1.z>50.0)
if(screen_coord2.z>50.0)
if(screen_coord3.z>50.0)
{
linev(screen_coord1,screen_coord2,float3(0,1,0));
linev(screen_coord1,screen_coord3,float3(0,1,0));
}
}








for(int y=-y_size/2;y<y_size/2;y++)
for(int x=-x_size/2;x<x_size/2;x++)
{
float3 screen = float3(x,y,300);
float3 ray = ViewMatrix_x*screen.x + ViewMatrix_y*screen.y + ViewMatrix_z*screen.z;
ray.Normalize();

float3 plane_origo = float3(0,0,0);
float3 plane_normal = float3(0,10,0).Normalize();
float3 plane_tangent = plane_normal.cross(float3(0,0,1));
float3 plane_binormal = plane_tangent.cross(plane_normal);


float dist = plane_normal.dot(plane_origo-Eyes) / plane_normal.dot(ray);
float3 plane_ray_intersection = Eyes + ray*dist;
float dist_=dist;

float map_scale=1.0/(float)map_size;
float3 color = plane_ray_intersection*map_scale;
float3 temp = plane_ray_intersection - plane_origo;
float3 txcoord = float3(plane_tangent.dot(temp),plane_binormal.dot(temp),0)*map_scale;





#ifdef enable_parallax
float3 plane_origo2 = plane_origo-plane_normal*80.0;
dist = plane_normal.dot(plane_origo2-Eyes) / plane_normal.dot(ray);
float3 plane_ray_intersection2 = Eyes + ray*dist;

temp = plane_ray_intersection2-plane_origo2;
float3 txcoord2 = float3(plane_tangent.dot(temp),plane_binormal.dot(temp),0)*map_scale;
float3 txcoord3;


int parallax_step = 64;
float position = 1.0, delta_position=-1.0/(float)parallax_step;
for(int i=0;i<6;i++)
{
float3 height_map;

for(int j=0;j<parallax_step+1;j++)
{
txcoord3 = lerp(txcoord2,txcoord,position);
height_map = tex2D[0][get_texture_addr(txcoord3)];

if(position <= 0.0) break;
if(height_map.r > position) break;
position += delta_position;
}
if(position<0.0) {txcoord3 = txcoord2;break;}

if(height_map.r>position) {position -= delta_position;delta_position*=0.5;}
else
break;
}
plane_ray_intersection = lerp(plane_ray_intersection2,plane_ray_intersection,position);
txcoord=txcoord3;
#endif




float parallax_shadow=1;
#ifdef enable_parallax_shadow
float3 light_ray=plane_ray_intersection-light_position;
light_ray.Normalize();

dist = plane_normal.dot(plane_origo-light_position) / plane_normal.dot(light_ray);
float3 plane_ray_intersection4 = light_position + light_ray*dist;

dist = plane_normal.dot(plane_origo2-light_position) / plane_normal.dot(light_ray);
float3 plane_ray_intersection5 = light_position + light_ray*dist;

temp = plane_ray_intersection4 - plane_origo;
float3 txcoord4 = float3(plane_tangent.dot(temp),plane_binormal.dot(temp),0)*map_scale;
temp = plane_ray_intersection5 - plane_origo;
float3 txcoord5 = float3(plane_tangent.dot(temp),plane_binormal.dot(temp),0)*map_scale;



parallax_step=64;
delta_position = 1.0/(float)parallax_step;
position += delta_position*2;
{
float3 height_map;

for(int j=0;j<parallax_step+1;j++)
{
float3 txcoord6 = lerp(txcoord5,txcoord4,position);
height_map = tex2D[0][get_texture_addr(txcoord6)];

if(position >= 1.0) break;
if(height_map.r > position) {parallax_shadow=0;break;}
position += delta_position;
}
}
#endif






int txcoord_hw = get_texture_addr(txcoord);
float3 normal_map = tex2D[1][txcoord_hw];
color = normal_map;



#ifdef enable_lighting
normal_map = (normal_map-float3(0.5,0.5,0.5))*(-2.0);
float3 normal = plane_tangent*normal_map.x + plane_normal*normal_map.y + plane_binormal*normal_map.z;
float3 plane2light = light_position - plane_ray_intersection;
plane2light.Normalize();

float ambient=0.25;
float diffuse_light = saturate(plane2light.dot(normal));
color *= (diffuse_light*parallax_shadow*(1.0-ambient)+ambient);

float3 eyes2plane = plane_ray_intersection - Eyes;
eyes2plane.Normalize();
float3 reflection_dir = eyes2plane - normal*normal.dot(eyes2plane)*2.0;
float3 light_color = float3(1.0,1.0,1.0);
float specular_light = pow(saturate(reflection_dir.dot(plane2light)),20.0);
color = lerp(color,light_color,specular_light*parallax_shadow);
#endif


#ifdef sky_color_reflection
float3 sky_color = lerp(float3(0,0,1),float3(0,0,0),fabs(reflection_dir.y))*0.3;
color += sky_color;
color=saturate(color);
#endif

if(dist_<0.0) color = lerp(float3(0,0,1),float3(0,1,1),ray.y);//sky_color


pixelv(screen,color);
}



}

[ Szerkesztve ]

(#22) 3man


3man
csendes tag

Erdemes az egeszet bemasolni, mert vannak benne ujdonsagok, mint pl ez:

case 4:
rad=sqrt(kx*kx+ky*ky)/50.0;
if(rad<1.0)
z=sqrt(1.0-rad*rad );
break;

Egy felgombot rajzol a mapba.

(#23) 3man


3man
csendes tag

linuxon igy fordul le a program
cc ww.cpp -lm /usr/lib/libX*.a

(#24) 3man


3man
csendes tag

Igazandibol az alapokat leirtam, nem tudom mit kellene reszleteznem, mi az ami nem ertheto igazan. Ha lesz kerdes, akkor majd tudni fogom. Addig szunet.

(#25) 3man


3man
csendes tag

Vektorokkal ugyan ugy fel lehet irni egyenleteket, mint a skalarokkal.

Erre egy pelda, a raytrace technikanal hasznalt egyenes-gomb metszespont meghatarozasa.

Az elso egyenletbol lehet kiindulni. Ez annyit mond, hogy ha az eyes pontbol ray iranyban t tavolsagot teszek meg, akkor egy olyan pontba jutok, ami a ball ponttol r tavolsagra van, vagyis egy olyan gomb feluleten,

ami r sugaru es a kozeppontja a terben a ball helyvektor.

sqrt(dot( eyes+ray*t - ball)) = r

Az egyenletben r^2 szerepel, ha nincs gyokvonas, hiszen a dot() a vektor hosszanak a negyzetet adja, ha a vektort onmagaval szorzom.

A kovetkezokben egy uj vektort bevezetve egyszerusitem az egyenletet. {ball2eyes}, majd felirom a pontszorzatot reszletesen.

Innentol kezdve egyszeru egyenletrendezes jon, amivel egy masodfoku egyenlethez jutok. Innen mar nem is reszletezem, ezt mar illik ismerni.

Ket megoldasa van az egyenletnek, nyilvan az egyenes ha metszi a gombot, akkor ket ponton metszi.

Ball ray intersetion:

dot(eyes+ray*t-ball) = r*r

ball2eyes=eyes-ball

dot(ball2eyes+ray*t) = r*r

(ball2eyes.x+ray.x*t)*(ball2eyes.x+ray.x*t) + (ball2eyes.y+ray.y*t)*(ball2eyes.y+ray.y*t) + (ball2eyes.z+ray.z*t)*(ball2eyes.z+ray.z*t) = r*r

ball2eyes.x*ball2eyes.x + 2*ray.x*t*ball2eyes.x + ray.x*ray.x*t*t +

ball2eyes.y*ball2eyes.y + 2*ray.y*t*ball2eyes.y + ray.y*ray.y*t*t +

ball2eyes.z*ball2eyes.z + 2*ray.z*t*ball2eyes.z + ray.z*ray.z*t*t = r*r

t*t*(ray.x*ray.x + ray.y*ray.y + ray.z*ray.z) +

t*(2*ray.x*ball2eyes.x + 2*ray.y*ball2eyes.y + 2*ray.z*ball2eyes.z) +

(-r*r + ball2eyes.x*ball2eyes.x + ball2eyes.y*ball2eyes.y + ball2eyes.z*ball2eyes.z ) =0

a=(ray.x*ray.x + ray.y*ray.y + ray.z*ray.z);

b=(2.0*ray.x*ball2eyes.x + 2.0*ray.y*ball2eyes.y + 2.0*ray.z*ball2eyes.z) ;

c=(-r*r + ball2eyes.x*ball2eyes.x + ball2eyes.y*ball2eyes.y + ball2eyes.z*ball2eyes.z ) ;

Rovidebben felirva:

a=dot(ray,ray);

b=dot(ray,ball2eyes)*2.0 ;

c=dot(ball2eyes,ball2eyes)-r*r;

t=((+ vagy -)b+sqrt(b*b-4*a*c))/(2*a)

ball_ray_intersection = eyes + ray*t

D=b*b-4*a*c

ha D>=0 akkor metszi az egyenes a gombot.

[ Szerkesztve ]

(#26) 3man


3man
csendes tag

Talan igy jobb

Ball ray intersetion:

dot(eyes+ray*t-ball) = r*r

ball2eyes=eyes-ball

dot(ball2eyes+ray*t) = r*r



(ball2eyes.x+ray.x*t)*(ball2eyes.x+ray.x*t) + (ball2eyes.y+ray.y*t)*(ball2eyes.y+ray.y*t) + (ball2eyes.z+ray.z*t)*(ball2eyes.z+ray.z*t) = r*r



ball2eyes.x*ball2eyes.x + 2*ray.x*t*ball2eyes.x + ray.x*ray.x*t*t +

ball2eyes.y*ball2eyes.y + 2*ray.y*t*ball2eyes.y + ray.y*ray.y*t*t +

ball2eyes.z*ball2eyes.z + 2*ray.z*t*ball2eyes.z + ray.z*ray.z*t*t = r*r



t*t*(ray.x*ray.x + ray.y*ray.y + ray.z*ray.z) +

t*(2*ray.x*ball2eyes.x + 2*ray.y*ball2eyes.y + 2*ray.z*ball2eyes.z) +

(-r*r + ball2eyes.x*ball2eyes.x + ball2eyes.y*ball2eyes.y + ball2eyes.z*ball2eyes.z ) =0





a=(ray.x*ray.x + ray.y*ray.y + ray.z*ray.z);

b=(2.0*ray.x*ball2eyes.x + 2.0*ray.y*ball2eyes.y + 2.0*ray.z*ball2eyes.z) ;

c=(-r*r + ball2eyes.x*ball2eyes.x + ball2eyes.y*ball2eyes.y + ball2eyes.z*ball2eyes.z ) ;



Rovidebben felirva:

a=dot(ray,ray);

b=dot(ray,ball2eyes)*2.0 ;

c=dot(ball2eyes,ball2eyes)-r*r;



t=((+ vagy -)b+sqrt(b*b-4*a*c))/(2*a)

ball_ray_intersection = eyes + ray*t





D=b*b-4*a*c

ha D>=0 akkor metszi az egyenes a gombot.

Útvonal

Fórumok  »  Szoftverfejlesztés  »  Vektorok es matrixok (téma lezárva)
Copyright © 2000-2024 PROHARDVER Informatikai Kft.