obroty w opengl

0

Mamy obiekt, który wiruje sobie dookoła jakiejś osi, np.: 1,1,1.

I gdy to obracam wprost za pomocą glRotate(kąt, 1,1,1);
wówczas światło też się obraca...

Jak to rysować, żeby światło stało w miejscu?
Np. ustawiam lampę w miejscu: 0,0,10; i jeszcze drugą (np. zieloną) w: 1,10,0
i tam mają one stać cały czas, jedynie ten obiekt ma się obracać.

0

Rysowanie, obracanie i przemieszczanie obiektu rób między wywołaniami glPushMatrix(), glPopMatrix(). Światło zostaw na zewnątrz.

0

Chyba tak to robię i te światła się knocą..

glLoadIdentity();
transWsp(); // obracam sobie całą scenę - wraz z tymi światłami, jak mniemam.

drawObj(); // i teraz rysuję coś tam - najpierw obracam i przesuwam

glFinish();
SwapBuffers(wglGetCurrentDC());

no i to jest do kitu.
Ta bryła jest źle oświetlana... niekiedy wcale jakby lamp w ogóle nie było.

0

Pokaż pełny kod funkcji.

0

Cały kod jest dość długi.. różne bryły wirujące, z teksturami, itd.

void transWsp()
{
glTranslatef(0,0, zfar);

posLamps(tLamp[0], bLamp);    // ustawiam przed obrotami

float o[3];
o[0] = ukladWsp[5]; o[1] = ukladWsp[6]; o[2] = ukladWsp[7]; // orientacja całego układu - trzy kąty

if( isAnim() ) // animacja - obroty całego układu
 {
   double t = AnimTim*0.001;
   for(int i = 0; i < 3; i++) o[i] = fmod(o[i] + animPar(i)*t, 360);
 }

glRotatef(o[2],  0,0,1);     // obrót ostatecznego widoku
glRotatef(o[1],  0,1,0);
glRotatef(o[0],  1,0,0);

glTranslatef(-Ox(),-Oy(), -Oz()); // przesunięcie do początku układu.

}

a rysowanie obiektu wygląda z grubsza tak:

drawObj()
{
glPushMatrix();
glTranslatef(xobj, yobj, zobj); // wsp. obiektu
glRotatef(k, alfa,beta,gamma); // obracamy go

... i tu rysujemy .. glBegin itd.

  glPopMatrix();
}

}

0

Może weźmy prosty przykład obrotów:

z
^
|
S ------------------------------> Z ----- K

S to słońce, które jest od razu pozycją lampy - światła,
Z to Ziemia, która krąży dookoła S,
oraz K - Księżyc który który z kolei dookoła Z.

W sumie mamy tylko trzy sfery:
S - stoi (lampa).
Z - krąży dookoła S w płaszczyźnie XY, z prędkością: 1 stopień / s.
K - krąży dookoła Z, z prędkością 12 x większą = 12 stopni/s.

Jak to teraz rysować w tym opengl i pod dowolnym kątem - z góry, z boku, czy skosem?

1
glLoadIdentity();
gluLookAt(ustawienia kamery);
Słońce();
glPushMatrix();
    glTranslate();
    glRotate();
    Ziemia();
    glPushMatrix();
        glTranslate();
        glRotate();
        Księżyc();
    glPopMatrix();
glPopMatrix();

Przy czym w tak prostej sytuacji (jedna planeta z jednym księżycem) te pushmatrix/popmatrix nie są potrzebne.

glLoadIdentity();
gluLookAt(ustawienia kamery);

Słońce();

glTranslate();
glRotate();
Ziemia();

glTranslate();
glRotate();
Księżyc();

Ale zaczną być, jeśli byś chciał rysować więcej ciał:

    Ziemia();
    glPushMatrix();
        glTranslate();
        glRotate();
        Księżyc1();
    glPopMatrix();
    glPushMatrix();
        glTranslate();
        glRotate();
        Księżyc2();
    glPopMatrix();

itp.

Wyobrażaj sobie to tak, że każdy obiekt ma swoje Translate/Rotate/Scale obwarowane PushMatrix/PopMatrix ograniczającymi zasięg transformacji.

0

Nie używam gluLookAt, bo to jest tylko prosta kombinacja: translate + rotate.

Poza tym, te przykłady są mało adekwatne - nie ma tam świateł, o które mi chodzi (samo rysowanie dobrze mi działa).

