二维纹理映射:
其实就是往画的二维几何图形上贴贴图
显示效果:
随便找了个Gayhub的Logo转成了bmp当贴图
后期会补上详细的源码分析啥的, 顺便转成板子方便考试用
已补
源码:
main.cpp
#define NDEBUG
#ifndef GLUT_DISABLE_ATEXIT_HACK
#define GLUT_DISABLE_ATEXIT_HACK
#endif
#include <windows.h>
#include <gl/glut.h>
#include <math.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include "imageloader.cpp"
using namespace std;
//这里用的是课上给定的BMP位图加载代码:
//Makes the image into a texture, and returns the id of the texture
GLuint loadTexture(Image* image) {
GLuint textureId;
glGenTextures(1, &textureId); //Make room for our texture
glBindTexture(GL_TEXTURE_2D, textureId); //Tell OpenGL which texture to edit
//Map the image to the texture
glTexImage2D(GL_TEXTURE_2D, //Always GL_TEXTURE_2D
0, //0 for now
GL_RGB, //Format OpenGL uses for image
image->width, image->height, //Width and height
0, //The border of the image
GL_RGB, //GL_RGB, because pixels are stored in RGB format
GL_UNSIGNED_BYTE, //GL_UNSIGNED_BYTE, because pixels are stored
//as unsigned numbers
image->pixels); //The actual pixel data
return textureId; //Returns the id of the texture
}
GLuint _textureId; //The id of the texture
void initRendering() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
//加载图片
//目标图片为GitHub Logo
Image* image = loadBMP("github.bmp");
_textureId = loadTexture(image);
delete image;
}
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (float)w / (float)h, 1.0, 200.0);
return ;
}
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 1.0f, -6.0f);
//设置光照
GLfloat ambientLight[] = {0.2f, 0.2f, 0.2f, 1.0f};
GLfloat directedLight[] = {0.7f, 0.7f, 0.7f, 1.0f};
GLfloat directedLightPos[] = {-10.0f, 15.0f, 20.0f, 0.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, directedLight);
glLightfv(GL_LIGHT0, GL_POSITION, directedLightPos);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, _textureId);
//绘制底部矩形
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glNormal3f(0.0, 1.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-2.5f, -2.5f, 2.5f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(2.5f, -2.5f, 2.5f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(2.5f, -2.5f, -2.5f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-2.5f, -2.5f, -2.5f);
glEnd();
//绘制后部back三角形
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLES);
//设定平面法向量指向位置
glNormal3f(0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-2.5f, -2.5f, -2.5f);
glTexCoord2f(0.5f, 1.0f);
glVertex3f(0.0f, 2.5f, -2.5f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(2.5f, -2.5f, -2.5f);
glEnd();
//绘制左侧矩形
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glNormal3f(1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-2.5f, -2.5f, 2.5f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-2.5f, -2.5f, -2.5f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-2.5f, 2.5f, -2.5f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-2.5f, 2.5f, 2.5f);
glEnd();
glDisable(GL_TEXTURE_2D);
glutSwapBuffers();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutCreateWindow("Textures");
initRendering();
glutDisplayFunc(drawScene);
glutReshapeFunc(handleResize);
glutMainLoop();
return 0;
}
imageloader.h
这个直接用的老师给的上古源码:
#ifndef IMAGELOADER_H
#define IMAGELOADER_H
/* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* File for "Textures" lesson of the OpenGL tutorial on
* www.videotutorialsrock.com
*/
//Represents an image
class Image {
public:
Image(char* ps, int w, int h);
~Image();
/* An array of the form (R1, G1, B1, R2, G2, B2, ...) indicating the
* color of each pixel in image. Color components range from 0 to 255.
* The array starts the bottom-left pixel, then moves right to the end
* of the row, then moves up to the next column, and so on. This is the
* format in which OpenGL likes images.
*/
char* pixels;
int width;
int height;
};
//Reads a bitmap image from file.
Image* loadBMP(const char* filename);
#endif // IMAGELOADER_H
imageloader.cpp
这个同样也是老师给的上古源码
然后就很阴间, 对于分辨率过高的图片加载后会出现颜色乱码
/* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* File for "Textures" lesson of the OpenGL tutorial on
* www.videotutorialsrock.com
*/
#include <assert.h>
#include <fstream>
#include "imageloader.h"
using namespace std;
Image::Image(char* ps, int w, int h) : pixels(ps), width(w), height(h) {
}
Image::~Image() {
delete[] pixels;
}
namespace {
//Converts a four-character array to an integer, using little-endian form
int toInt(const char* bytes) {
return (int)(((unsigned char)bytes[3] << 24) |
((unsigned char)bytes[2] << 16) |
((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Converts a two-character array to a short, using little-endian form
short toShort(const char* bytes) {
return (short)(((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Reads the next four bytes as an integer, using little-endian form
int readInt(ifstream &input) {
char buffer[4];
input.read(buffer, 4);
return toInt(buffer);
}
//Reads the next two bytes as a short, using little-endian form
short readShort(ifstream &input) {
char buffer[2];
input.read(buffer, 2);
return toShort(buffer);
}
//Just like auto_ptr, but for arrays
template<class T>
class auto_array {
private:
T* array;
mutable bool isReleased;
public:
explicit auto_array(T* array_ = NULL) :
array(array_), isReleased(false) {
}
auto_array(const auto_array<T> &aarray) {
array = aarray.array;
isReleased = aarray.isReleased;
aarray.isReleased = true;
}
~auto_array() {
if (!isReleased && array != NULL) {
delete[] array;
}
}
T* get() const {
return array;
}
T &operator*() const {
return *array;
}
void operator=(const auto_array<T> &aarray) {
if (!isReleased && array != NULL) {
delete[] array;
}
array = aarray.array;
isReleased = aarray.isReleased;
aarray.isReleased = true;
}
T* operator->() const {
return array;
}
T* release() {
isReleased = true;
return array;
}
void reset(T* array_ = NULL) {
if (!isReleased && array != NULL) {
delete[] array;
}
array = array_;
}
T* operator+(int i) {
return array + i;
}
T &operator[](int i) {
return array[i];
}
};
}
Image* loadBMP(const char* filename) {
ifstream input;
input.open(filename, ifstream::binary);
assert(!input.fail() || !"Could not find file");
char buffer[2];
input.read(buffer, 2);
assert(buffer[0] == 'B' && buffer[1] == 'M' || !"Not a bitmap file");
input.ignore(8);
int dataOffset = readInt(input);
//Read the header
int headerSize = readInt(input);
int width;
int height;
switch(headerSize) {
case 40:
//V3
width = readInt(input);
height = readInt(input);
input.ignore(2);
assert(readShort(input) == 24 || !"Image is not 24 bits per pixel");
assert(readShort(input) == 0 || !"Image is compressed");
break;
case 12:
//OS/2 V1
width = readShort(input);
height = readShort(input);
input.ignore(2);
assert(readShort(input) == 24 || !"Image is not 24 bits per pixel");
break;
case 64:
//OS/2 V2
assert(!"Can't load OS/2 V2 bitmaps");
break;
case 108:
//Windows V4
assert(!"Can't load Windows V4 bitmaps");
break;
case 124:
//Windows V5
assert(!"Can't load Windows V5 bitmaps");
break;
default:
assert(!"Unknown bitmap format");
}
//Read the data
int bytesPerRow = ((width * 3 + 3) / 4) * 4 - (width * 3 % 4);
int size = bytesPerRow * height;
auto_array<char> pixels(new char[size]);
input.seekg(dataOffset, ios_base::beg);
input.read(pixels.get(), size);
//Get the data into the right format
auto_array<char> pixels2(new char[width * height * 3]);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
for(int c = 0; c < 3; c++) {
pixels2[3 * (width * y + x) + c] =
pixels[bytesPerRow * y + 3 * x + (2 - c)];
}
}
}
input.close();
return new Image(pixels2.release(), width, height);
}
修正版的源码:
#define NDEBUG
#ifndef GLUT_DISABLE_ATEXIT_HACK
#define GLUT_DISABLE_ATEXIT_HACK
#endif
#define STB_IMAGE_IMPLEMENTATION
#include <windows.h>
#include <gl/glut.h>
#include <math.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <stb_image.h>
//#include "imageloader.h"
using namespace std;
//image类储存加载到内存中的图片
struct Image{
int width=0;
int height=0;
int nrChannels=0;
unsigned char *data=nullptr;
};
//图片加载函数
/**
* @brief loadImage 将图片加载到内存
* @param fileName 图片文件名(相对路径)
* @return
*/
Image * loadImage(const char* fileName){
Image* image=new Image();
//翻转图像, 否则图像是反的
stbi_set_flip_vertically_on_load(true);
image->data=stbi_load (fileName,&image->width,&image->height,
&image->nrChannels,0);
return image;
}
//纹理加载函数
/**
* @brief loadTexture 将图片加载为纹理
* @param image 已经加载到内存中的图片
* @return
*/
GLuint loadTexture(Image* image) {
GLuint textureId;
//纹理初始化
glGenTextures(1, &textureId);
//选定当前要编辑的纹理
glBindTexture(GL_TEXTURE_2D, textureId);
if(image->nrChannels==3){
glTexImage2D(GL_TEXTURE_2D, //二维纹理永远是GL_TEXTURE_2D
0, //基本都是用0
GL_RGB, //纹理储存格式
image->width, image->height, //图像宽高
0, //永远是0
GL_RGB, //纹理数据格式, 必须与上头相同
GL_UNSIGNED_BYTE, //纹理数据类型, 基本用GL_UNSIGNED_BYTE
image->data); //图片data数组指针
}else{
//如果是PNG图像就有alpha通道, 用RGBA
glTexImage2D(GL_TEXTURE_2D, //二维纹理永远是GL_TEXTURE_2D
0, //基本都是用0
GL_RGBA, //纹理储存格式
image->width, image->height, //图像宽高
0, //永远是0
GL_RGBA, //纹理数据格式, 必须与上头相同
GL_UNSIGNED_BYTE, //纹理数据类型, 基本用GL_UNSIGNED_BYTE
image->data); //图片data数组指针
}
return textureId; //返回加载的纹理ID
}
GLuint _textureId; //The id of the texture
void initRendering() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
//加载图片
//目标图片为GitHub Logo
Image* image = loadImage("ttt.png");
_textureId = loadTexture(image);
delete image;
}
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (float)w / (float)h, 1.0, 200.0);
return ;
}
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 1.0f, -6.0f);
//设置光照
GLfloat ambientLight[] = {0.2f, 0.2f, 0.2f, 1.0f};
GLfloat directedLight[] = {0.7f, 0.7f, 0.7f, 1.0f};
GLfloat directedLightPos[] = {-10.0f, 15.0f, 20.0f, 0.0f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, directedLight);
glLightfv(GL_LIGHT0, GL_POSITION, directedLightPos);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, _textureId);
//绘制底部矩形
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glNormal3f(0.0, 1.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-2.5f, -2.5f, 2.5f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(2.5f, -2.5f, 2.5f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(2.5f, -2.5f, -2.5f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-2.5f, -2.5f, -2.5f);
glEnd();
//绘制后部back三角形
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLES);
//设定平面法向量指向位置
glNormal3f(0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-2.5f, -2.5f, -2.5f);
glTexCoord2f(0.5f, 1.0f);
glVertex3f(0.0f, 2.5f, -2.5f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(2.5f, -2.5f, -2.5f);
glEnd();
//绘制左侧矩形
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glNormal3f(1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-2.5f, -2.5f, 2.5f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-2.5f, -2.5f, -2.5f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-2.5f, 2.5f, -2.5f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-2.5f, 2.5f, 2.5f);
glEnd();
glDisable(GL_TEXTURE_2D);
glutSwapBuffers();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutCreateWindow("Textures");
initRendering();
glutDisplayFunc(drawScene);
glutReshapeFunc(handleResize);
glutMainLoop();
return 0;
}
源码分析:
纹理加载:
这里使用std_image.h
来加载:
int width, height, nrChannels;
unsigned char *data = stbi_load("imageName.jpg", &width, &height, &nrChannels, 0);
- 图片格式为主流格式基本上都能加载
纹理生成:
一套操作:
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
-
纹理初始化
void glGenTextures(GLsizei n,GLuint *textures);
输入给定数量的纹理, 并生成相应数量的ID储存在
textures
里参数:
- 输入的纹理的数量
- 储存数组
-
纹理绑定:
void glBindTexture(GLenum target,GLuint texture);
相当于选定当前要编辑的纹理
参数:
- GL_TEXTURE_2D
这里是二维纹理, 所以用的还是这个 - 之前初始化的ID号
- GL_TEXTURE_2D
-
纹理载入:
void glTexImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height, GLint border,GLenum format,GLenum type,const GLvoid *pixels);
将图片载入到纹理中
参数:
-
GL_TEXTURE_2D
对还是这个 -
指定多级渐远纹理的级别
通常用0, 级别越高图像越小(应该是这么理解吧)别搞这种 -
纹理储存格式
根据图像而定, 常用的为GL_RGB或GL_RGBA(有alpha通道) -
指定图像宽度
-
指定图像高度
-
指定边框的宽度
这个必须为0 -
指定纹理数据的格式
这个必须与上头的纹理储存格式相同 -
指定纹理数据的数据类型
通常为GL_UNSIGNED_BYTE -
指定一个指向内存中图像数据的指针
就是加载到内存中图片的数组首地址
-
纹理过滤:
纹理映射到几何体上是并不是等大的, 更多情况会被放大缩小
这里的过滤就指定了纹理放大缩小时采用的规则:
同样使用函数:
glTexParameteri(GL_TEXTURE_2D, para1, para2);
-
第一个参数永远是GL_TEXTURE_2D, 因为使用的是2D纹理
-
para1:
有两个可选的值, 通常要使用两次glTexParameteri
这两种情况都设置一遍- GL_TEXTURE_MIN_FILTER
决定纹理方法时采用的规则 - GL_TEXTURE_MAG_FILTER
决定纹理缩小是采用的规则
- GL_TEXTURE_MIN_FILTER
-
para2:
有两个值:- GL_NEAREST 邻近过滤
- GL_LINEAR 线性过滤, 要好看点通常选用这个
效果:
具体差别可以看这里:
https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/
纹理绘制:
例程:
反正按着这个流程就对了
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, _textureId);
//绘制底部矩形
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
{
glNormal3f(0.0, 1.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-2.5f, -2.5f, 2.5f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(2.5f, -2.5f, 2.5f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(2.5f, -2.5f, -2.5f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-2.5f, -2.5f, -2.5f);
}
glEnd();
glDisable(GL_TEXTURE_2D);