OpenGL - oświetlenie, problem z normalizacją

0

Stworzyłem aplikację w C, z wykorzystaniem OpenGL'a. Aplikacja umożliwia użytkownikowi poruszanie się po planszy za pomocą klawiszy strzałek i obracanie się poprzez ruch myszą z przytrzymanym przyciskiem. Problem pojawił się po dodaniu oświetlenia. Dodałem światło typu - positioned light i spodziewałem się, że narysowane przeze mnie ściany zostaną oświetlone z jednej strony, a pozostaną ciemne z drugiej. Jednak efekt jest taki, że albo ściany są oświetlone z obu stron, albo ciemne z obu stron. Problem znika, kiedy zamiast ścian rysuje zdefiniowane w bibliotece GLUT czajniki - tam oświetlenie działa prawidłowo. Poniżej zamieszczam kod (był on bardziej skomplikowany, ale ograniczyłem kod do samych ścian i światła). Światło znajduje się w pozycji, w której narysowałem sferę.

#include <math.h>
#include <stdlib.h>
#include <GL/glut.h>

//horizontal camera angle
float angle = 0.0;
//vertical camera angle
float angleV = 0.0;

//position of the camera
float x = 5.0f, y = 2.0f, z = 5.0f;
//vector - shows camera direction
float lx = 0.0f, ly = 0.0f, lz = -1.0f;

float rotationSpeed = 0.0f;
float moveSpeed= 0.0f;

int mouseX = 0.0f;
int mouseY = 0.0f;

const float mapSizeX = 1000.0f, mapSizeZ = 1000.0f;

void wall()
{
    const float height = 5.0;
    const float width = 6.0;

    glBegin(GL_QUADS);
    glNormal3f(0.0, 0.0, 1.0);
    glColor3f(1.0, 1.0, 1.0);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-width/2.0, 0.0, 0.0);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(width/2.0, 0.0, 0.0);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(width/2.0, height, 0.0);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-width/2.0, height, 0.0);
    glEnd();

    glDisable(GL_TEXTURE_2D);
}


void lights ()
{
    GLfloat lightColor0[] = {0.9f, 0.9f, 0.9f, 1.0f};
    GLfloat lightPos0[] = {5.0f, 5.0f, 12.0f, 1.0f};
    //GLfloat lightPos0[] = {5.0f, 5.0f, 12.0f, 0.0f};
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);

    glPushMatrix();
        glColor3f(1.0, 1.0, 1.0);
        glTranslatef(lightPos0[0], lightPos0[1], lightPos0[2]);
        glutWireSphere(2.0, 100, 100);
    glPopMatrix();


}

void refreshMyRoation (float angleArg)
{
    lx = sin(angle);
    ly = -sin(angleV);
    lz = -cos(angle);
}


void refreshMyPosition (float speedArg)
{
    x = x + moveSpeed*(lx);
    y = y + moveSpeed*(ly);
    z = z + moveSpeed*(lz);
}

void drawScene()
{
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glClearColor(0.1, 0.1, 0.1, 0.0);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    gluLookAt(x, y, z, x + lx, y + ly, z + lz, 0.0f, 1.0f, 0.0f);

    lights();

    for(int i = -5; i < 5; i++)
        for(int j = -3; j < 3; j++)
        {
            glPushMatrix();
                glTranslatef((float)i*30.0, 0, (float)j*30.0);
                wall();
                //glTranslatef(0.0, 1.0, 0.0);
                //glutSolidTeapot(2.0);
            glPopMatrix();
        }

    glutSwapBuffers();

}

void pressKey(int key, int x, int y)
{
switch (key)
{
  case GLUT_KEY_LEFT : rotationSpeed = -0.05f; break;
  case GLUT_KEY_RIGHT : rotationSpeed = 0.05f; break;
  case GLUT_KEY_UP : moveSpeed = 1.1; break;
  case GLUT_KEY_DOWN : moveSpeed = -1.1; break;
}

glutPostRedisplay();
}


void releaseKey(int key, int x, int y)
{

switch (key)
{
  case GLUT_KEY_LEFT :
  case GLUT_KEY_RIGHT : rotationSpeed = 0.0f; break;
  case GLUT_KEY_DOWN :
  case GLUT_KEY_UP : moveSpeed = 0.0f; break;
}

glutPostRedisplay();

}

void mouseMotion (int xpos, int ypos)
{
    angle += 0.01f*(xpos - mouseX);
    angleV += 0.01f*(ypos - mouseY);
    mouseX = xpos;
    mouseY = ypos;
}

void mouseButtons (int button, int state, int xclick, int yclick)
{
    if(state == GLUT_DOWN)
    {
        mouseX = xclick;
        mouseY = yclick;
    }
}

void reshape(int w, int h)
{

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

glViewport(0, 0, w, h);

gluPerspective(45, ((float)w) / ((float)h), 0.5, 1000);

}