Być może problem wynika z ograniczeń opengl:
tam chyba nie można zdefiniować światła, które świeci tak dookoła - jak żarówka, czy Słońce.

Tam są światła kierunkowe - świecące tylko równolegle,
albo ograniczone do pewnego kąta - chyba do 90 stopni to maks.

Zatem gdy obrócimy obiekt o zbyt duży kąt, wtedy to światło znika zupełnie.
Tak mi to przynajmniej wygląda...

0
zbigooooo napisał(a):

Nie używam gluLookAt, bo to jest tylko prosta kombinacja: translate + rotate.

A wiesz że glTranslate i glRotate to nic innego jak glMultMatrix z odpowiednim parametrem?
Tylko po co sobie życie utrudniać…

Poza tym, te przykłady są mało adekwatne - nie ma tam świateł, o które mi chodzi (samo rysowanie dobrze mi działa).

Przepraszam że pomogłem.

Być może problem wynika z ograniczeń opengl:
tam chyba nie można zdefiniować światła, które świeci tak dookoła - jak żarówka, czy Słońce.

Bzdura.

http://www.glprogramming.com/red/chapter05.html

A tak poza tym… pokaż kod!

0

Może pokażę jeden przykładowy obrazek z moich testów z GL:

https://ibb.co/m3cXDF

Jak widać są tam dwie bryły: torus oraz wstęga Mobiusa.

Torus jest OK - dobrze go widać.
Natomiast ta wstęga jest raczej źle oświetlona, ponieważ ta powierzchnia nie ma prawej i lewej strony lecz tylko jedną.

No i tam tam światło się gubi wyraźnie - tylko połowa jest oświetlona poprawnie, a pozostała część jest czarna.

W takim przypadku należy włączyć 'oświetlenie dwustronne' w gl, co powinno załatwić problem.
Niestety, ale po włączeniu dwustronnego oświetlenia w ogóle nie ma światła - nawet ten torus jest płaski, jednobarwny!

0
  1. pokaż wreszcie jak to światło ustawiasz w kodzie, inaczej nie da się ci pomóc
  2. czarna część möbiusa jest po prostu w cieniu, a przy braku atmosfery masz efekt cienia księżycowego – czarnego. pod linkiem przeze mnie podanym masz informacje o różnych rodzajach oświetlenia; poczytaj zwłaszcza o ambient light.
0
Azarien napisał(a):
  1. pokaż wreszcie jak to światło ustawiasz w kodzie, inaczej nie da się ci pomóc

Proszę bardzo - funkcja z ustawianiem parametrów sceny:

void setGLParams()
{
if( isLight() ) glEnable (GL_LIGHTING);
else glDisable(GL_LIGHTING);

 if( isDepth() ) glEnable (GL_DEPTH_TEST);
 else            glDisable(GL_DEPTH_TEST);

// glClearDepth(1.0f);
// glDepthFunc(GL_LESS);

 glShadeModel (isSmooth() ? GL_SMOOTH : GL_FLAT);

 if( isLineSmooth() ) glEnable (GL_LINE_SMOOTH);
 else                 glDisable(GL_LINE_SMOOTH);

 float v[4]; v[0] = v[1] = v[2] = v[3] = 1;
 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, v);
 v[0] = TwoSide() ? 1 : 0;
 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE,     v);
 v[0] = LocalViewer() ? 1 : 0;
 glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, v);

 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);

// glEnable(GL_COLOR_MATERIAL);

 glClearColor(clearColor[0], clearColor[1], clearColor[2], 1);

 for(int i = 0; i < MAX_LAMP; i++) // tu są parametry lamp
   if( bLamp & (1 << i) )
    {
      setLamp(tLamp[i], i);
      glEnable(GL_LIGHT0+i);
    }
   else glDisable(GL_LIGHT0+i);

 if( isFog() )
  {
    glFogi (GL_FOG_MODE,    fog.mode);
    glFogfv(GL_FOG_COLOR,   fog.color);
    glFogf (GL_FOG_DENSITY, fog.density);
    // if( mode == GL_LINEAR )
    glFogf (GL_FOG_START, fog.start);
    glFogf (GL_FOG_END,   fog.end);

    glEnable(GL_FOG);
  }
 else glDisable(GL_FOG);

}

