Autor Wątek: Jak wyznaczyć teksel w który trafił promień? (raytracing)  (Przeczytany 1716 razy)

Offline Demon

  • Użytkownik

# Czerwiec 06, 2007, 13:46:21
Jeżeli powiedzmy mam trójkąt złożony z punktów P1, P2, P3 i odpowiednio wyznaczone koordynaty tekstury dla każdego punktu [u1, v1], [u2, v2], [u3, v3], punkt w który trafiłem to R i jestem pewien że leży on na trójkącie P1 P2 P3, promień który trafił w punkt R ma kierunek V
Jak wyznaczyć teksel dla punktu R?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Areal

  • Użytkownik

# Czerwiec 06, 2007, 16:38:03
Kod: (matlab) [Zaznacz]
P1+a*(P2-P1)+b*(P3-P1)=R
Rozwiązujesz powyższe równanie szukając a oraz b.

Teraz wyznaczasz szukane [u,v] ze wzoru:
Kod: (matlab) [Zaznacz]
[u,v]=[u1,v1]+a*([u2,v2]-[u1,v1])+b*([u3,v3]-[u1,v1])
Pisane z głowy, więc nietestowane.
« Ostatnia zmiana: Czerwiec 06, 2007, 16:44:13 wysłana przez Areal »

Offline Reg

  • Administrator
    • Adam Sawicki - Home Page

# Czerwiec 06, 2007, 19:16:20
Po pierwsze, nie koloruj tekstu w postach, bo nie każdy używa tej samej skóry na forum, a żółty tekst na białym tle niefajnie się czyta :)

Po drugie, to:
Cytuj
promień który trafił w punkt R ma kierunek V
Promień ma jakiś stały kierunek niezależnie czy trafił, czy nie trafił :) Miałeś na myśli chyba raczej punkt przecięcia tego promienia z tym trójkątek.

Dość czepiania się, teraz odpowiedź:
Masz pozycje wierzchołków trójkąta P1, P2, P3, masz punkt przecięcia się promienia z tym trójkątem V, masz współrzędne tekstury wierzchołków tego trójkąta [u1, v1], [u2, v2], [u3, v3], chcesz znaleźć współrzędne tekstury w miejscu przecięcia, dajmy na to [uV, vV].

Głowy nie daję, ale na pierwszy rzut oka musisz:
1. Poznać i zrozumieć Współrzędne Barycentryczne (Barycentric Coordinates).
2. Policzyć to tak:
a) mając P1, P2, P3 i V, wyliczyć współrzędne barycentryczne B1, B2, B3.
b) mając B1, B2, B3 i współrzędne tekstury [u1, v1], [u2, v2], [u3, v3], wyliczyć [uV, vV].
Słowem, przejść z przestrzeni pozycji w świecie do przestrzeni wspórzędnych tekstury używąc jako pośrednika tych współrzędnych barycentrycznych.

Offline Demon

  • Użytkownik

# Czerwiec 07, 2007, 00:30:23
Po drugie, to:
Cytuj
promień który trafił w punkt R ma kierunek V
Promień ma jakiś stały kierunek niezależnie czy trafił, czy nie trafił :) Miałeś na myśli chyba raczej punkt przecięcia tego promienia z tym trójkątek.

Nie, miałem na myśli kierunek promienia rzucanego który trafił w punkt R, w końcu promień to wektor, a wektor ma kierunek.

Areal z tego że są tylko 2 niewiadome wnioskuję że to się nie sprawdzi, ponieważ mogę wyliczyć a i b na kilka sposobów, robiąc 2 równanie z x-ów i y-ów lub z x-ów i z-ów lub y-ów i z-ów, zastanawiam się czy jakbym to rozszerzył do takiego równania:
[P1+a*(P2-P1)]+[P2+b*(P3-P2)]+(P3+c*(P1-P3))=R

[u,v]=([u1,v1]+a*([u2,v2]-[u1,v1]))+([u2,v2]+b*([u3,v3]-[u2,v2]))+([u3,v3]+c*([u1,v1]-[u3,v3]))

to czy to by miało jakiś sens, niby są 3 niewiadome i 3 równania można ułożyć, więc jest tylko 1 rozwiązanie. Tak czy siak czuję że zastosuję to o czym napisał Reg, wyczytałem że mnóstwo raytracerów używa właśnie koordynatów barycentrycznych.
« Ostatnia zmiana: Czerwiec 07, 2007, 00:44:25 wysłana przez Demon »

Offline Areal

  • Użytkownik

