Я пытаюсь перенести мой код на современный Opengl, но у меня проблемы. Прямо сейчас мой код нарисует куб и наложит текстуру, но он прикрепит только первую текстуру ко всему моему лицу. Я также использую SOIL для загрузки моих текстур в мою программу. Что я делаю неправильно?
Это мой код:
class Rectangle
{
public:
Rectangle();
Rectangle(float x, float y, float z, float width, float height, float depth, string frontFace, string backFace, string leftFace,
string RightFace, string topFace, string bottomFace);
void Draw();
private:
GLuint m_Textures[6];
string m_TextureNames[6];GLfloat m_Vertices[72]; // v0,v1,v2,v3 (front)
// normal array
GLfloat m_Normals[72]; // v0,v1,v2,v3 (front)
// color array
GLfloat m_Colours[72]; // v0,v1,v2,v3 (front)
// index array of vertex array for glDrawElements() & glDrawRangeElement()
GLubyte m_Indices[36]; // front
GLfloat m_Texcoords[48];
};
Rectangle::Rectangle(float x, float y, float z, float width, float height, float depth, string topFace, string bottomFace, string frontFace,
string backFace, string leftFace, string rightFace)
{
m_CenterX = x;
m_CenterY = y;
m_CenterZ = z;
m_Width = width;
m_Height = height;
m_Depth = depth;
m_TextureNames[0] = topFace;
m_TextureNames[1] = bottomFace;
m_TextureNames[2] = frontFace;
m_TextureNames[3] = backFace;
m_TextureNames[4] = leftFace;
m_TextureNames[5] = rightFace;
m_ObjectType = Textured;
GLfloat tempVert[] = { // front
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// top
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
-1.0, 1.0, -1.0,
// back
1.0, -1.0, -1.0,
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
// bottom
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// left
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0,
// right
1.0, -1.0, 1.0,
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
};
// normal array
GLfloat tempNormals[] = { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0,v1,v2,v3 (front)
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0,v3,v4,v5 (right)
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0,v5,v6,v1 (top)
-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1,v6,v7,v2 (left)
0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7,v4,v3,v2 (bottom)
0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1 }; // v4,v7,v6,v5 (back)
// color array
GLfloat tempColors[] = { 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, // v0,v1,v2,v3 (front)
1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, // v0,v3,v4,v5 (right)
1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, // v0,v5,v6,v1 (top)
1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, // v1,v6,v7,v2 (left)
0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // v7,v4,v3,v2 (bottom)
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1 }; // v4,v7,v6,v5 (back)
// index array of vertex array for glDrawElements() & glDrawRangeElement()
GLubyte tempIndices[] = { 0, 1, 2, 2, 3, 0, // front
4, 5, 6, 6, 7, 4, // right
8, 9,10, 10,11, 8, // top
12,13,14, 14,15,12, // left
16,17,18, 18,19,16, // bottom
20,21,22, 22,23,20 }; // back
GLfloat tempTexcoords[2*4*6] = {
// front
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
};
for (int i = 1; i < 6; i++)
memcpy(&tempTexcoords[i*4*2], &tempTexcoords[0], 2*4*sizeof(GLfloat));copy(tempVert, tempVert + 72, m_Vertices);
copy(tempNormals, tempNormals + 72, m_Normals);
copy(tempColors, tempColors + 72, m_Colours);
copy(tempIndices, tempIndices + 36, m_Indices);
std::copy(tempTexcoords, tempTexcoords + 48, m_Texcoords);
LoadTexture(m_TextureNames);
}
void Rectangle::LoadTexture(string TextureName[6])
{
// Create texture index array.
glGenTextures(6, m_Textures);for(int i = 0 ; i < 1 ; i++)
{
glBindTexture(GL_TEXTURE_2D, m_Textures[i]);
// Set our texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture filtering
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // NOTE the GL_NEAREST Here!
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); // NOTE the GL_NEAREST Here!
std::string fileType;
fileType.append(m_TextureNames[i], m_TextureNames[i].size()-3,3);
if(fileType == "jpg")
{
m_Textures[i] = SOIL_load_OGL_texture // load an image file directly as a new OpenGL texture
(
m_TextureNames[i].c_str(),
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
);
// allocate a texture name
}
else
{
m_Textures[i] = SOIL_load_OGL_texture // load an image file directly as a new OpenGL texture
(
m_TextureNames[i].c_str(),
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
);
// allocate a texture name
}
}
}
// Function to draw Sphere.
void Rectangle::Draw()
{
// enable and specify pointers to vertex arrays
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, m_Normals);
glTexCoordPointer(2, GL_FLOAT, 0, m_Texcoords);
glColorPointer(3, GL_FLOAT, 0, m_Colours);
glVertexPointer(3, GL_FLOAT, 0, m_Vertices);
for (int i=0;i<6;i++)
{
glPushMatrix();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Textures[i]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, m_Indices);
glPopMatrix();
}
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}Rectangle testRect;
// Drawing routine.
void drawScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
testRect.Draw();
glutSwapBuffers();
}
// Initialization routine.
void setup(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
testRect = Rectangle(2, 0.0, 0.0, 1, 2, 1, "grass.bmp","grass.bmp", "grass.bmp", "launch.png", "launch.png", "launch.png");
// Turn on OpenGL texturing.
glEnable(GL_TEXTURE_2D);
glShadeModel (GL_SMOOTH);
}
Размещенный код имеет несколько проблем:
Он загружает только одну текстуру:
glGenTextures(6, m_Textures);
for(int i = 0 ; i < 1 ; i++)
{
glBindTexture(GL_TEXTURE_2D, m_Textures[i]);
...
Если вы хотите загрузить 6 текстур, как предлагает остальная часть кода, вам придется использовать 6 для конечного значения цикла:
for(int i = 0 ; i < 6 ; i++)
Он создает идентификаторы текстуры дважды и устанавливает параметры с неправильной границей текстуры. В начале LoadTexture()
, он генерирует 6 идентификаторов текстуры:
glGenTextures(6, m_Textures);
а затем связывает их, и делает glTexParameteri()
установить на них различные параметры. Но тогда это вызывает SOIL_load_ogl_texture()
с флагом, запрашивающим создание нового идентификатора, и затем сохраняющим его:
m_Textures[i] = SOIL_load_OGL_texture(
m_TextureNames[i].c_str(),
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
);
Чтобы это исправить, вы можете опустить gGenTextures()
вызовите и переместите код для привязки текстуры и вызова glTexParameteri()
после SOIL_load_ogl_texture()
вызов. Кроме того, здесь используется флаг для создания мип-карт, но в фильтрах текстур не используется мип-карт.
В функции рисования она перебирает 6 граней, но каждый раз рисует весь куб:
for (int i=0;i<6;i++)
{
glPushMatrix();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Textures[i]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, m_Indices);
glPopMatrix();
}
Второй аргумент glDrawElements()
определяет количество вершин для визуализации. При значении 36 будут использоваться все вершины (6 сторон куба, по 2 треугольника в каждом, по 3 вершины в каждой).
Так же glPushMatrix()
/glPopMatrix()
не служит абсолютно никакой цели. Цикл рисования должен выглядеть примерно так:
glActiveTexture(GL_TEXTURE0);
for (int i=0;i<6;i++)
{
glBindTexture(GL_TEXTURE_2D, m_Textures[i]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, m_Indices + i * 6);
}
Я не вижу, чтобы тест глубины был включен нигде. Добавьте это к setup()
:
glEnable(GL_DEPTH_TEST);
Я делаю это немного по-другому, так что, возможно, проблема в разнице.
Я бы привязал каждую текстуру к отдельной GL_Texture (GL_Texture0, GL_Texture1 …), чтобы каждая текстура имела свои собственные данные. Я не знаю, как работает SOIL, но в моем случае для первой текстуры после:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
Я бы включил звонок:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture1Width, texture1Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmapData);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Textures[0]);
И я бы повторил этот процесс для каждой из 6 текстур.
Тогда я бы нарисовал каждое лицо:
// First face
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Textures[0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, m_Indices);
// Second face
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_Textures[1]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, m_Indices);
И так для каждого лица.
РЕДАКТИРОВАТЬ:
Я провел некоторую проверку на предмет SOIL, и мне кажется (используя SOIL) вы бы:
GLuint m_Textures[6];
int img_width, img_height;
glGenTextures(6, m_Textures);
// For each texture
unsigned char* img = SOIL_load_image(m_TextureNames[0].c_str(), &img_width, &img_height, NULL, 0); // or m_TextureNames[1].c_str() ...
glBindTexture(GL_TEXTURE_2D, m_Textures[0]); // or m_textures[1]...
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture filtering
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // NOTE the GL_NEAREST Here!
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); // NOTE the GL_NEAREST Here!
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img_width, img_height, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
glActiveTexture(GL_TEXTURE0); // or GL_TEXTURE1....
glBindTexture(GL_TEXTURE_2D, m_Textures[0]); // or m_Textures[1]...