ustawienie lamp wygląda tak:
void setLamp(float *p, uint ix) // p to tablicz 24 floatów - pozycja 4, kierunek 3, ambient 4, itd...
{
ix += GL_LIGHT0;
// glEnable(GL_LIGHT0+ix);

glLightfv(ix, GL_POSITION, p); p += 4;     // = (0,0,1,0); w = 0 -> tylko kierunkowe
glLightfv(ix, GL_SPOT_DIRECTION, p); p += 3; // kierunek     = (0, 0, -1)

glLightfv(ix, GL_AMBIENT,  p); p += 4;     // = (0,0,0,1)             stałe
glLightfv(ix, GL_DIFFUSE,  p); p += 4;     // = (0,0,0,1); L0 =(1,1,1,1)
glLightfv(ix, GL_SPECULAR, p); p += 4;     //    -       ''       -   odbite

glLightfv(ix, GL_SPOT_EXPONENT,  p); p += 1; // 0-128        = 0
glLightfv(ix, GL_SPOT_CUTOFF,    p); p += 1; // 0-90 lub 180 = 180

                       // rozpraszanie: 1/f = a + b*r + c*r^2;
glLightfv(ix, GL_CONSTANT_ATTENUATION,  p);  p += 1;    // a > 0  = 1
glLightfv(ix, GL_LINEAR_ATTENUATION,    p);  p += 1;    // b > 0  = 0
glLightfv(ix, GL_QUADRATIC_ATTENUATION, p);             // c > 0  = 0

}

void posLamps(float *pt, uint b)
{
for(int ix = GL_LIGHT0; b; ix++, pt+=N_LAMP_F, b >>= 1)
if( b & 1 )
{
glLightfv(ix, GL_POSITION, pt);
glLightfv(ix, GL_SPOT_DIRECTION, pt+4);
}
}

  1. czarna część möbiusa jest po prostu w cieniu, a przy braku atmosfery masz efekt cienia księżycowego – czarnego. pod linkiem przeze mnie podanym masz informacje o różnych rodzajach oświetlenia; poczytaj zwłaszcza o ambient light.

Ambient light nie ma wpływu na cienie.
To jest tylko 'zerowe' oświetlenie otoczenia, czyli bias koloru - zawsze, bezwarunkowo dodawany do światła.

0

Ambient to symulacja rozproszenia światła w atmosferze, diffuse czy specular pada z określonego kierunku (określonego za pomocą funkcji glLightfv). Ambient nie musi być bezwarunkowo dodawany do światła, może być ustawiony na 0 a wtedy ambientu nie ma (tak jakby światła rozproszonego nie było).

Położenie światła podlega transformacjom, więc najpierw ustal położenie światła a potem obracaj kamerę itp itd, chyba że chcesz żeby światło kręciło się razem z kamerą.

Jeśli ustawisz glLightfv z parametrem GL_SPOT_CUTOFF na 180 to otrzymasz "żarówkę", punktowe źródło światła świecące we wszystkich kierunkach, pamiętaj jednak że to źródło ma ustalone położenie i nie oświetli powierzchni odwróconej tyłem, chyba że normalne są dziwnie wyznaczone...

Sprawdź dla tej wstęgi mobiusa jak zdefiniowane są normalne do powierzchni, czy są znormalizowane, bo kolor powierzchni obliczany jest na podstawie kąta jaki tworzy normalna do powierzchni i kierunek światła od źródła do werteksa pod który podpięty jest ta normalna.

Obrazek wygląda dobrze, po prostu tam gdzie wstęga jest czarna nie dochodzą promienie bo są absorbowane przez wystawioną na światło powierzchnię, źródło światła jest ustawione do góry i na lewo od przedmiotów, przesuń nieco źródło światła (wgłąb obrazka, nie wiem jaka oś bo nie wiem jakie transformacje zastosowane) i też promienie powinny na czarną powierzchnię padać.

0

Obrazek wygląda dobrze, po prostu tam gdzie wstęga jest czarna nie dochodzą promienie bo są absorbowane przez wystawioną na światło powierzchnię, źródło światła jest ustawione do góry i na lewo od przedmiotów, przesuń nieco źródło światła (wgłąb obrazka, nie wiem jaka oś bo nie wiem jakie transformacje zastosowane) i też promienie powinny na czarną powierzchnię padać.

W opengl nie ma żadnego zasłaniania światła przez obiekty.
Zasłanianie (GL_DEPH_TEST) dotyczy tylko obiektów - ten bliżej zakrywa dalsze.

