Как зафиксировать источник света в OpenGL при вращении объекта? - PullRequest
5 голосов
/ 18 ноября 2009

У меня есть glutSolidTeapot (у которого нормали его поверхности генерируются автоматически в соответствии с opengl.org) и источник света, который излучает рассеянный свет. Проблема возникает, когда я пытаюсь повернуть чайник: кажется, что источник света также выполняет вращение, не оставаясь в том же положении, в котором я его определил (это по существу следует за чайным горшком). Как вы можете видеть из моего кода, я изменяю положение освещения только при инициализации, поэтому он не подвергается glRotatef (), так как он вызывается после установки положения освещения.

Несмотря на то, что я потратил много часов, пытаясь решить эту проблему, я действительно понятия не имею, к чему можно отнести такое поведение.

Вставка glEnable (GL_NORMALIZE); в инициализации не решает проблему ни.

Я думаю, что желаемым выходным сигналом должен быть чайник с блестящей правой стороной (поскольку свет идет с этого направления), независимо от того, на какой угол повернут чайник.

Если вы хотите проверить мой код, нажмите пробел, чтобы повернуть чайник.

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

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#include <windows.h>     
#endif

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>     

void onInitialization( ) { //creating the light source
 glEnable(GL_LIGHTING);
 glEnable(GL_DEPTH_TEST); 

 GLfloat diffuse[]={0.8, 0.8, 0.8, 1.0};
 GLfloat pos[]={0.5, 0.0, 0.8, 0.0};

 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
 glLightfv(GL_LIGHT0, GL_POSITION, pos);

 glEnable(GL_LIGHT0);

 glRotatef(-90, 1, 0, 0); //we want to see the top of the teapot
}

void onDisplay( ) {
    glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 //rotating on every frame (for testing purposes only)
 glRotatef(5, 0,1,0);
 glutSolidTeapot(0.4);

    glFinish();
    glutSwapBuffers();
}


void onKeyboard(unsigned char key, int x, int y) {
 if (key==32){ //do rotation upon hitting the Space key
  glutPostRedisplay();
 }
}

int main(int argc, char **argv) {
    glutInit(&argc, argv); 
    glutInitWindowSize(600, 600);
    glutInitWindowPosition(100, 100);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("Teapot");

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    onInitialization();

    glutDisplayFunc(onDisplay);
    glutKeyboardFunc(onKeyboard);

    glutMainLoop();

    return 0;
}

Ответы [ 6 ]

2 голосов
/ 18 ноября 2009

Я думаю, что меняется

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

до

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

хорошее место для начала.

1 голос
/ 20 февраля 2012

Я столкнулся с той же проблемой и получил решение. Проблема заключалась в том, что я установил светлое положение only в OnLoad части программы ... Я думаю, что лучше всего опубликовать некоторый код. Я работаю в C #, используя OpenTK, потому что я знаю, что никогда не буду заниматься графическим бизнесом. :)

В результате получается чайник или какой-то другой объект, который вращается со светом, который имеет фиксированное положение. Я могу изменить положение глаз (метод LookAt ), и источник света остается неподвижным. Это как в реальном слове: объект может вращаться, а солнце - нет. :) Кроме того, мы можем ходить вокруг объекта, но солнце все еще остается не впечатленным и остается неподвижным. Этот код сделает этот трюк.

protected override void OnRenderFrame(FrameEventArgs e)
 {
        base.OnRenderFrame(e);

        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        System.Threading.Thread.Sleep(10); //useful thing to lower CPU usage

        //I can set the eye position at runtime, it's not necessary to have this
        modelview = Matrix4.LookAt(this.eye, Vector3.Zero, Vector3.UnitY);

        GL.MatrixMode(MatrixMode.Modelview);                       
        GL.LoadMatrix(ref modelview);           

        //**this is the key - you have to set the light position every time**
        GL.Light(LightName.Light0, LightParameter.Position, new float[4] { 1000, 1000, 0, 0 });


        // We don't want the walls to rotate so we push the current matrix
        GL.PushMatrix();

         GL.Rotate(move, Vector3.UnitY);
         move += 0.5f;

         GL.Color3(1.0f, 1.0f, 1.0f);

           GL.Begin(BeginMode.Triangles);
           //the object that will rotate             
           GL.End();
        GL.PopMatrix();              


        GL.Begin(BeginMode.Quads);
        //some quads (walls) in the background that will stay still
        GL.End();                                                

        SwapBuffers();
    }

Я взял это из своей программы и удалил много вещей, которые здесь не важны, так что, возможно, это выглядит немного странно. Надеюсь, это поможет.

1 голос
/ 12 февраля 2012

Попробуйте вручную установить нормальные значения для каждой вершины.

1 голос
/ 06 декабря 2009

Я также думаю, что ваше приложение "разрушает" вид модели матрица; это никогда не пересчитывается с нуля. Вам следует начать каждый кадр с LoadIdentity (), затем испустить источник света, затем поверните как хотите, и, наконец, испустите геометрия.

Это не работает, это не работает, это не работает, lalalalalalalala, и часто задаваемые вопросы явно неверны , просто и просто.

Излучение света сразу после glLoadIdentity () для получения света, связанного с камерой, будет работать в простых случаях, когда вы только переводите или вращаете модель только вокруг источника. Но когда вы начинаете делать нетривиальные, не относящиеся к миру вещи, такие как вращение объекта вокруг точки, отличной от начала координат (перевод (-v), вращение (угол), перевод (v)), а затем перемещение его так, чтобы центр вращения помещается перед камерой, , затем , начинается техника "загрузить идентификатор, разместить свет" эффектно терпит неудачу и таким образом, что очень трудно определить, что происходит .

Нет, я не знаю решения.

0 голосов
/ 08 декабря 2009

По моему мнению, вам следует не только вызвать glLoadIdentity () в начале вашей процедуры рендеринга, но и нажать и вытолкнуть матрицу просмотра модели.

для сцены с глобально фиксированным источником света и двумя объектами, которые независимо расположены и повернуты, этот псевдокод сделает свое дело:

glLoadIdentity();

// first object
glPushMatrix();
glTranslate(...);
glRotate(...)
glPopMatrix();

// second object
glPushMatrix();
glTranslate(...);
glRotate(...);
glPopMatrix();
0 голосов
/ 18 ноября 2009

Состояния FAQ :

Позиция света трансформируется текущая матрица ModelView на время позиция указывается с вызов glLight * ().

Другими словами, огни не расположены в какой-то магической статической "мировой системе координат"; они умножаются на матрицу вида модели, как любая геометрия. Это имеет смысл; Вы часто хотите, чтобы источники света были привязаны к геометрии.

Я также думаю, что ваше приложение "разрушает" матрицу просмотра модели; это никогда не пересчитывается с нуля. Вы должны начинать каждый кадр с LoadIdentity (), затем излучать источник света, затем вращаться по желанию и, наконец, излучать геометрию.

...