# Czerwiec 07, 2007, 08:09:10
Niedokładnie przeczytałem i uznałem, że punkt R należy do powierzchni trójkąta. Ale skoro V tylko przechodzi przez R to trzeba przerobić na:
P1+a*(P2-P1)+b*(P3-P1)=R+c*V (1)
Poniższy wzór pozostaje w starej postaci:
[u,v]=[u1,v1]+a*([u2,v2]-[u1,v1])+b*([u3,v3]-[u1,v1]) (2)
Rozwiązanie wzóru (1) można rozumieć jako poszukiwanie "ile należy iść" wzdłuż wektorów (P2-P1) oraz (P3-P1) wychodząc od punktu P1, tak aby spotkać się na powierzchni trójkąta z promieniem V, który idzie od punktu R.
Wzór (2) wykorzystuje to "ile należy iść" do znalezienia współrzędnych wychodząc od współrzędnych punktu P1.

Powyższe wzory sprawdzone w Mathcadzie. Działają poprawnie.

Offline Demon

  • Użytkownik

# Czerwiec 07, 2007, 09:56:13
Areal - punkt R należy do trójkąta, chodzi mi o to że jak wierzchołki trójkąta mają wszystkie współrzędne x, y, lub z takie same(czyli trójkąt leży na płaszczyźnie x, y, lub z to wtedy trzeba sprawdzać czy tak jest i używać odpowiedniego wzoru, ponieważ twój wzór ma tylko 2 niewiadome to znaczy że można wyliczyć a, b układając tylko 2 równania, a kiedy np wybierzemy że wyliczamy z x, y a trójkąt będzie leżał na płaszczyźnie y lub x, to wtedy nie da się wyliczyć a i b, bo trzeba zamiast liczenia ze współrzędnych x lub y (tych współrzędnych które są jednakowe dla wszystkich wierzchołków) wyliczyć ze współrzędnej z, jednak trzeba sprawdzać czy trójkąt nie leży na jakiejś płaszczyźnie i dlatego nie wiem co będzie szybsze czy twój sposób czy koordynaty barycentryczne.

//EDIT
Na stronie wikipedii http://en.wikipedia.org/wiki/Barycentric_coordinates_(mathematics) znalazłem info o koordynatach barycentrycznych i na samym dole jest taka notka:

Note that this formulation breaks down when A and B are equal to 0, which is an indication that the triangle is perpendicular to the x axis. In those cases, simply switch A with D, B with E, C with F, and the equations for λ1 and λ2 will still work.

Czyli w koordynatach barycentrycznych też trzeba sprawdzać taki przypadek szczególny,
« Ostatnia zmiana: Czerwiec 07, 2007, 10:15:06 wysłana przez Demon »

Offline Areal

  • Użytkownik

# Czerwiec 07, 2007, 11:46:03
Po poprawce, która zaproponowałem jest układ 3 równań z 3 niewiadomymi (a,b,c). Można go rozwiązać np. metodą wyznaczników. Oczywiście należy sprawdzić, czy wartość wyznacznika jest różna od zera (gdy jest równy zero znaczy, że któreś z wektorów są współliniowe, bo np. trójkąt jest zdegenerowany lub wektor V leży w płaszczyźnie trójkąta).

Wzory te stosowałem w swoich projektach (m.in. w bibliotece topologicznej do interpolowania wysokości między węzłami) i wszystko śmigało :)
« Ostatnia zmiana: Czerwiec 07, 2007, 12:03:01 wysłana przez Areal »

Offline ziomber

  • Użytkownik

  • Zbanowany
# Czerwiec 07, 2007, 21:34:31
wyznacz srodek polygonu, i masz 4 cwiartki takie jakie są normalnie 4 ćwiartki :] zaczynasz od punktu 0,5 / 0,5

I to są niby wektory od środka do punktu

A to ci nic nie pomoze, ale to jest cos podobnie identycznego ;d (dodatkowo ta funkcja ladnie i szybko rysuje :d)



function GET_PLANE_POINT_LIGHT(model : tglarrayselectionmodel; normal : t3dpoint; faceindex : integer;
 lights :  tnoxx_gllight;var facepoint : array of t3dpoint;plen : integer; var pakiet : tpakiet_kolizyjny) : textpoint;


var
wektor : t3dpoint;
distance : single;   distance3 : single;
distance2 : single; //dystans face'a ten wlasciwy
i,j,n : integer;
LIGHT_COLLISION_IN_FACE : boolean;
LIGHT_LINE : tline;
DELTA   : single;
A,B,C   : single;
KTOREWIERZCHOLKI        : array of boolean;
newverts                : array of t3dpoint;
M1             : array of single;
M2             : array of single;
M3             : array of single;
MIN,MAX        : t3dpoint;
coords : array of textpoint;
coordsPRzed : array of textpoint;
PIERWSZY : t3dpoint;
OSTATNI  : t3dpoint;
srodek : t3dpoint;
inny : t3dpoint;
eC      : integer;
ODLEGLOSC_D : single;
pozycja_swiatla : gdziejestswiatlo;
light_v4 : array [0..3] of t3dpoint;
light_v : array of t3dpoint;
FACECENTERPOINT : t3dpoint;
render_mode : byte;