Mówiłem już o tym, że wstęga mobiusa ma tylko jedną stronę, co uniemożliwia ustawienie normalnych tak aby było dobrze.

Taką wstęgę należałoby chyba rysować w wersji 3D - musi mieć niezerową grubość,
wtedy będą dwie powierzchnie: zewnętrzna i wewnętrzna, jak w przypadku torusa.
Zresztą to byłby faktycznie torus - o przekroju prostokąta, który się obraca dookoła środka.

0

W opengl nie ma żadnego zasłaniania światła przez obiekty.

Faktycznie racja, za łatwo cienie byłby robić (ciekawe czy nie można tego było powiązać z GL_DEPTH_TEST?).

W takim razie pozostaje tylko opcja z niezdefiniowanymi normalnymi po wewnętrznej stronie torusa, można sprubować co drugi werteks odwrócić normalne do środka ale jak by to wyszło to do końca nie wiem.

0

Faktycznie racja, za łatwo cienie byłby robić (ciekawe czy nie można tego było powiązać z GL_DEPTH_TEST?).

Jeszcze nie próbowałem robić cieni, ale DEPTH_TEST raczej w tym nie pomoże.
O ile pamiętam z dokumentacji, cienie robi się za pomocą operacji GL_STENCIL_TEST.

W takim razie pozostaje tylko opcja z niezdefiniowanymi normalnymi po wewnętrznej stronie torusa, można sprubować co drugi werteks odwrócić normalne do środka ale jak by to wyszło to do końca nie wiem.

Ale przy ustawieniu dwustronnego oświetlenia powinno dobrze rysować, a jest ciemno.

0

Ale przy ustawieniu dwustronnego oświetlenia powinno dobrze rysować, a jest ciemno.

No nie wiem, to zależy od normalnych obiektu, chyba że te dwustronne oświetlenie działa tak że kopiuje normalne z przeciwnym zwrotem ale w to wątpię.

O ile pamiętam z dokumentacji, cienie robi się za pomocą operacji GL_STENCIL_TEST.

Pewnie tak, ale ciekawe czy w nowym openglu nie da rady napisać shadera który "ucina" promień po napotkaniu pierwszej przeszkody, chociaż w zasadzie to już byłby ray-tracing, problematyczne.

0
czaffik napisał(a):

Ale przy ustawieniu dwustronnego oświetlenia powinno dobrze rysować, a jest ciemno.

No nie wiem, to zależy od normalnych obiektu, chyba że te dwustronne oświetlenie działa tak że kopiuje normalne z przeciwnym zwrotem ale w to wątpię.

Dokładnie tak powinno być:
w trybie dwustronnego oświetlenia wektory normalne są automatycznie ustawiane w kierunku światła.

https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glLightModel.xml

Pewnie tak, ale ciekawe czy w nowym openglu nie da rady napisać shadera który "ucina" promień po napotkaniu pierwszej przeszkody, chociaż w zasadzie to już byłby ray-tracing, problematyczne.

Dla wyprodukowania cieni musisz wykonywać kilka przebiegów (bez wyświetlania wyników na ekranie)
z różnych orientacji układu... bo zależnie od liczby świateł.

0

Chyba trochę się pomyliłem, bo wedle tego opisu:
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glColorMaterial.xml

face
Specifies whether front,
back,
or both front and back material parameters should track the current color.
Accepted values are
GL_FRONT,
GL_BACK,
and GL_FRONT_AND_BACK.
The initial value is GL_FRONT_AND_BACK.
mode
Specifies which of several material parameters track the current color.
Accepted values are
GL_EMISSION,
GL_AMBIENT,
GL_DIFFUSE,
GL_SPECULAR,
and GL_AMBIENT_AND_DIFFUSE.
The initial value is GL_AMBIENT_AND_DIFFUSE.

A ja stosuję tylko:
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
czyli ten GL_SPECULAR mi znika w trybie dwustronnym.
Zaraz to sprawdzę...

0

Jak chcesz dodać światło odbicia to oprócz:

glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);

trzeba dodać (chyba. nie jestem pewien jak to działa):

glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);

Normalnie zamiast śledzenia kolorów zastosowałbym materiały:

glMaterialfv(GL_FRONT, GL_AMBIENT, ambient.data());
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse.data());
glMaterialfv(GL_FRONT, GL_SPECULAR, specular.data());
glMaterialfv(GL_FRONT, GL_EMISSION, emission.data());
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
0

