Come faccio a fissare una sorgente di luce in OpenGL durante la rotazione di un oggetto?
Domanda
Ho una glutSolidTeapot (che ha le sue normali alla superficie generate automaticamente secondo opengl.org) e una sorgente di luce che sta emettendo luce diffusa. Il problema nasce quando si tenta di ruotare la teiera: sembra che la sorgente di luce sta facendo la rotazione pure, non rimanendo nella stessa posizione ho definita (segue essenzialmente teaspot). Come si può vedere nel mio codice, modifico solo la posizione di illuminazione al momento dell'inizializzazione, quindi non è sottoposto a glRotatef (), dal momento che la sua chiamata dopo impostare la posizione della luce.
Nonostante la spesa numerose ore cercando di risolvere questo problema, ho veramente idea di cosa questo tipo di comportamento può essere attribuito a.
Incolla glEnable (GL_NORMALIZE); nell'inizializzazione non risolve il problema né.
Credo l'output desiderato dovrebbe essere una teiera con un lato lucido destra (poiché la luce proviene da quella direzione), indipendentemente dall'angolo teiera viene ruotato.
Se si desidera verificare il mio codice, premere la barra spaziatrice per ruotare la teiera.
#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;
}
Soluzione
Credo che cambia
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
a
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
è un buon punto di partenza.
Altri suggerimenti
Credo anche che l'applicazione "distrugge" la modelview matrice; non è mai ri-calcolata da zero. Dovresti iniziare ogni telaio con una LoadIdentity (), allora emettere il lightsource, quindi ruotare come desiderato e infine emettere la geometria.
Questo non funziona, questo non funziona, questo non funziona, lalalalalalalala, e la FAQ è palesemente sbagliato , puro e semplice.
che emette la luce subito dopo glLoadIdentity () al fine di ottenere una luce fotocamera-bound lavorerà nei casi più semplici quando si traducono solo, o ruotare solo il modello attorno all'origine. Ma quando si inizia a fare le cose non banali, non-ciao-mondo come rotazione di un oggetto attorno a un punto diverso da quello di origine (tradurre (-v), ruotare (angolo), tradurre (v)) e poi si spostano in modo che il centro di rotazione viene portato davanti alla macchina fotografica, poi l ' "identità di carico, posto luce" tecnica inizia non aver spettacolare e in modi che rendono molto difficile dedurre ciò che è ancora in corso.
No, non so la soluzione.
Prova a impostare manualmente i valori normali per ogni vertice.
Ho incontrato lo stesso problema e ho la soluzione. Il problema è stato che ho impostato la posizione della luce solo in OnLoad parte del programma ... penso che sia il migliore per pubblicare un certo codice. Io lavoro in C # utilizzando OpenTK perche 'sono a conoscenza non potrò mai entrare aziendale grafica. :)
Il risultato è una teiera o qualche altro oggetto che ruota con la luce che ha posizione fissa. Posso spostare la posizione degli occhi ( LookAt metodo) e la sorgente luminosa rimane ancora. E 'proprio come nel mondo reale: L'oggetto può girare, ma il sole non lo farà. :) Inoltre, siamo in grado di andare in giro l'oggetto, ma il sole ancora rimane indifferente e rimane ancora. Questo codice farà quel trucco.
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();
}
Ho preso questo dal mio programma e cancellato un sacco di roba che è qui rilevante, forse sembra un po 'strano. Spero che aiuta.
Il frequenti stati :
La posizione di una luce si trasforma grazie la matrice modelview corrente al momento la posizione è specificato con un chiamare per GLLight * ().
In altre parole, le luci non sono posizionati in una sorta di magia statica "Sistema di Coordinate"; stanno moltiplicato per la matrice modelview proprio come qualsiasi geometria sarebbe. Questo ha senso; spesso si desidera avere le luci bloccate alla geometria.
Credo anche che l'applicazione "distrugge" la matrice modelview; non è mai ri-calcolata da zero. Si dovrebbe iniziare ogni frame con un LoadIdentity (), allora emettere la sorgente di luce, quindi ruotare come desiderato, e infine emettere la geometria.
A mio parere ciò che si dovrebbe fare è non solo di chiamare glLoadIdentity () all'inizio della vostra routine di rendering, ma a spingere e pop la matrice modelview.
per una scena con una fonte di illuminazione fissata globalmente e due oggetti che sono indepently posizionati e ruotati questo codice pseudo farà il trucco:
glLoadIdentity();
// first object
glPushMatrix();
glTranslate(...);
glRotate(...)
glPopMatrix();
// second object
glPushMatrix();
glTranslate(...);
glRotate(...);
glPopMatrix();