Текстура не накладывается на сферу
Пытаюсь налижить текстуру на сферу в OpenGL c помощью UV-параметризации.
Написал следующий код, но текстура не накладывается:
#define _USE_MATH_DEFINES
#define _CRT_SECURE_NO_WARNINGS
#include "glew.h"
#include "glut.h"
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
typedef struct
{
GLbyte identsize; // Size of ID field that follows header(0)
GLbyte colorMapType; // 0 = None, 1 = paletted
GLbyte imageType; // 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8 = rle
unsigned short colorMapStart; // First colour map entry
unsigned short colorMapLength; // Number of colors
unsigned char colorMapBits; // bits per palette entry
unsigned short xstart; // image x origin
unsigned short ystart; // image y origin
unsigned short width; // width in pixels
unsigned short height; // height in pixels
GLbyte bits; // bits per pixel (8 16, 24, 32)
GLbyte descriptor; // image descriptor
} TGAHEADER;
GLbyte* gltLoadTGA(const char* szFileName, GLint* iWidth, GLint* iHeight,
GLint* iComponents, GLenum* eFormat)
{
FILE* pFile; // File pointer
TGAHEADER tgaHeader; // TGA file header
unsigned long lImageSize; // Size in bytes of image
short sDepth; // Pixel depth;
GLbyte* pBits = NULL; // Pointer to bits
// Default/Failed values
*iWidth = 0;
*iHeight = 0;
*eFormat = GL_BGR_EXT;
*iComponents = GL_RGB8;
// Attempt to open the file
pFile = fopen(szFileName, "rb");
if (pFile == NULL) return NULL;
// Read in header (binary)
fread(&tgaHeader, 18, 1, pFile);
// Do byte swap for big vs little endian
#ifdef __APPLE__
BYTE_SWAP(tgaHeader.colorMapStart);
BYTE_SWAP(tgaHeader.colorMapLength);
BYTE_SWAP(tgaHeader.xstart);
BYTE_SWAP(tgaHeader.ystart);
BYTE_SWAP(tgaHeader.width);
BYTE_SWAP(tgaHeader.height);
#endif
// Get width, height, and depth of texture
* iWidth = tgaHeader.width;
*iHeight = tgaHeader.height;
sDepth = tgaHeader.bits / 8;
// Put some validity checks here. Very simply, I only understand
// or care about 8, 24, or 32 bit targa's.
if (tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32)
return NULL;
// Calculate size of image buffer
lImageSize = tgaHeader.width * tgaHeader.height * sDepth;
// Allocate memory and check for success
pBits = (GLbyte*)malloc(lImageSize * sizeof(GLbyte));
if (pBits == NULL) return NULL;
// Read in the bits
// Check for read error. This should catch RLE or other
// weird formats that I don't want to recognize
if (fread(pBits, lImageSize, 1, pFile) != 1)
{
free(pBits);
return NULL;
}
// Set OpenGL format expected
switch (sDepth)
{
case 3: // Most likely case
*eFormat = GL_BGR_EXT;
*iComponents = GL_RGB8;
break;
case 4:
*eFormat = GL_BGRA_EXT;
*iComponents = GL_RGBA8;
break;
case 1:
*eFormat = GL_LUMINANCE;
*iComponents = GL_LUMINANCE8;
break;
};
// Done with File
fclose(pFile);
// Return pointer to image data
return pBits;
}
void uvSphere(float radius, int slices, int stacks) {
for (int i = 0; i <= stacks; ++i) {
float v = i / (float)stacks;
float phi = v * M_PI;
for (int j = 0; j <= slices; ++j) {
float u = j / (float)slices;
float theta = u * 2 * M_PI;
float x = cos(theta) * sin(phi);
float y = cos(phi);
float z = sin(theta) * sin(phi);
glTexCoord2f(u, v);
glNormal3f(x, y, z);
glVertex3f(x * radius, y * radius, z * radius);
}
}
}
GLuint textureID;
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Установка матрицы проекции
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (float)glutGet(GLUT_WINDOW_WIDTH) / (float)glutGet(GLUT_WINDOW_HEIGHT), 0.1f, 100.0f);
// Установка матрицы модели
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Поворот сферы
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
// Перемещение камеры вглубь сцены
glTranslatef(0.0f, 0.0f, -5.0f);
// Установка цвета
glColor3f(1.0f, 1.0f, 1.0f);
// Включение текстурирования
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID);
// Рисование сферы
glBegin(GL_QUADS);
uvSphere(1.0f, 20, 20);
glEnd();
// Отключение текстурирования
glDisable(GL_TEXTURE_2D);
glutSwapBuffers();
}
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_UP) xRot -= 5.0f;
if (key == GLUT_KEY_DOWN) xRot += 5.0f;
if (key == GLUT_KEY_LEFT) yRot -= 5.0f;
if (key == GLUT_KEY_RIGHT) yRot += 5.0f;
xRot = (GLfloat)((const int)xRot % 360);
yRot = (GLfloat)((const int)yRot % 360);
// Refresh the Window
glutPostRedisplay();
}
void reshape(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (float)width / (float)height, 0.1f, 100.0f);
}
void SetupRC() {
// Включение тестирования глубины
glEnable(GL_DEPTH_TEST);
GLubyte* pBytes;
GLint iWidth, iHeight, iComponents;
GLenum eFormat;
pBytes = (GLubyte*)gltLoadTGA("planet 1024.tga", &iWidth, &iHeight, &iComponents,
&eFormat);
glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat,
GL_UNSIGNED_BYTE, pBytes);
free(pBytes);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_TEXTURE_2D);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutCreateWindow("Sphere UV Parametrization with Texture");
glutInitWindowSize(800, 800);
// Настройка контекста рендеринга
SetupRC();
// Регистрация функций обратного вызова
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutSpecialFunc(SpecialKeys);
// Запуск главного цикла GLUT
glutMainLoop();
return 0;
}