I dokładnie tak robię:

void setMaterial(float *p, int side) // side = GL_FRONT_AND_BACK
{
glMaterialfv (side, GL_AMBIENT, p); p += 4;
glMaterialfv (side, GL_DIFFUSE, p); p += 4;
glMaterialfv (side, GL_SPECULAR, p); p += 4;
glMaterialf (side, GL_SHININESS, *p); p++;
glMaterialfv (side, GL_EMISSION, p);
}

najwyraźniej nie ma to znaczenia dla oświetlenia w trybie dwustronnym.

0

Światło w openglu potrafi się czasami zachowywać osobliwie, ale co się spodziewać, to tylko przybliżony model.

Poustawiaj jeszcze światło, SPOT_CUTOFF na 180, LINEAR_ATTENUATION i QUADRIC_ATTENUATION na 0, może jakieś inne kombinacje, jak nie to bierzesz opengla 330 albo nowszego i piszesz własnego shadera:

in vec3 gPosition;
in vec3 gNormal;
in vec2 gTexcoord;
in vec3 gEye;
in vec3 gLightPos[20];

out vec4 outColor;

uniform sampler2D texSampler;

uniform vec4 ambient;
uniform vec4 diffuse;
uniform vec4 specular;
uniform float shininess;
uniform vec4 emission;

uniform vec4 lightAmbient;
uniform vec4 lightColor[20];
uniform float lightAttenuation[20];
uniform int lightsCount;
 
void main() 
{	
	vec4 color = texture(texSampler, gTexcoord);
 
	vec4 sum = vec4(0.0);
	vec4 ambientColor = vec4(0.0);
	vec3 e = vec3(0.0);
	vec3 lightDir = vec3(0.0);
	vec4 diffuseColor = vec4(0.0);
	vec3 halfDir = vec3(0.0);
	vec4 specularColor = vec4(0.0);
	float distanceToLight = 0.0;
	float attenuation = 0.0;
	
	ambientColor = ambient*lightAmbient;
	
	for (int i = 0; i < lightsCount; i++)
	{	
		e = vec3(gLightPos[i] - gPosition);	
		lightDir = normalize(e);
		
		diffuseColor = max(dot(gNormal, lightDir), 0.0)*diffuse*lightColor[i];
	
		halfDir = normalize(lightDir + gEye);
		specularColor = pow(max(dot(halfDir, gNormal), 0.0), shininess)*specular*lightColor[i];
	
		distanceToLight = length(e);
		attenuation = 1.0/(1.0 + lightAttenuation[i]*pow(distanceToLight, 2));
		
		sum += vec4(attenuation*(diffuseColor + specularColor));
	}
 
	outColor = (ambientColor + sum + emission)*color;
}
0

Nie w czym to pomoże...
prawdopodobnie tryb dwustronnego oświetlenia nie działa - są tam jakieś błędy w samym openglu.

Ostatecznie zawsze mamy jakieś tam całe bryły - pozamykane dookoła, czyli z dwoma powierzchniami: wewnętrzną i zewnętrzną;
a wtedy nie potrzeba dwustronnego oświetlania.

0

Wynik dla grubego mobiusa - o niezerowym przekroju eliptycznym:
https://ibb.co/bVYjDF

jak widać jest OK.

eliptyczny-mobius

0

No to może się mylę ale wygląda na to że te oświetlenie dwustronne po prostu informuje o tym że ma liczyć kolory dla pikseli dla obu stron prymitywów ale normalne trzeba wyznaczać samemu.

0
czaffik napisał(a):

No to może się mylę ale wygląda na to że te oświetlenie dwustronne po prostu informuje o tym że ma liczyć kolory dla pikseli dla obu stron prymitywów ale normalne trzeba wyznaczać samemu.

Raczej nie ma takiej możliwości.
Normalne do ścian są takie jakie są, one nie zależą od kąta patrzenia... niestety.

Wedle moich prób wychodzi, że tam jest jednak jakieś szczątkowe oświetlenie w wersji dwustronnej;
chyba nie ma wtedy świateł z kątem 180, czyli pozostają jedynie te stożkowe - do 90 stopni, których zwykle nie używamy... jakoś tak to chyba działa.

1 użytkowników online, w tym zalogowanych: 0, gości: 1