//LINE
X,Y,Z : single;  //trzeba ustawić kółko tak jak jest ustawiony prymityw od boku
A1,B1,C1 : single;
x1,x2 : single;
mode : byte;
znaks : integer;
allinradius : byte; //0 falkse 1 true 3 inne    //wszystkie vertexy w zasiegu swiatla
allinradius2 : boolean;  //wszystkie vertexy poza zasiegiem, a promien przebija face
rysuj : boolean;
tp : t3dpoint;
lightsi : integer;
size : single;
jestemwewnatrz : boolean;
begin
jestemwewnatrz :=true;
rysuj := false;
eC := length(facepoint);
if (normal.x > 1) or (normal.y > 1) or (normal.z > 1) or (normal.x < -1) or (normal.y < -1) or (normal.z < -1) then
normal := normalize(normal);
{distance := getplaned(normal,lights[0].pos);
distance2 := getplaned(normal,facepoint[0]);          }

allinradius := 1;
allinradius2 := true;



znaks := 1;
if classifyapointagainstaplane(lights.pos,normal,getplaned(normal,facepoint[0])) = isfront  then znaks := -1;


WEKTOR.x := (NORMAL.x*lights.radius*1000);//*distance*10000;
WEKTOR.y := (NORMAL.y*lights.radius*1000);//*distance*10000;
WEKTOR.z := (NORMAL.z*lights.radius*1000);//*distance*10000;

A := lights.radius*sqrt(2)/2;

FACECENTERPOINT := t3dpointsum(facepoint);

tp.x := lights.pos.x+znaks*wektor.x;
tp.y := lights.pos.y+znaks*wektor.y;
tp.z := lights.pos.z+znaks*wektor.z;

//showmessage(floattostr(wektor.x)+'  '+floattostr(wektor.y)+'  '+floattostr(wektor.z));

srodek := GET_PINTERSECTION_LINE_PLANE(model.COLARRAYS[faceindex],
[lights.pos,tp],
model.facelength[faceindex]);

              {
if intersectedpolygon(model.COLARRAYS[faceindex],
[lights[0].pos,vectors_add(wektor,lights[0].pos)],
model.facelength[faceindex]) = true then begin

for n:=0 to eC-1 do
if n3ddistance(facepoint[n],srodek) < A then allinradius2 := false;
end;       }


setlength(coords,eC);

pierwszy.y :=  srodek.Y-A;
pierwszy.x :=  srodek.X-A;
pierwszy.z :=  srodek.Z-A;


//inny := GET_PINTERSECTION_LINE_PLANE(normal,distance, WEKTOR,pierwszy);

ODLEGLOSC_D := n3dDISTANCE_FACE_POINT(normal,facepoint[0],lights.pos);
rysuj := true;
render_mode := 0;
mode := 0;



//allinradius := 1;
for n:=0 to eC-1 do
if n3ddistance(facepoint[n],lights.pos) > lights.radius then  begin
 rysuj := false;
allinradius := 0;
end;
//.if jestemwewnatrz then allinradius := 0;




if allinradius = 0 then begin
if ec > 6 then exit;
// glPushMatrix();

end;


//jak face jest wewnatrz zasiegu swiatla
if allinradius = 1 then begin



glcolor4fv(@lights.rgba);
//draw_QUAD(normal,srodek,getplaned(normal,facepoint[0]));
//exit;

for n:=0 to eC-1 do
begin
//distance3 := n3ddistance(facepoint[i],lights[0].pos);


if (abs(NORMAL.X) >= abs(NORMAL.Y)) and (abs(NORMAL.X) >= abs(NORMAL.Z)) then   //DLA X -> ZY  Y = X
begin//   Y
mode := 0;
if  model.arrays[faceindex][n].vertex3f.z < srodek.z then
coords[n].x := 0.5+abs(model.arrays[faceindex][n].vertex3f.z-srodek.z)/(2*a) else
coords[n].x := 0.5-abs(srodek.z-model.arrays[faceindex][n].vertex3f.z)/(2*a);

if  model.arrays[faceindex][n].vertex3f.y < srodek.y then
coords[n].y := 0.5+abs(srodek.y-model.arrays[faceindex][n].vertex3f.y)/(2*a) else
coords[n].y := 0.5-abs(model.arrays[faceindex][n].vertex3f.y-srodek.y)/(2*a);
                                                                               
//coords[n].y := (pierwszy.Y-model.arrays[faceindex][n].vertex3f.Y)/(a);      }


if  model.arrays[faceindex][n].vertex3f.y < srodek.y then
coords[n].x := 0.5+abs(model.arrays[faceindex][n].vertex3f.y-srodek.y)/(2*a) else
coords[n].x := 0.5-abs(srodek.y-model.arrays[faceindex][n].vertex3f.y)/(2*a);

