У меня есть небольшая проблема с моим освещением OpenGL.
Это хорошо отрисовывает модель (чайник из Юты), но у меня есть странные схемы освещения. Модель должна быть плоской, с единственным освещением, освещающим сцену, но я получаю пятнистый свет по всему чайнику:
Это всего лишь простое упражнение для создания загрузчика модели в C ++ с использованием SFML.
Код выглядит следующим образом:
bool modelLoader(string fileName, vector<GLfloat>& vertices, vector<GLushort>& indices, vector<GLfloat>& normals)
{
fstream object;
string face;
string dataLine;
string lineChar;
GLfloat point;
GLfloat uvs;
GLfloat storedNorm;
GLushort ind;
vector<GLfloat> storedNormals;
vector<GLfloat> storedUVs;
vector<GLfloat> localNormals , localVertices;
vertices.clear();
indices.clear();
object.open(fileName);
if(!object.is_open())
{
printf("Cannot open file: %f \n", fileName);
return false;
}
while(object>>lineChar)
{
if(lineChar == "v" /*|| dataLine.find("vt ") == 0*/ || lineChar == "f" || lineChar == "vn")
{
if(lineChar == "v")
{
//cout<<"v ";
for(int i=0;i<3;++i)
{
object >> point;
//cout << point << " ";
localVertices.push_back(point);
}
//cout<<endl;
}
else if(lineChar == "vn")
{
//cout<<"vn";
for(int j=0;j<3;++j)
{
object >> point;
//cout<<point<<" ";
localNormals.push_back(point);
}
//cout<<endl;
}
else if(lineChar == "f")
{
for(int k=0;k<3;++k)
{
getline(object, face, '/');
ind = atoi(face.c_str());
indices.push_back(ind-1);
object.ignore(2);
//getline(object, face, '/');
//uvs = atoi(face.c_str());
//storedUVs.push_back(uvs);
getline(object, face, ' ');
storedNorm = atoi(face.c_str());
storedNormals.push_back(storedNorm);
}
}
}
}
for (unsigned int i=0; i<indices.size(); ++i )
{
vertices.push_back(localVertices[indices[i]*3]);
vertices.push_back(localVertices[indices[i]*3 + 1]);
vertices.push_back(localVertices[indices[i]*3 + 2]);
normals.push_back(localNormals[(unsigned int) storedNormals[i]*3]);
normals.push_back(localNormals[(unsigned int) storedNormals[i]*3 + 1]);
normals.push_back(localNormals[(unsigned int) storedNormals[i]*3 + 2]);
}
return true;
}
Основной цикл:
int main()
{
// Create the main window
sf::Window App(sf::VideoMode(SC_WIDTH, SC_HEIGHT, 32), "SFML OpenGL");
// Create a clock for measuring time elapsed
sf::Clock Clock;
//output version of OpenGL to the console
cout<<"OpenGL version: "<<glGetString(GL_VERSION)<<endl;
// Create the vectors to hold the object data
vector<GLfloat> vertices;
vector<GLushort> indices;
vector<GLfloat> normals;
//Load model
if(!modelLoader("teapot2.obj", vertices, indices, normals))
{
printf("Failed to load model. Make sure the .obj file has no errors.");
system("pause");
return 0;
}
//enable the use of vertex arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
// tell OpenGL where the vertices are with glVertexPointer()
glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);
glNormalPointer(GL_FLOAT, 0, &normals[0]);//*************************************************************
// Set color and depth clear value
glClearDepth(1.f);
glClearColor(0.f, 0.f, 0.f, 0.f);
// Enable Z-buffer read and write
glDepthMask(GL_TRUE);
// Set up lighting for the scene
GLfloat ambient[4] = {0.f,0.5f,0.5f, 1.f};
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
// Setup a perspective projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.f, 1.f, 1.f, 500.f);
// Start game loop
while (App.IsOpened())
{
// Process events
sf::Event Event;
while (App.GetEvent(Event))
{
// Close window : exit
if (Event.Type == sf::Event::Closed)
App.Close();
// Escape key : exit
if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
App.Close();
// Resize event : adjust viewport
if (Event.Type == sf::Event::Resized)
glViewport(0, 0, Event.Size.Width, Event.Size.Height);
}
// Set the active window before using OpenGL commands
// It's useless here because active window is always the same,
// but don't forget it if you use multiple windows or controls
App.SetActive();if((float)Clock.GetElapsedTime()>REFRESH_RATE){
// Clear colour and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Apply some transformations
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();glTranslatef(0.f, 0.f, -5.f);
glRotatef(45.f, 1.f, 1.f, 1.f);
glPushMatrix();
//draw the triangles with glDrawArrays() and then with glDrawElements()
glDrawArrays(GL_TRIANGLES, 0, vertices.size()/3);
//glDrawElements(GL_TRIANGLES, vertices.size(), GL_UNSIGNED_SHORT, &indices[0]);
//glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, &indices[0]);
glPopMatrix();Clock.Reset();
}// Finally, display rendered frame on screen
App.Display();
}
//delete the vertex arrays using glDisableClientState()
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);return EXIT_SUCCESS;
}
У кого-нибудь есть мысли?
Источники света OpenGL имеют значения по умолчанию для всех свойств (например, GL_AMBIENT
, GL_DIFFUSE
, так далее.). В случае GL_LIGHT0
свойство diffuse не установлено в ноль (это то, что вам нужно, чтобы получить только окружающее освещение). Чтобы исправить это, вам нужно сделать
GLfloat black[] = { 0.0f, 0.0f, 0.0f, 1.0f };
glLightfv( GL_LIGHT0, GL_DIFFUSE, black );
Так как, IIRC, остальные свойства освещения уже равны нулю, что должно дать вам освещение только для окружающей среды, которое удаляет направленную составляющую вашего освещения. Кроме того, режим по умолчанию для glColorMaterial
является GL_AMBIENT_AND_DIFFUSE
, который устанавливает свойства окружающего и рассеянного материала для цвета входящей вершины. Вы можете подумать о том, чтобы переключить это только на окружающийglColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT );
) также.
Однако коренная причина странности вашего затенения, я думаю, вероятно, связана с ненормативной длиной нормалей. Вы можете попробовать добавить glEnable( GL_NORMALIZE );
перед выполнением световых расчетов.
Других решений пока нет …