void idle (int value) {

    angle += rotationSpeed;
    refreshMyPosition(moveSpeed);
    refreshMyRoation(angle);

    glutPostRedisplay();

    glutTimerFunc(15, idle, 0);
}


void init ()
{
    glEnable(GL_DEPTH_TEST);

    glEnable(GL_NORMALIZE);
   glEnable(GL_COLOR_MATERIAL);

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);

    glutDisplayFunc(drawScene);

   glutIgnoreKeyRepeat(1);
   glutSpecialFunc(pressKey);
   glutSpecialUpFunc(releaseKey);

   glutMotionFunc(mouseMotion);
   glutMouseFunc(mouseButtons);

   glutReshapeFunc(reshape);

}

int main(int argc, char** argv) {

   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize(800, 600);

   glutCreateWindow("3D");
    init();

    glutTimerFunc(25, idle, 0);

   glutMainLoop();
   return 0;
}
0

A wiesz do czego służą wektory normalne modelu oświetlenia?

Lekcja poglądowa, zmień funkcję wall() na taką:

void wall()
{
    const float height = 5.0;
    const float width = 6.0;

    glBegin(GL_QUADS);

    glNormal3f(0.0, 0.0, -1.0);                                  // -1.0 jest kluczowe
    glColor3f(1.0, 1.0, 1.0);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-width/2.0, 0.0, 0.0);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(width/2.0, 0.0, 0.0);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(width/2.0, height, 0.0);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-width/2.0, height, 0.0);

    glNormal3f(0.0, 0.0, 1.0);                                // a tu 1.0
    glColor3f(1.0, 1.0, 1.0);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-width/2.0, 0.0, 0.01);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(width/2.0, 0.0, 0.01);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(width/2.0, height, 0.01);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-width/2.0, height, 0.01);

    glEnd();

    glDisable(GL_TEXTURE_2D);
}

Potem zmień znaki (w pierwszym na 1.0 a w drugim -1.0), obejrzyj efekt jeszcze raz i wyciągnij wnioski, dlaczego 1 kwadrat z jednym wektorem normalnym nie robił tego czego chciałeś.

0

wektory normalne dla wierzcholkow to jeden problem drugi to ze on nie ma GL_CULL_FACE

0

Wektory normalne dla wierzchołków nic nie zmienią, działają one tylko wygładzając krawędzie, gdy inna płaszczyzna jest do niej przyległa.
A GL_CULL_FACE nie ma nic wspólnego ze światłem, z wektora normalnego też nie korzysta - po prostu nie rysuje ścian, które są zwrócone plecami.

Rozwiązaniem mojego problemu jest chyba to, że po prostu OpenGL działa w ten sposób, że:
gdy wektor normalny skierowany jest w kierunku źródła światła to obie strony ścian są jasne, w przeciwnym wypadku obie strony ścian są ciemne. Jeżeli siedzimy w narysowanym domku to po wewnętrznych stronach ścian zobaczymy światło słoneczne spoza domku. Myślę, że tak to właśnie działa.

0
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
0
Kojot89 napisał(a)

Wektory normalne dla wierzchołków nic nie zmienią, działają one tylko wygładzając krawędzie, gdy inna płaszczyzna jest do niej przyległa.

Rany, weź gościu sobie uruchom to jeszcze raz, stań pod kulą, obóć się parę razy o 360 stopni i nie mów że dalej nie widzisz związku pomiędzy kierunkami wektorów normalnych i padania światła z jasnoscią tych płaszczyzn.

Druga sprawa, weź sobie do ręki jakąś kulkę o jednolitym kolorze (może być landrynka, kulka od myszy czy od biedy możesz wyskrobać g**no z d**y) i to jest pixel, możesz na niego popatrzeć z kilku stron, będzie mieć taki sam kolor. Jak zmienisz go na zielony, niebieski, purpurowy to z każdej strony będzie taki sam. Nawet jak oświetlisz go światłem będzie błyszczał tak samo z wszystkich stron.
Teraz wyobraź sobie że z tych pikseli tworzysz prostokąt jak w twoim programie. Pixele zachowują swoje właściwości. Zmienisz kolor któregoś piksela z jednej strony płaszczyzny to z drugiej też będzie zmieniony.
Do czego zmierzam, oświetlasz prostokąt z jednej strony to nie dziw się że błyszczą obie strony.

0

i jeszcze jedno wektory normalne maja wplyw na swiatlo

0

Gry 3D - dynamiczne światła, OpenGL

i jeszcze jedno wektory normalne maja wplyw na swiatlo

Do czego zmierzam, oświetlasz prostokąt z jednej strony to nie dziw się że błyszczą obie strony.

dp tego uzywamy wektorrow normalnych i gl_cull_face lub ?blendingu?
to jest rysowanie dwoch stron

a normalnie to pewnie nie ustawiasz gl_color_material i nie wlaczasz gl_color_material
to nie swieci ci na okreslony kolor

0

Dobra pomyliłem się, gościowi brakło po prostu w init()

   glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,1.0f);

Idę popełnić seppuku.

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