if  model.arrays[faceindex][n].vertex3f.z < srodek.z then
coords[n].y := 0.5+abs(srodek.z-model.arrays[faceindex][n].vertex3f.z)/(2*a) else
coords[n].y := 0.5-abs(model.arrays[faceindex][n].vertex3f.z-srodek.z)/(2*a);
end;

if (abs(NORMAL.Y) >= abs(NORMAL.X)) and (abs(NORMAL.Y) >= abs(NORMAL.Z)) then   //DLA Y -> ZX Y=Z
begin//   Y
mode := 1;

if  model.arrays[faceindex][n].vertex3f.x < srodek.x then
coords[n].x := 0.5+abs(model.arrays[faceindex][n].vertex3f.x-srodek.x)/(2*a) else
coords[n].x := 0.5-abs(srodek.x-model.arrays[faceindex][n].vertex3f.x)/(2*a);

if  model.arrays[faceindex][n].vertex3f.Z < srodek.z then
coords[n].y := 0.5+abs(srodek.z-model.arrays[faceindex][n].vertex3f.z)/(2*a) else
coords[n].y := 0.5-abs(model.arrays[faceindex][n].vertex3f.z-srodek.z)/(2*a);
end;                                                     


if (abs(NORMAL.Z) >= abs(NORMAL.X)) and (abs(NORMAL.Z) >= abs(NORMAL.Y)) then   //DLA Z -> XY   Z=Y
begin//   Y

mode := 2;
if  model.arrays[faceindex][n].vertex3f.x < srodek.x then
coords[n].x := 0.5+abs(model.arrays[faceindex][n].vertex3f.x-srodek.x)/(2*a) else
coords[n].x := 0.5-abs(srodek.x-model.arrays[faceindex][n].vertex3f.x)/(2*a);

if  model.arrays[faceindex][n].vertex3f.y < srodek.y then
coords[n].y := 0.5+abs(srodek.y-model.arrays[faceindex][n].vertex3f.y)/(2*a) else
coords[n].y := 0.5-abs(model.arrays[faceindex][n].vertex3f.y-srodek.y)/(2*a);
end;


end;  //koniec loopa
end;  //eof if not allinradius then

{if allinradius = 0 then begin
rysuj := true;
render_mode := 1;
size := abs((lights.radius-n3ddistance(srodek,lights.pos)));
if (abs(NORMAL.Z) >= abs(NORMAL.X)) and (abs(NORMAL.Z) >= abs(NORMAL.Y)) then   //DLA Z -> XY   Z=Y
begin//   Y
//createsphere(srodek.x-size,srodek.y-size,
//get_z_from_XY((srodek.x-size)*normal.x,(srodek.y-size)*normal.y,normal.z,getplaned(normal,facepoint[0])),1,4);
glbegin(GL_QUADS);
glTexCoord2f(0,0);
glvertex3f(srodek.x-size,srodek.y-size,
get_z_from_XY((srodek.x-size)*normal.x,(srodek.y-size)*normal.y,normal.z,getplaned(normal,facepoint[0])));
glTexCoord2f(1,0);

glvertex3f(srodek.x-size,srodek.y+size,
get_z_from_XY((srodek.x-size)*normal.x,(srodek.y+size)*normal.y,normal.z,getplaned(normal,facepoint[0])));
glTexCoord2f(1,1);
glvertex3f(srodek.x+size,srodek.y+size,
get_z_from_XY((srodek.x+size)*normal.x,(srodek.y+size)*normal.y,normal.z,getplaned(normal,facepoint[0])));

glTexCoord2f(0,1);
glvertex3f(srodek.x+size,srodek.y-size,
get_z_from_XY((srodek.x+size)*normal.x,(srodek.y-size)*normal.y,normal.z,getplaned(normal,facepoint[0])));
glend;
end;


end;
         }


if rysuj then begin
glbindtexture(GL_TEXTURE_2d,NOXX_LIGHT_TEXTURE);

matrixtoglenable(model.face[faceindex].matrix);


pakiet[0].x := coords[0].x;
pakiet[0].y := coords[0].y;

pakiet[1].x := coords[1].x;
pakiet[1].y := coords[1].y;

pakiet[2].x := coords[2].x;
pakiet[2].y := coords[2].y;

pakiet[3].x := coords[3].x;
pakiet[3].y := coords[3].y;
//unit1.mainfont

for n:=0 to high(coords) do
begin

glvertex3fv(@model.arrays[faceindex][n].vertex3f);
gltexcoord2f(coords[n].x,coords[n].y);
end;

glend();

end;
« Ostatnia zmiana: Czerwiec 07, 2007, 21:39:38 wysłana przez ziomber »