OpenGL 蓝书学习(第四版)第八章
OpenGL 蓝书学习(第四版)第八章
欢迎来到第八章纹理的学习
金字塔(四棱锥)
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#else
extern "C" {
#include <GL/freeglut.h>
}
#endif
#include <iostream>
#include <fstream>
#include <format>
#include <vector>
// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度
static GLfloat xPos = 0.0F; // x位置
static GLfloat yPos = 0.0F; // y位置
static GLfloat zPos = 0.0F; // z位置
// Targa 图像文件头结构体
#pragma pack(push, 1) // 关闭结构体对齐填充
struct TargaHeader {
// 图像 ID 区长度,0 = 无
GLubyte idLength;
GLubyte colorMapType; // 0 = 无调色板
GLubyte dataTypeCode; // 图像数据类型代码 2 = 未压缩真彩图(非 RLE)
GLushort colorMapOrigin; // 调色板起始索引
GLushort colorMapLength; // 调色板颜色的数量
GLubyte colorMapDepth; // 调色板每条颜色的位数
GLushort xOrigin; // 图像在屏幕上的 X 坐标
GLushort yOrigin; // 图像在屏幕上的 Y 坐标
GLushort width; // 图像宽度
GLushort height; // 图像高度
// 每像素 24 位 = RGB 各 8 位
GLubyte bitsPerPixel;
// 0 表示自下而上存储
GLubyte imageDescriptor;
};
#pragma pack(pop) // 恢复结构体对齐填充
std::ostream& operator<<(std::ostream& os, const TargaHeader& header) {
os << "TargaHeader { "
<< "idLength=" << static_cast<int>(header.idLength) << ", "
<< "colorMapType=" << static_cast<int>(header.colorMapType) << ", "
<< "dataTypeCode=" << static_cast<int>(header.dataTypeCode) << ", "
<< "colorMapOrigin=" << header.colorMapOrigin << ", "
<< "colorMapLength=" << header.colorMapLength << ", "
<< "colorMapDepth=" << static_cast<int>(header.colorMapDepth) << ", "
<< "xOrigin=" << header.xOrigin << ", "
<< "yOrigin=" << header.yOrigin << ", "
<< "width=" << header.width << ", "
<< "height=" << header.height << ", "
<< "bitsPerPixel=" << static_cast<int>(header.bitsPerPixel) << ", "
<< "imageDescriptor=" << static_cast<int>(header.imageDescriptor)
<< " }";
return os;
}
void changeSize(const int w, int h) {
if (h == 0) h = 1; // Prevent division by zero
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, static_cast<double>(w) / static_cast<double>(h), 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// 用三角形三个顶点求面法线(右手定则叉乘 + 归一化),并设为当前法线。
// 顶点顺序需与 glVertex3f 一致:CCW 正面时法线指向观察者。
void setFaceNormal(const GLfloat ax[3],
const GLfloat bx[3],
const GLfloat cx[3]) {
const GLfloat ux = bx[0] - ax[0], uy = bx[1] - ax[1], uz = bx[2] - ax[2];
const GLfloat vx = cx[0] - ax[0], vy = cx[1] - ax[1], vz = cx[2] - ax[2];
GLfloat nx = uy * vz - uz * vy;
GLfloat ny = uz * vx - ux * vz;
GLfloat nz = ux * vy - uy * vx;
const GLfloat len = std::sqrt(nx * nx + ny * ny + nz * nz);
if (len > 0.0F) {
nx /= len;
ny /= len;
nz /= len;
}
glNormal3f(nx, ny, nz);
}
void renderScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0f, -0.5f, -3.0f);
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glRotatef(zRot, 0.0f, 0.0f, 1.0f);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLES);
// 底部
constexpr GLfloat vertices[][3] = {
{ 0.0F, 0.8F, 0.0F }, // 顶 0
{ -0.5F, 0.0F, -0.5F },// 左后. 1
{ 0.5F, 0.0F, -0.5F }, // 右后. 2
{ 0.5F, 0.0F, 0.5F }, // 右前 3
{ -0.5F, 0.0F, 0.5F }, // 左前 4
};
// 底部
glNormal3f(0.0F, -1.0F, 0.0F);
glTexCoord2f(1.0F, 1.0F);
glVertex3fv(vertices[2]);
glTexCoord2f(0.0F, 0.0F);
glVertex3fv(vertices[4]);
glTexCoord2f(0.0F, 1.0F);
glVertex3fv(vertices[1]);
glTexCoord2f(1.0F, 1.0F);
glVertex3fv(vertices[2]);
glTexCoord2f(1.0F, 0.0F);
glVertex3fv(vertices[3]);
glTexCoord2f(0.0F, 0.0F);
glVertex3fv(vertices[4]);
// 正面
setFaceNormal(vertices[0], vertices[4], vertices[3]);
glTexCoord2f(0.5F, 1.0F);
glVertex3fv(vertices[0]);
glTexCoord2f(0.0F, 0.0F);
glVertex3fv(vertices[4]);
glTexCoord2f(1.0F, 0.0F);
glVertex3fv(vertices[3]);
// 左面
setFaceNormal(vertices[0], vertices[1], vertices[4]);
glTexCoord2f(0.5F, 1.0F);
glVertex3fv(vertices[0]);
glTexCoord2f(0.0F, 0.0F);
glVertex3fv(vertices[1]);
glTexCoord2f(1.0F, 0.0F);
glVertex3fv(vertices[4]);
// 右面
setFaceNormal(vertices[0], vertices[3], vertices[2]);
glTexCoord2f(0.5F, 1.0F);
glVertex3fv(vertices[0]);
glTexCoord2f(0.0F, 0.0F);
glVertex3fv(vertices[3]);
glTexCoord2f(1.0F, 0.0F);
glVertex3fv(vertices[2]);
// 背面
setFaceNormal(vertices[0], vertices[2], vertices[1]);
glTexCoord2f(0.5F, 1.0F);
glVertex3fv(vertices[0]);
glTexCoord2f(0.0F, 0.0F);
glVertex3fv(vertices[2]);
glTexCoord2f(1.0F, 0.0F);
glVertex3fv(vertices[1]);
glEnd();
glPopMatrix();
glutSwapBuffers();
}
void setupRc() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_DEPTH_TEST); // Hidden surface removal
glFrontFace(GL_CCW); // Counter clock-wise polygons face out
glEnable(GL_CULL_FACE); // Do not calculate inside of jet
// 灯光
GLfloat whiteLight[] = { 0.05f, 0.05f, 0.05f, 1.0f };
GLfloat sourceLight[] = { 0.25f, 0.25f, 0.25f, 1.0f };
GLfloat lightPos[] = { -10.f, 5.0f, 5.0f, 1.0f };
// Enable lighting
glEnable(GL_LIGHTING);
// Setup and enable light 0
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, whiteLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, sourceLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, sourceLight);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
// 加载纹理
std::ifstream file("../stone.tga", std::ios::binary);
if (!file.is_open()) {
throw std::runtime_error("Failed to open stone.tga");
}
TargaHeader header;
file.read(reinterpret_cast<char*>(&header), sizeof(TargaHeader));
if(file.fail()) {
throw std::runtime_error("Failed to read Targa header from stone.tga");
}
std::cout << "Targa header: " << header << std::endl;
const std::size_t imageSize = header.width * header.height * (header.bitsPerPixel / 8);
std::vector<char> imageData(imageSize);
file.read(imageData.data(), imageSize);
if(file.fail()) {
throw std::runtime_error("Failed to read Targa image data from stone.tga");
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, header.width, header.height, 0, GL_BGR, GL_UNSIGNED_BYTE, imageData.data());
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);
}
// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
switch (key) {
case 27: // ESC 键
case 'q':
case 'Q':
std::cout << "keyboard close..." << "\n";
std::exit(0);
break;
case 'a':
case 'A':
zRot -= 5.0F; // 绕 Z 轴逆时针旋转
glutPostRedisplay();
break;
case 'd':
case 'D':
zRot += 5.0F; // 绕 Z 轴顺时针旋转
glutPostRedisplay();
break;
case 'w':
case 'W':
yPos += 0.1F; // 向上移动
glutPostRedisplay();
break;
case 's':
case 'S':
yPos -= 0.1F; // 向下移动
glutPostRedisplay();
break;
case 'z':
case 'Z':
xPos += 0.1F; // 向前移动
glutPostRedisplay();
break;
case 'x':
case 'X':
xPos -= 0.1F; // 向后移动
glutPostRedisplay();
break;
case 'c':
case 'C':
zPos += 0.1F; // 向前移动
glutPostRedisplay();
break;
case 'v':
case 'V':
zPos -= 0.1F; // 向后移动
glutPostRedisplay();
break;
default:
break;
}
}
void specialKeys(const int key, const int x, const int y) {
std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
switch (key) {
case GLUT_KEY_UP:
xRot -= 5.0F;
break;
case GLUT_KEY_DOWN:
xRot += 5.0F;
break;
case GLUT_KEY_LEFT:
yRot -= 5.0F;
break;
case GLUT_KEY_RIGHT:
yRot += 5.0F;
break;
default:
break;
}
// Refresh the Window
glutPostRedisplay();
}
auto main(const int argc, const char** argv) -> int {
std::cout << "Hello, World!" << std::endl;
glutInit(const_cast<int*>(&argc), const_cast<char**>(argv));
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
const int mainWindowId = glutCreateWindow("OpenGL");
if (!mainWindowId) {
throw std::runtime_error("Failed to create OpenGL window");
}
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutSpecialFunc(specialKeys); // 特殊键事件
glutKeyboardFunc(keyboard); // 普通键事件
setupRc();
glutMainLoop();
return 0;
}
卡通纹理
#include <iosfwd>
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#else
extern "C" {
#include <GL/freeglut.h>
}
#endif
#include <iostream>
#include <format>
#include <numbers>
// 常量
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLfloat vLightDir[3] = { -1.0F, 1.0F, 1.0F }; // 眼睛坐标
// 变量
static GLfloat xRot = 0.0F; // x旋转角度
static GLfloat yRot = 0.0F; // y旋转角度
static GLfloat zRot = 0.0F; // z旋转角度
static GLfloat xPos = 0.0F; // x位置
static GLfloat yPos = 0.0F; // y位置
static GLfloat zPos = 0.0F; // z位置
void changeSize(const int w, int h) {
if (h == 0) h = 1; // Prevent division by zero
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, static_cast<double>(w) / static_cast<double>(h), 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void normalize(GLfloat v[3]) {
const GLfloat len = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
if (len > 0.0F) {
v[0] /= len;
v[1] /= len;
v[2] /= len;
}
}
GLfloat toonShade(const GLfloat n[3], const GLfloat m[16], const GLfloat light[3]) {
GLfloat e[3] = {
m[0] * n[0] + m[4] * n[1] + m[8] * n[2],
m[1] * n[0] + m[5] * n[1] + m[9] * n[2],
m[2] * n[0] + m[6] * n[1] + m[10] * n[2],
};
normalize(e);
return light[0] * e[0] + light[1] * e[1] + light[2] * e[2];
}
void drawTorus(const GLfloat majorRadius, const GLfloat minorRadius, const int numMajor, const int numMinor) {
GLfloat modelViewMatrix[16];
// 获取当前模型视图矩阵
glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix);
GLfloat lightDir[3] = { vLightDir[0], vLightDir[1], vLightDir[2] };
normalize(lightDir);
const GLfloat majorStep = 2.0F * PI / static_cast<GLfloat>(numMajor);
const GLfloat minorStep = 2.0F * PI / static_cast<GLfloat>(numMinor);
for (int i = 0; i < numMajor; ++i) {
const GLfloat u0 = i * majorStep;
const GLfloat u1 = u0 + majorStep;
glBegin(GL_TRIANGLE_STRIP);
for (int j = 0; j <= numMinor; ++j) {
const GLfloat v0 = j * minorStep;
// 计算两个顶点的坐标
const GLfloat n0[3] = {
std::cos(v0) * std::cos(u0),
std::cos(v0) * std::sin(u0),
std::sin(v0)
};
const GLfloat x00 = (majorRadius + minorRadius * std::cos(v0)) * std::cos(u0);
const GLfloat y00 = (majorRadius + minorRadius * std::cos(v0)) * std::sin(u0);
const GLfloat z00 = minorRadius * std::sin(v0);
const GLfloat n1[3] = {
std::cos(v0) * std::cos(u1),
std::cos(v0) * std::sin(u1),
std::sin(v0)
};
const GLfloat x01 = (majorRadius + minorRadius * std::cos(v0)) * std::cos(u1);
const GLfloat y01 = (majorRadius + minorRadius * std::cos(v0)) * std::sin(u1);
const GLfloat z01 = minorRadius * std::sin(v0);
glTexCoord1f(toonShade(n0, modelViewMatrix, lightDir)); // s = N·L
glVertex3f(x00, y00, z00);
glTexCoord1f(toonShade(n1, modelViewMatrix, lightDir)); // s = N·L
glVertex3f(x01, y01, z01);
}
glEnd();
}
}
void renderScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0F, 0.0F, -4.0F);
glRotatef(xRot, 1.0F, 0.0F, 0.0F);
glRotatef(yRot, 0.0F, 1.0F, 0.0F);
glRotatef(zRot, 0.0F, 0.0F, 1.0F);
glColor3f(1.0f, 1.0f, 1.0f);
drawTorus(1.0F, 0.3F, 32, 16);
glPopMatrix();
glutSwapBuffers();
}
void setupRc() {
glClearColor(0.0f, 0.0f, 0.5f, 1.0f);
glEnable(GL_DEPTH_TEST); // Hidden surface removal
glFrontFace(GL_CCW); // Counter clock-wise polygons face out
glEnable(GL_CULL_FACE); // Do not calculate inside of jet
// 加载1d纹理
constexpr GLubyte toonTable[][3] = {
{0, 32, 0},
{0, 64, 0},
{0, 128, 0},
{0, 192, 0},
};
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// s = N·L (法线与光线方向的点积,范围 -1 … 1) s 超出 [0,1] 钳到边缘
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 4, 0, GL_RGB, GL_UNSIGNED_BYTE, toonTable);
glEnable(GL_TEXTURE_1D);
}
// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
switch (key) {
case 27: // ESC 键
case 'q':
case 'Q':
std::cout << "keyboard close..." << "\n";
std::exit(0);
break;
case 'a':
case 'A':
zRot -= 5.0F; // 绕 Z 轴逆时针旋转
glutPostRedisplay();
break;
case 'd':
case 'D':
zRot += 5.0F; // 绕 Z 轴顺时针旋转
glutPostRedisplay();
break;
case 'w':
case 'W':
yPos += 0.1F; // 向上移动
glutPostRedisplay();
break;
case 's':
case 'S':
yPos -= 0.1F; // 向下移动
glutPostRedisplay();
break;
case 'z':
case 'Z':
xPos += 0.1F; // 向前移动
glutPostRedisplay();
break;
case 'x':
case 'X':
xPos -= 0.1F; // 向后移动
glutPostRedisplay();
break;
case 'c':
case 'C':
zPos += 0.1F; // 向前移动
glutPostRedisplay();
break;
case 'v':
case 'V':
zPos -= 0.1F; // 向后移动
glutPostRedisplay();
break;
default:
break;
}
}
void specialKeys(const int key, const int x, const int y) {
std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
switch (key) {
case GLUT_KEY_UP:
xRot -= 5.0F;
break;
case GLUT_KEY_DOWN:
xRot += 5.0F;
break;
case GLUT_KEY_LEFT:
yRot -= 5.0F;
break;
case GLUT_KEY_RIGHT:
yRot += 5.0F;
break;
default:
break;
}
// Refresh the Window
glutPostRedisplay();
}
auto main(const int argc, const char** argv) -> int {
std::cout << "Hello, World!" << std::endl;
glutInit(const_cast<int*>(&argc), const_cast<char**>(argv));
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
const int mainWindowId = glutCreateWindow("OpenGL");
if (!mainWindowId) {
throw std::runtime_error("Failed to create OpenGL window");
}
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutSpecialFunc(specialKeys); // 特殊键事件
glutKeyboardFunc(keyboard); // 普通键事件
setupRc();
glutMainLoop();
return 0;
}
mip过滤
#include <OpenGL/gltypes.h>
#include <OpenGL/glu.h>
#include <array>
#include <iosfwd>
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#else
extern "C" {
#include <GL/freeglut.h>
}
#endif
#include <iostream>
#include <format>
#include <numbers>
#include <fstream>
#include <vector>
// 常量
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLuint NUM_TEXTURES = 3;
static constexpr std::array<std::string, NUM_TEXTURES> textureFiles = {
"../brick.tga", // 0 砖块
"../floor.tga", // 1 地板
"../ceiling.tga" // 2 天花板
};
// 变量
static GLfloat zPos = -60.0F; // z位置
static int mainWindowId; // 主窗口 ID
static GLuint textureIds[NUM_TEXTURES];
// Targa 图像文件头结构体
#pragma pack(push, 1) // 关闭结构体对齐填充
struct TargaHeader {
// 图像 ID 区长度,0 = 无
GLubyte idLength;
GLubyte colorMapType; // 0 = 无调色板
GLubyte dataTypeCode; // 图像数据类型代码 2 = 未压缩真彩图(非 RLE)
GLushort colorMapOrigin; // 调色板起始索引
GLushort colorMapLength; // 调色板颜色的数量
GLubyte colorMapDepth; // 调色板每条颜色的位数
GLushort xOrigin; // 图像在屏幕上的 X 坐标
GLushort yOrigin; // 图像在屏幕上的 Y 坐标
GLushort width; // 图像宽度
GLushort height; // 图像高度
// 每像素 24 位 = RGB 各 8 位
GLubyte bitsPerPixel;
// 0 表示自下而上存储
GLubyte imageDescriptor;
};
#pragma pack(pop) // 恢复结构体对齐填充
std::ostream& operator<<(std::ostream& os, const TargaHeader& header) {
os << "TargaHeader { "
<< "idLength=" << static_cast<int>(header.idLength) << ", "
<< "colorMapType=" << static_cast<int>(header.colorMapType) << ", "
<< "dataTypeCode=" << static_cast<int>(header.dataTypeCode) << ", "
<< "colorMapOrigin=" << header.colorMapOrigin << ", "
<< "colorMapLength=" << header.colorMapLength << ", "
<< "colorMapDepth=" << static_cast<int>(header.colorMapDepth) << ", "
<< "xOrigin=" << header.xOrigin << ", "
<< "yOrigin=" << header.yOrigin << ", "
<< "width=" << header.width << ", "
<< "height=" << header.height << ", "
<< "bitsPerPixel=" << static_cast<int>(header.bitsPerPixel) << ", "
<< "imageDescriptor=" << static_cast<int>(header.imageDescriptor)
<< " }";
return os;
}
void changeSize(const int w, int h) {
if (h == 0) h = 1; // Prevent division by zero
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, static_cast<double>(w) / static_cast<double>(h), 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void normalize(GLfloat v[3]) {
const GLfloat len = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
if (len > 0.0F) {
v[0] /= len;
v[1] /= len;
v[2] /= len;
}
}
GLfloat toonShade(const GLfloat n[3], const GLfloat m[16], const GLfloat light[3]) {
GLfloat e[3] = {
m[0] * n[0] + m[4] * n[1] + m[8] * n[2],
m[1] * n[0] + m[5] * n[1] + m[9] * n[2],
m[2] * n[0] + m[6] * n[1] + m[10] * n[2],
};
normalize(e);
return light[0] * e[0] + light[1] * e[1] + light[2] * e[2];
}
void renderScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0F, 0.0F, zPos);
for(GLfloat z = 60.0F; z >= 0.0F; z -= 10.0F){
// 地板
glBindTexture(GL_TEXTURE_2D, textureIds[1]); // 绑定第一个纹理
glBegin(GL_QUADS);
glTexCoord2f(0.0F, 0.0F);
glVertex3f(-10.0F, -10.0F, z);
glTexCoord2f(1.0F, 0.0F);
glVertex3f( 10.0F, -10.0F, z);
glTexCoord2f(1.0F, 1.0F);
glVertex3f( 10.0F, -10.0F, z - 10.0F);
glTexCoord2f(0.0F, 1.0F);
glVertex3f(-10.0F, -10.0F, z - 10.0F);
glEnd();
// 天花板
glBindTexture(GL_TEXTURE_2D, textureIds[2]); // 绑定天花板纹理
glBegin(GL_QUADS);
glTexCoord2f(0.0F, 1.0F);
glVertex3f(-10.0F, 10.0F, z - 10.0F);
glTexCoord2f(1.0F, 1.0F);
glVertex3f( 10.0F, 10.0F, z - 10.0F);
glTexCoord2f(1.0F, 0.0F);
glVertex3f( 10.0F, 10.0F, z);
glTexCoord2f(0.0F, 0.0F);
glVertex3f(-10.0F, 10.0F, z);
glEnd();
// 左
glBindTexture(GL_TEXTURE_2D, textureIds[0]); // 绑定左墙纹理
glBegin(GL_QUADS);
glTexCoord2f(0.0F, 0.0F);
glVertex3f(-10.0F, -10.0F, z);
glTexCoord2f(1.0F, 0.0F);
glVertex3f(-10.0F, -10.0F, z - 10.0F);
glTexCoord2f(1.0F, 1.0F);
glVertex3f(-10.0F, 10.0F, z - 10.0F);
glTexCoord2f(0.0F, 1.0F);
glVertex3f(-10.0F, 10.0F, z);
glEnd();
// 右
glBindTexture(GL_TEXTURE_2D, textureIds[0]); // 绑定右墙纹理
glBegin(GL_QUADS);
glTexCoord2f(0.0F, 1.0F);
glVertex3f(10.0F, 10.0F, z);
glTexCoord2f(1.0F, 1.0F);
glVertex3f(10.0F, 10.0F, z - 10.0F);
glTexCoord2f(1.0F, 0.0F);
glVertex3f(10.0F, -10.0F, z - 10.0F);
glTexCoord2f(0.0F, 0.0F);
glVertex3f(10.0F, -10.0F, z);
glEnd();
}
glPopMatrix();
glutSwapBuffers();
}
void setupRc() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 开启2d纹理
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glGenTextures(NUM_TEXTURES, textureIds);
for (GLuint i = 0; i < NUM_TEXTURES; ++i) {
glBindTexture(GL_TEXTURE_2D, textureIds[i]);
// 加载纹理数据
std::ifstream file(textureFiles[i], std::ios::binary);
if (!file.is_open()) {
throw std::runtime_error("Failed to open " + textureFiles[i]);
}
TargaHeader header;
file.read(reinterpret_cast<char*>(&header), sizeof(TargaHeader));
if(file.fail()) {
throw std::runtime_error("Failed to read Targa header from " + textureFiles[i]);
}
std::cout << "Targa header: " << header << std::endl;
const std::size_t imageSize = header.width * header.height * (header.bitsPerPixel / 8);
std::vector<char> imageData(imageSize);
file.read(imageData.data(), imageSize);
if(file.fail()) {
throw std::runtime_error("Failed to read Targa image data from " + textureFiles[i]);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, header.width, header.height, GL_BGR, GL_UNSIGNED_BYTE, imageData.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);
}
}
void shutdownRc() {
glDeleteTextures(NUM_TEXTURES, textureIds);
}
// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
switch (key) {
case 27: // ESC 键
case 'q':
case 'Q':
std::cout << "keyboard close..." << "\n";
std::exit(0);
break;
case 'a':
case 'A':
break;
case 'd':
case 'D':
// glutPostRedisplay();
break;
case 'w':
case 'W':
break;
case 's':
case 'S':
break;
case 'z':
case 'Z':
break;
case 'x':
case 'X':
break;
case 'c':
case 'C':
break;
case 'v':
case 'V':
break;
default:
break;
}
}
void specialKeys(const int key, const int x, const int y) {
std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
switch (key) {
case GLUT_KEY_UP:
zPos += 1.0f;
break;
case GLUT_KEY_DOWN:
zPos -= 1.0f;
break;
case GLUT_KEY_LEFT:
break;
case GLUT_KEY_RIGHT:
break;
default:
break;
}
// Refresh the Window
glutPostRedisplay();
}
void processMenu(const int value) {
std::cout << std::format("Menu selected: {}", value) << "\n";
for(GLuint i = 0; i < NUM_TEXTURES; ++i) {
glBindTexture(GL_TEXTURE_2D, textureIds[i]);
switch (value) {
case 0:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
case 1:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
break;
case 2:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
break;
case 3:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
break;
case 4:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
break;
case 5:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
break;
}
}
glutSetWindow(mainWindowId);
glutPostRedisplay();
}
auto main(const int argc, const char** argv) -> int {
std::cout << "Hello, World!" << std::endl;
glutInit(const_cast<int*>(&argc), const_cast<char**>(argv));
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
mainWindowId = glutCreateWindow("OpenGL");
if (!mainWindowId) {
throw std::runtime_error("Failed to create OpenGL window");
}
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutSpecialFunc(specialKeys); // 特殊键事件
glutKeyboardFunc(keyboard); // 普通键事件
glutCreateMenu(processMenu);
glutAddMenuEntry("GL_NEAREST",0);
glutAddMenuEntry("GL_LINEAR",1);
glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST",2);
glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 3);
glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);
glutAttachMenu(GLUT_RIGHT_BUTTON);
setupRc();
glutMainLoop();
return 0;
}
对球进行纹理贴图
#include <OpenGL/gltypes.h>
#include <OpenGL/glu.h>
#include <array>
#include <iosfwd>
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#else
extern "C" {
#include <GL/freeglut.h>
}
#endif
#include <iostream>
#include <format>
#include <numbers>
#include <fstream>
#include <vector>
// 常量
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLuint NUM_TEXTURES = 3;
static constexpr std::array<std::string, NUM_TEXTURES> textureFiles = {
"../brick.tga", // 0 砖块
"../floor.tga", // 1 地板
"../ceiling.tga" // 2 天花板
};
// 变量
static GLfloat xRot = 0.0F; // z位置
static GLfloat yRot = 0.0F; // z位置
static GLfloat zRot = 0.0F; // z位置
static GLfloat zPos = -4.0F; // z位置
static int mainWindowId; // 主窗口 ID
static GLuint textureIds[NUM_TEXTURES];
// Targa 图像文件头结构体
#pragma pack(push, 1) // 关闭结构体对齐填充
struct TargaHeader {
// 图像 ID 区长度,0 = 无
GLubyte idLength;
GLubyte colorMapType; // 0 = 无调色板
GLubyte dataTypeCode; // 图像数据类型代码 2 = 未压缩真彩图(非 RLE)
GLushort colorMapOrigin; // 调色板起始索引
GLushort colorMapLength; // 调色板颜色的数量
GLubyte colorMapDepth; // 调色板每条颜色的位数
GLushort xOrigin; // 图像在屏幕上的 X 坐标
GLushort yOrigin; // 图像在屏幕上的 Y 坐标
GLushort width; // 图像宽度
GLushort height; // 图像高度
// 每像素 24 位 = RGB 各 8 位
GLubyte bitsPerPixel;
// 0 表示自下而上存储
GLubyte imageDescriptor;
};
#pragma pack(pop) // 恢复结构体对齐填充
std::ostream& operator<<(std::ostream& os, const TargaHeader& header) {
os << "TargaHeader { "
<< "idLength=" << static_cast<int>(header.idLength) << ", "
<< "colorMapType=" << static_cast<int>(header.colorMapType) << ", "
<< "dataTypeCode=" << static_cast<int>(header.dataTypeCode) << ", "
<< "colorMapOrigin=" << header.colorMapOrigin << ", "
<< "colorMapLength=" << header.colorMapLength << ", "
<< "colorMapDepth=" << static_cast<int>(header.colorMapDepth) << ", "
<< "xOrigin=" << header.xOrigin << ", "
<< "yOrigin=" << header.yOrigin << ", "
<< "width=" << header.width << ", "
<< "height=" << header.height << ", "
<< "bitsPerPixel=" << static_cast<int>(header.bitsPerPixel) << ", "
<< "imageDescriptor=" << static_cast<int>(header.imageDescriptor)
<< " }";
return os;
}
void changeSize(const int w, int h) {
if (h == 0) h = 1; // Prevent division by zero
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, static_cast<double>(w) / static_cast<double>(h), 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void normalize(GLfloat v[3]) {
const GLfloat len = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
if (len > 0.0F) {
v[0] /= len;
v[1] /= len;
v[2] /= len;
}
}
GLfloat toonShade(const GLfloat n[3], const GLfloat m[16], const GLfloat light[3]) {
GLfloat e[3] = {
m[0] * n[0] + m[4] * n[1] + m[8] * n[2],
m[1] * n[0] + m[5] * n[1] + m[9] * n[2],
m[2] * n[0] + m[6] * n[1] + m[10] * n[2],
};
normalize(e);
return light[0] * e[0] + light[1] * e[1] + light[2] * e[2];
}
void drawSphere(const GLfloat radius, const GLint slices, const GLint stacks) {
const GLfloat sliceStep = 2.0F * PI / static_cast<GLfloat>(slices);
const GLfloat stackStep = PI / static_cast<GLfloat>(stacks);
for (GLint i = 0; i <= stacks; ++i) {
const GLfloat stackAngle1 = i * stackStep;
const GLfloat stackAngle2 = (i + 1) * stackStep;
glBegin(GL_TRIANGLE_STRIP);
for (GLint j = 0; j <= slices; ++j) {
const GLfloat sliceAngle1 = j * sliceStep;
const GLfloat sliceAngle2 = (j + 1) * sliceStep;
const GLfloat nx1 = std::sin(stackAngle1) * std::cos(sliceAngle1);
const GLfloat ny1 = std::cos(stackAngle1);
const GLfloat nz1 = std::sin(stackAngle1) * std::sin(sliceAngle1);
const GLfloat x1 = radius * nx1;
const GLfloat y1 = radius * ny1;
const GLfloat z1 = radius * nz1;
const GLfloat nx2 = std::sin(stackAngle2) * std::cos(sliceAngle1);
const GLfloat ny2 = std::cos(stackAngle2);
const GLfloat nz2 = std::sin(stackAngle2) * std::sin(sliceAngle1);
const GLfloat x2 = radius * nx2;
const GLfloat y2 = radius * ny2;
const GLfloat z2 = radius * nz2;
glNormal3f(nx1, ny1, nz1);
glTexCoord2f(static_cast<GLfloat>(j) / slices, // 左下角
1.0F - static_cast<GLfloat>(i) / stacks);
glVertex3f(x1, y1, z1);
glNormal3f(nx2, ny2, nz2);
glTexCoord2f(static_cast<GLfloat>(j) / slices,
1.0F - static_cast<GLfloat>(i + 1) / stacks);
glVertex3f(x2, y2, z2);
}
glEnd();
}
}
void renderScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0F, 0.0F, zPos);
glRotatef(xRot, 1.0F, 0.0F, 0.0F);
glRotatef(yRot, 0.0F, 1.0F, 0.0F);
glRotatef(zRot, 0.0F, 0.0F, 1.0F);
glBindTexture(GL_TEXTURE_2D, textureIds[0]);
drawSphere(1.0F, 36, 18);
glPopMatrix();
glutSwapBuffers();
}
void setupRc() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_DEPTH_TEST);
// 开启2d纹理
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glGenTextures(NUM_TEXTURES, textureIds);
for (GLuint i = 0; i < NUM_TEXTURES; ++i) {
glBindTexture(GL_TEXTURE_2D, textureIds[i]);
// 加载纹理数据
std::ifstream file(textureFiles[i], std::ios::binary);
if (!file.is_open()) {
throw std::runtime_error("Failed to open " + textureFiles[i]);
}
TargaHeader header;
file.read(reinterpret_cast<char*>(&header), sizeof(TargaHeader));
if(file.fail()) {
throw std::runtime_error("Failed to read Targa header from " + textureFiles[i]);
}
std::cout << "Targa header: " << header << std::endl;
const std::size_t imageSize = header.width * header.height * (header.bitsPerPixel / 8);
std::vector<char> imageData(imageSize);
file.read(imageData.data(), imageSize);
if(file.fail()) {
throw std::runtime_error("Failed to read Targa image data from " + textureFiles[i]);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, header.width, header.height, GL_BGR, GL_UNSIGNED_BYTE, imageData.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);
}
}
void shutdownRc() {
glDeleteTextures(NUM_TEXTURES, textureIds);
}
// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
switch (key) {
case 27: // ESC 键
case 'q':
case 'Q':
std::cout << "keyboard close..." << "\n";
std::exit(0);
break;
case 'a':
case 'A':
yRot -= 5.0F;
break;
case 'd':
case 'D':
yRot += 5.0F;
// glutPostRedisplay();
break;
case 'w':
case 'W':
xRot -= 5.0F;
break;
case 's':
case 'S':
xRot += 5.0F;
break;
case 'z':
case 'Z':
zRot -= 5.0F;
break;
case 'x':
case 'X':
zRot += 5.0F;
break;
case 'c':
case 'C':
break;
case 'v':
case 'V':
break;
default:
break;
}
glutPostRedisplay();
}
void specialKeys(const int key, const int x, const int y) {
std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
switch (key) {
case GLUT_KEY_UP:
zPos += 1.0f;
break;
case GLUT_KEY_DOWN:
zPos -= 1.0f;
break;
case GLUT_KEY_LEFT:
break;
case GLUT_KEY_RIGHT:
break;
default:
break;
}
// Refresh the Window
glutPostRedisplay();
}
void processMenu(const int value) {
std::cout << std::format("Menu selected: {}", value) << "\n";
for(GLuint i = 0; i < NUM_TEXTURES; ++i) {
glBindTexture(GL_TEXTURE_2D, textureIds[i]);
switch (value) {
case 0:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
case 1:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
break;
case 2:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
break;
case 3:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
break;
case 4:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
break;
case 5:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
break;
}
}
glutSetWindow(mainWindowId);
glutPostRedisplay();
}
auto main(const int argc, const char** argv) -> int {
std::cout << "Hello, World!" << std::endl;
glutInit(const_cast<int*>(&argc), const_cast<char**>(argv));
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
mainWindowId = glutCreateWindow("OpenGL");
if (!mainWindowId) {
throw std::runtime_error("Failed to create OpenGL window");
}
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutSpecialFunc(specialKeys); // 特殊键事件
glutKeyboardFunc(keyboard); // 普通键事件
glutCreateMenu(processMenu);
glutAddMenuEntry("GL_NEAREST",0);
glutAddMenuEntry("GL_LINEAR",1);
glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST",2);
glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 3);
glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);
glutAttachMenu(GLUT_RIGHT_BUTTON);
setupRc();
glutMainLoop();
return 0;
}
对圆环进行纹理贴图
#include <OpenGL/gltypes.h>
#include <OpenGL/glu.h>
#include <array>
#include <iosfwd>
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#else
extern "C" {
#include <GL/freeglut.h>
}
#endif
#include <iostream>
#include <format>
#include <numbers>
#include <fstream>
#include <vector>
// 常量
static constexpr GLfloat PI = std::numbers::pi_v<GLfloat>;
static constexpr GLuint NUM_TEXTURES = 3;
static constexpr std::array<std::string, NUM_TEXTURES> textureFiles = {
"../brick.tga", // 0 砖块
"../floor.tga", // 1 地板
"../ceiling.tga" // 2 天花板
};
// 变量
static GLfloat xRot = 0.0F; // z位置
static GLfloat yRot = 0.0F; // z位置
static GLfloat zRot = 0.0F; // z位置
static GLfloat zPos = -4.0F; // z位置
static int mainWindowId; // 主窗口 ID
static GLuint textureIds[NUM_TEXTURES];
// Targa 图像文件头结构体
#pragma pack(push, 1) // 关闭结构体对齐填充
struct TargaHeader {
// 图像 ID 区长度,0 = 无
GLubyte idLength;
GLubyte colorMapType; // 0 = 无调色板
GLubyte dataTypeCode; // 图像数据类型代码 2 = 未压缩真彩图(非 RLE)
GLushort colorMapOrigin; // 调色板起始索引
GLushort colorMapLength; // 调色板颜色的数量
GLubyte colorMapDepth; // 调色板每条颜色的位数
GLushort xOrigin; // 图像在屏幕上的 X 坐标
GLushort yOrigin; // 图像在屏幕上的 Y 坐标
GLushort width; // 图像宽度
GLushort height; // 图像高度
// 每像素 24 位 = RGB 各 8 位
GLubyte bitsPerPixel;
// 0 表示自下而上存储
GLubyte imageDescriptor;
};
#pragma pack(pop) // 恢复结构体对齐填充
std::ostream& operator<<(std::ostream& os, const TargaHeader& header) {
os << "TargaHeader { "
<< "idLength=" << static_cast<int>(header.idLength) << ", "
<< "colorMapType=" << static_cast<int>(header.colorMapType) << ", "
<< "dataTypeCode=" << static_cast<int>(header.dataTypeCode) << ", "
<< "colorMapOrigin=" << header.colorMapOrigin << ", "
<< "colorMapLength=" << header.colorMapLength << ", "
<< "colorMapDepth=" << static_cast<int>(header.colorMapDepth) << ", "
<< "xOrigin=" << header.xOrigin << ", "
<< "yOrigin=" << header.yOrigin << ", "
<< "width=" << header.width << ", "
<< "height=" << header.height << ", "
<< "bitsPerPixel=" << static_cast<int>(header.bitsPerPixel) << ", "
<< "imageDescriptor=" << static_cast<int>(header.imageDescriptor)
<< " }";
return os;
}
void changeSize(const int w, int h) {
if (h == 0) h = 1; // Prevent division by zero
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, static_cast<double>(w) / static_cast<double>(h), 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void normalize(GLfloat v[3]) {
const GLfloat len = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
if (len > 0.0F) {
v[0] /= len;
v[1] /= len;
v[2] /= len;
}
}
GLfloat toonShade(const GLfloat n[3], const GLfloat m[16], const GLfloat light[3]) {
GLfloat e[3] = {
m[0] * n[0] + m[4] * n[1] + m[8] * n[2],
m[1] * n[0] + m[5] * n[1] + m[9] * n[2],
m[2] * n[0] + m[6] * n[1] + m[10] * n[2],
};
normalize(e);
return light[0] * e[0] + light[1] * e[1] + light[2] * e[2];
}
void drawSphere(const GLfloat radius, const GLint slices, const GLint stacks) {
const GLfloat sliceStep = 2.0F * PI / static_cast<GLfloat>(slices);
const GLfloat stackStep = PI / static_cast<GLfloat>(stacks);
for (GLint i = 0; i <= stacks; ++i) {
const GLfloat stackAngle1 = i * stackStep;
const GLfloat stackAngle2 = (i + 1) * stackStep;
glBegin(GL_TRIANGLE_STRIP);
for (GLint j = 0; j <= slices; ++j) {
const GLfloat sliceAngle1 = j * sliceStep;
const GLfloat sliceAngle2 = (j + 1) * sliceStep;
const GLfloat nx1 = std::sin(stackAngle1) * std::cos(sliceAngle1);
const GLfloat ny1 = std::cos(stackAngle1);
const GLfloat nz1 = std::sin(stackAngle1) * std::sin(sliceAngle1);
const GLfloat x1 = radius * nx1;
const GLfloat y1 = radius * ny1;
const GLfloat z1 = radius * nz1;
const GLfloat nx2 = std::sin(stackAngle2) * std::cos(sliceAngle1);
const GLfloat ny2 = std::cos(stackAngle2);
const GLfloat nz2 = std::sin(stackAngle2) * std::sin(sliceAngle1);
const GLfloat x2 = radius * nx2;
const GLfloat y2 = radius * ny2;
const GLfloat z2 = radius * nz2;
glNormal3f(nx1, ny1, nz1);
glTexCoord2f(static_cast<GLfloat>(j) / slices, // 左下角
1.0F - static_cast<GLfloat>(i) / stacks);
glVertex3f(x1, y1, z1);
glNormal3f(nx2, ny2, nz2);
glTexCoord2f(static_cast<GLfloat>(j) / slices,
1.0F - static_cast<GLfloat>(i + 1) / stacks);
glVertex3f(x2, y2, z2);
}
glEnd();
}
}
void drawTorus(const GLfloat majorRadius, const GLfloat minorRadius, const int numMajor, const int numMinor) {
const GLfloat majorStep = 2.0F * PI / static_cast<GLfloat>(numMajor);
const GLfloat minorStep = 2.0F * PI / static_cast<GLfloat>(numMinor);
for (int i = 0; i < numMajor; ++i) {
const GLfloat u0 = i * majorStep;
const GLfloat u1 = u0 + majorStep;
glBegin(GL_TRIANGLE_STRIP);
for (int j = 0; j <= numMinor; ++j) {
const GLfloat v0 = j * minorStep;
// 计算两个顶点的坐标
const GLfloat n0[3] = {
std::cos(v0) * std::cos(u0),
std::cos(v0) * std::sin(u0),
std::sin(v0)
};
const GLfloat x00 = (majorRadius + minorRadius * std::cos(v0)) * std::cos(u0);
const GLfloat y00 = (majorRadius + minorRadius * std::cos(v0)) * std::sin(u0);
const GLfloat z00 = minorRadius * std::sin(v0);
const GLfloat n1[3] = {
std::cos(v0) * std::cos(u1),
std::cos(v0) * std::sin(u1),
std::sin(v0)
};
const GLfloat x01 = (majorRadius + minorRadius * std::cos(v0)) * std::cos(u1);
const GLfloat y01 = (majorRadius + minorRadius * std::cos(v0)) * std::sin(u1);
const GLfloat z01 = minorRadius * std::sin(v0);
glNormal3f(n0[0], n0[1], n0[2]);
glTexCoord2f(static_cast<GLfloat>(j) / numMinor, static_cast<GLfloat>(i) / numMajor);
glVertex3f(x00, y00, z00);
glNormal3f(n1[0], n1[1], n1[2]);
glTexCoord2f(static_cast<GLfloat>(j) / numMinor, static_cast<GLfloat>(i + 1) / numMajor);
glVertex3f(x01, y01, z01);
}
glEnd();
}
}
void renderScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0F, 0.0F, zPos);
glRotatef(xRot, 1.0F, 0.0F, 0.0F);
glRotatef(yRot, 0.0F, 1.0F, 0.0F);
glRotatef(zRot, 0.0F, 0.0F, 1.0F);
glBindTexture(GL_TEXTURE_2D, textureIds[0]);
drawTorus(1.0F, 0.3F, 32, 16);
glPopMatrix();
glutSwapBuffers();
}
void setupRc() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_DEPTH_TEST);
// 开启2d纹理
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glGenTextures(NUM_TEXTURES, textureIds);
for (GLuint i = 0; i < NUM_TEXTURES; ++i) {
glBindTexture(GL_TEXTURE_2D, textureIds[i]);
// 加载纹理数据
std::ifstream file(textureFiles[i], std::ios::binary);
if (!file.is_open()) {
throw std::runtime_error("Failed to open " + textureFiles[i]);
}
TargaHeader header;
file.read(reinterpret_cast<char*>(&header), sizeof(TargaHeader));
if(file.fail()) {
throw std::runtime_error("Failed to read Targa header from " + textureFiles[i]);
}
std::cout << "Targa header: " << header << std::endl;
const std::size_t imageSize = header.width * header.height * (header.bitsPerPixel / 8);
std::vector<char> imageData(imageSize);
file.read(imageData.data(), imageSize);
if(file.fail()) {
throw std::runtime_error("Failed to read Targa image data from " + textureFiles[i]);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, header.width, header.height, GL_BGR, GL_UNSIGNED_BYTE, imageData.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);
}
}
void shutdownRc() {
glDeleteTextures(NUM_TEXTURES, textureIds);
}
// 键盘回调:按 ESC 或 'q' 退出
void keyboard(const unsigned char key, const int x, const int y) {
std::cout << std::format("keyboard: key={}, x={}, y={}", key, x, y) << "\n";
switch (key) {
case 27: // ESC 键
case 'q':
case 'Q':
std::cout << "keyboard close..." << "\n";
std::exit(0);
break;
case 'a':
case 'A':
yRot -= 5.0F;
break;
case 'd':
case 'D':
yRot += 5.0F;
// glutPostRedisplay();
break;
case 'w':
case 'W':
xRot -= 5.0F;
break;
case 's':
case 'S':
xRot += 5.0F;
break;
case 'z':
case 'Z':
zRot -= 5.0F;
break;
case 'x':
case 'X':
zRot += 5.0F;
break;
case 'c':
case 'C':
break;
case 'v':
case 'V':
break;
default:
break;
}
glutPostRedisplay();
}
void specialKeys(const int key, const int x, const int y) {
std::cout << std::format("specialKeys: key={}, x={}, y={}", key, x, y) << "\n";
switch (key) {
case GLUT_KEY_UP:
zPos += 1.0f;
break;
case GLUT_KEY_DOWN:
zPos -= 1.0f;
break;
case GLUT_KEY_LEFT:
break;
case GLUT_KEY_RIGHT:
break;
default:
break;
}
// Refresh the Window
glutPostRedisplay();
}
void processMenu(const int value) {
std::cout << std::format("Menu selected: {}", value) << "\n";
for(GLuint i = 0; i < NUM_TEXTURES; ++i) {
glBindTexture(GL_TEXTURE_2D, textureIds[i]);
switch (value) {
case 0:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
case 1:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
break;
case 2:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
break;
case 3:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
break;
case 4:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
break;
case 5:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
break;
}
}
glutSetWindow(mainWindowId);
glutPostRedisplay();
}
auto main(const int argc, const char** argv) -> int {
std::cout << "Hello, World!" << std::endl;
glutInit(const_cast<int*>(&argc), const_cast<char**>(argv));
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
mainWindowId = glutCreateWindow("OpenGL");
if (!mainWindowId) {
throw std::runtime_error("Failed to create OpenGL window");
}
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutSpecialFunc(specialKeys); // 特殊键事件
glutKeyboardFunc(keyboard); // 普通键事件
glutCreateMenu(processMenu);
glutAddMenuEntry("GL_NEAREST",0);
glutAddMenuEntry("GL_LINEAR",1);
glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST",2);
glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 3);
glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);
glutAttachMenu(GLUT_RIGHT_BUTTON);
setupRc();
glutMainLoop();
return 0;
}

浙公网安备 33010602011771号