2D Textures
2D Textures
- 2D textures are 2D raster graphics, which can be applied as a “color wallpaper” to 3D geometry
- This is an efficient way to achieve a high level of detail without representing the details as geometry

- It is possible to use multiple textures in a scene
- For example, the textures can be switched for each polygon or each object

2D 텍스처는 2D 래스터 그래픽으로 3D 지오메트리에 '컬러 벽지'로 적용 가능.
이것은 세부 사항을 지오메트리로 표현하지 않고 높은 수준의 세부 사항을 달성하기 위한 효율적인 방법
장면 내에서 여러 텍스처를 사용할 수 있음.
예를 들어, 텍스처는 각 폴리곤 또는 각 객체별로 전환될 수 있음.
2D Textures - Texture Mapping


2D 텍스처는 보통 정사각형, 0부터 1까지의 range를 가진 s와 t를 이용한 좌표계
2D texture space에서 3D surface로 매핑시키는 것
2D 텍스처는 일반적으로 정사각형이며, s와 t는 0~1 범위의 매개변수로 매개변수화됨
텍스처를 적용하려면 2D 텍스처 공간에서 3D 표면으로의 매핑 함수("텍스처 매핑")를 정의해야 함.
Textures in the OpenGL Pipeline

OpenGL Pipeline에서는 텍스쳐를 vertex와 pixel을 따로 처리해서 다룬다
vertex는 3차원의 x, y, z 정점을 말한다.
vertex는 좌표값에 operation한다면 pixel은 이미지의 한 픽셀에 대해 operation한다
rasterizer를 해야 화면에 보이게 된다.
pixel : 픽셀들을 assembly한 후 rasterizer 과정을 거침
- In OpenGL, setting a texture coordinate is performed with the command glTexCoord2f
- The particular texture coordinate that is set while drawing a vertex is assigned to the vertex (OpenGL as a state machine):
...
glBegin(GL_POLYGON);
glTexCoord2f(0.25f, 0.50f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.25f, 0.25f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(0.50f, 0.50f); glVertex3f(1.0f, -1.0f, 1.0f);
glTexCoord2f(0.50f, 0.50f); glVertex3f(1.0f, 1.0f, 1.0f);
glEnd();
...
- The texture coordinates are part of the vertex data in the OpenGL pipeline and pass through the left path of the pipeline
- The texture itself consists of pixel data that pass through the right path of the pipeline
- The texture pixels are also often referred to as “texels”
- In the rasterizer, for each output fragment (pixel of the frame buffer) interpolated texture coordinate (s,t)⊤ are computed
- Ideally, for the interpolation the distortion caused by perspective projection is taken into account (right figure)
OpenGL에서는 텍스처 좌표 설정은 glTexCord2f 명령으로 실행됨. 2는 2D, f는 float.
정점을 그릴 때 설정되는 특정 텍스처 좌표는 정점에 할당됨. (state machine으로서의 OpenGL):
텍스처 좌표는 OpenGL 파이프라인 정점 데이터의 일부이며 파이프라인 왼쪽 경로를 통과함.
텍스처 자체는 파이프라인의 올바른 경로를 통과하는 픽셀 데이터로 구성됨.
래스터라이저에서 각 출력 플래그먼트(프레임 버퍼의 픽셀)에 대해 보간된 텍스처 좌표가 계산됨
이상적으로는 보간의 경우 원근법 투영으로 인한 왜곡이 고려됨.
vertex를 그리는 중에 세팅되는 texture coordinate들을 vertex에 assign (2D에서 3D로의 매핑)
texture coordinate는 vertex데이터의 일부
rasterizer는 vertex에 assign한 texture coordinate와 texture 이미지들에 있는 픽셀값을 그대로 갖고와서 rasterizer가 그대로 합한다.
프레임 버퍼 : 화면에 보여질 영상들을 가져오는 메모리
perspectice projection : 원근감이 있어서 거리에 따라 크기 달라지는...
어떤 물체에 텍스쳐를 입히고 perspective projection을 하면 왜곡이 생길 수 있음
2D Textures in OpenGL
2D Textures in OpenGL - Creating
- Creating a texture is usually done before the actual rendering, e.g., in the function init( )
- A 2D texture can be generated with
glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(GL_TEXTURE_2D, texLevel, texFormat, inWidth, inHeight,
inBorder, inFormat, inType, inData);
- where texID is an integer value that serves as a unique identifier(“ID”) for the generated texture. With the function glGenTextures(1, &texID) such a unique identifier can be generated
- During the generation, additional parameters are often set that influence the appearance of the texture
- texLevel(Mipmap level, 사용하지 않으면 0), inWidth, inHeight(텍셀단위로 텍스쳐 폭과 높이), inBorder(텍스쳐 윤곽선을 몇 텍셀로 할 것인지), inFormat(GL_COLOR_INDEX, GL_RGB, GL_RGBA, …), inType(GL_UNSIGNED_BYTE, GL_BYTE…)
텍스처를 만드는 것은 보통 실제 렌더링 전에 이루어짐.예를 들어, init() 함수 안에서.
texID는 생성된 텍스처의 고유 식별자("ID") 역할을 하는 정수 값. glGenTextures(1, &texID) 함수를 사용하여 이러한 고유 식별자를 생성할 수 있음
생성 중에는 텍스처의 모양에 영향을 미치는 추가 매개 변수가 설정되는 경우가 종종 있음
2D Textures in OpenGL - Activating
- During rendering, first the texture unit must be activated
glEnable(GL_TEXTURE_2D);
- To render with a particular texture, its unique ID is used:
glBindTexture(GL_TEXTURE_2D, texID);
This command “binds” the texture with the given ID to the target GL_TEXTURE_2D
- That is, glBindTexture has several functions: when first called with a new ID, a new texture is generated, otherwise an existing texture is activated
Example
Example: Texturing a Cube
- In this example, a cube is textured
- To this end, the texture coordinates and vertices must be associated with each other(in the figure below, correspondences are coded with the same colors)

Example: Texturing a Cube in OpenGL
// This code example is created for educational purpose
// by Thorsten Thormaehlen (contact: www.thormae.de).
// It is distributed without any warranty.
#include <GL/freeglut.h> // we use glut here as window manager
#define _USE_MATH_DEFINES
#include <math.h>
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
using namespace std;
class Renderer {
public:
float t;
private:
GLuint texID;
public:
// constructor
Renderer() : t(0.0), texID(0) {}
// destructor
~Renderer() {
if (texID != 0) glDeleteTextures(1, &texID);
}
public:
void init() {
glEnable(GL_DEPTH_TEST); //초기화 GL_DEPTH_TEST : 안 보이는 부분들 표현하지 않게..
std::string fileName("dice_texture.ppm");
texID = loadTexture(fileName);
}
void resize(int w, int h) { //윈도우 사이즈 바꾸는 함수
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, (float)w / (float)h, 0.1, 50.0);
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// set camera
gluLookAt(8.0, -2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
// draw scene
glRotatef(t, 0.0f, 0.0f, 1.0f);
drawTexturedCube();
}
private:
// returns a valid textureID on success, otherwise 0
GLuint loadTexture(std::string& filename) {
unsigned width;
unsigned height;
int level = 0;
int border = 0;
std::vector<unsigned char> imgData;
// load image data
if (!loadPPMImageFlipped(filename, width, height, imgData)) return 0;
// data is aligned in byte order
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//request textureID
GLuint textureID;
glGenTextures(1, &textureID);
// bind texture
glBindTexture(GL_TEXTURE_2D, textureID);
//define how to filter the texture (important but ignore for now)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//texture colors should replace the original color values
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //GL_MODULATE
// specify the 2D texture map
glTexImage2D(GL_TEXTURE_2D, level, GL_RGB, width, height, border, GL_RGB, GL_UNSIGNED_BYTE, &imgData[0]);
// return unique texture identifier
return textureID;
}
void drawTexturedCube() {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID);
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_POLYGON); // three
glTexCoord2f(0.25f, 0.50f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.25f, 0.25f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(0.50f, 0.25f); glVertex3f(1.0f, -1.0f, 1.0f);
glTexCoord2f(0.50f, 0.50f); glVertex3f(1.0f, 1.0f, 1.0f);
glEnd();
glColor3f(1.0f, 1.0f, 0.0f);
glBegin(GL_POLYGON); // five
glTexCoord2f(0.00f, 0.50f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.00f, 0.25f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.25f, 0.25f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(0.25f, 0.50f); glVertex3f(-1.0f, 1.0f, 1.0f);
glEnd();
glColor3f(0.0f, 0.0f, 1.0f);
glBegin(GL_POLYGON); // two
glTexCoord2f(0.50f, 0.50f); glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.50f, 0.25f); glVertex3f(1.0f, -1.0f, 1.0f);
glTexCoord2f(0.75f, 0.25f); glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(0.75f, 0.50f); glVertex3f(1.0f, 1.0f, -1.0f);
glEnd();
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_POLYGON); // six
glTexCoord2f(0.25f, 0.75f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.25f, 0.50f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.50f, 0.50f); glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.50f, 0.75f); glVertex3f(1.0f, 1.0f, -1.0f);
glEnd();
glColor3f(0.0f, 1.0f, 1.0f);
glBegin(GL_POLYGON); // one
glTexCoord2f(0.25f, 0.25f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(0.25f, 0.00f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.50f, 0.00f); glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(0.50f, 0.25f); glVertex3f(1.0f, -1.0f, 1.0f);
glEnd();
glColor3f(0.0f, 1.0f, 0.0f);
glBegin(GL_POLYGON); //four
glTexCoord2f(0.75f, 0.50f); glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(0.75f, 0.25f); glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(1.00f, 0.25f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.00f, 0.50f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
}
bool loadPPMImageFlipped(std::string& filename, unsigned& width, unsigned& height, std::vector<unsigned char>& imgData) {
ifstream input(filename.c_str(), ifstream::in | ifstream::binary);
if (!input) { // cast istream to bool to see if something went wrong
cerr << "Can not find texture data file " << filename.c_str() << endl;
return false;
}
input.unsetf(std::ios_base::skipws);
string line;
input >> line >> std::ws;
if (line != "P6") {
cerr << "File is not PPM P6 raw format" << endl;
return false;
}
width = 0;
height = 0;
unsigned depth = 0;
unsigned readItems = 0;
unsigned char lastCharBeforeBinary;
while (readItems < 3) {
input >> std::ws;
if (input.peek() != '#') {
if (readItems == 0) input >> width;
if (readItems == 1) input >> height;
if (readItems == 2) input >> depth >> lastCharBeforeBinary;
readItems++;
}
else { // skip comments
std::getline(input, line);
}
}
if (depth >= 256) {
cerr << "Only 8-bit PPM format is supported" << endl;
return false;
}
unsigned byteCount = width * height * 3;
imgData.resize(byteCount);
input.read((char*)&imgData[0], byteCount * sizeof(unsigned char));
// vertically flip the image because the image origin
// in OpenGL is the lower-left corner
unsigned char tmpData;
for (unsigned y = 0; y < height / 2; y++) {
int sourceIndex = y * width * 3;
int targetIndex = (height - 1 - y) * width * 3;
for (unsigned x = 0; x < width * 3; x++) {
tmpData = imgData[targetIndex];
imgData[targetIndex] = imgData[sourceIndex];
imgData[sourceIndex] = tmpData;
sourceIndex++;
targetIndex++;
}
}
return true;
}
};
//this is a static pointer to a Renderer used in the glut callback functions
static Renderer* renderer;
//glut static callbacks start
static void glutResize(int w, int h)
{
renderer->resize(w, h);
}
static void glutDisplay()
{
renderer->display();
glutSwapBuffers();
glutReportErrors();
}
static void timer(int v)
{
float offset = 1.0f;
renderer->t += offset;
glutDisplay();
glutTimerFunc(unsigned(20), timer, ++v);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(320, 320);
glutCreateWindow("Texture Demo");
glutDisplayFunc(glutDisplay);
//glutIdleFunc(glutDisplay);
glutReshapeFunc(glutResize);
renderer = new Renderer;
renderer->init();
glutTimerFunc(unsigned(20), timer, 0);
glutMainLoop();
}

Parameter
Wrap Parameter
- The GL_TEXTURE_WRAP parameter defines how the texture mapping behaves if the texture coordinate s or t leaves the range [0;1]
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- Possible parameter values are: GL_CLAMP, GL_REPEAT, GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT

Filter Parameters
- When displaying textures it often occurs that color values for texture coordinates must be calculated that are not on the pixel grid of the underlying raster graphics
- A filter parameter allows to specify with which filtering method the color values are to be determined
- GL_TEXTURE_MIN_FILTER sets the filter for reduction in size and GL_TEXTURE_MAG_FILTER for enlargements:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- Possible parameter values are: GL_NEAREST or GL_LINEAR
- With GL_NEAREST the color value of the pixel is used that has the shortest distance to the texture coordinate (nearest-neighbor)
- This operation is very fast, because the texture coordinate is simply rounded to an integer pixel value and the corresponding color value f can then be read directly

- With GL_LINEAR the color value is determined by bilinear interpolation
Filter Parameters - Bilinear Interpolation


Aliasing
Aliasing
- 텍스쳐 매핑
- 비선형 매핑(Non-Linear Mapping): 평면 사각형이 곡선 사변형(Curvilinear Quadrilateral)으로

- 점 샘플링(Point Sampling)에 의한 에일리어싱: 언더샘플링

Anti - Aliasing
- 확장관계(Magnification)
- 텍셀보다 작은 크기의 텍스쳐가 한 픽셀로
- 축소관계(Minification)
- 여러 텍셀이 한 픽셀로
- 두 경우 모두 에일리어싱 발생가능

Anti-Aliasing - Bilinear Interpolation
- 확장관계에 주로 사용
- 화소 중앙점이 텍셀의 점 p로 사상되었을 경우
- 대부분 그래픽 카드에서 표준으로 채택
- 텍스쳐 경계선이 흐려짐

Anti-Aliasing - Mipmaps
- 축소관계에 주로 적용: 한 화소가 여러 텍셀에 걸쳐짐
- MIP Mapping: Multum in Parvo, Many Things in a Small Place
- 해상도 별로 평균치를 계산하여 텍스쳐 맵에 저장(R, G, B 별)
- 사전 필터링(Pre-Filtering), 다해상도 텍스쳐(Multi-Resolution Texture)



해상도에 따라 밉맵을 선택
1 화소가 1 텍셀로 매핑: Map #1
1 화소가 4 텍셀로 매핑: Map #2
평균 낸 텍스쳐 값을 사용함으로써 앤티-에일리어싱을 함
Mipmaps in OpenGL

Texture Parameters and Mip-mapping in OpenGL
// This code example is created for educational purpose
// by Thorsten Thormaehlen (contact: www.thormae.de).
// It is distributed without any warranty.
#include <GL/freeglut.h> // we use glut here as window manager
#define _USE_MATH_DEFINES
#include <math.h>
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
using namespace std;
#ifndef GL_GENERATE_MIPMAP
#define GL_GENERATE_MIPMAP 0x8191
#endif
#ifndef GL_MIRRORED_REPEAT
#define GL_MIRRORED_REPEAT 0x8370
#endif
#ifndef GL_CLAMP_TO_BORDER
#define GL_CLAMP_TO_BORDER 0x812D
#endif
class Renderer {
public:
float t;
int wrapS;
int wrapT;
int magFilter;
int minFilter;
int selectedTexID;
private:
GLuint texID0;
GLuint texID1;
public:
// constructor
Renderer() : t(-90.0f),
wrapS(GL_REPEAT), wrapT(GL_REPEAT),
magFilter(GL_LINEAR), minFilter(GL_LINEAR_MIPMAP_LINEAR),
selectedTexID(0),
texID0(0), texID1(0)
{}
// destructor
~Renderer() {
if (texID0 != 0) glDeleteTextures(1, &texID0);
if (texID1 != 0) glDeleteTextures(1, &texID1);
}
public:
void init() {
glEnable(GL_DEPTH_TEST);
std::string fileName0("checker_texture_512.ppm");
texID0 = loadTexture(fileName0);
std::string fileName1("checker_texture_32.ppm");
texID1 = loadTexture(fileName1);
}
void resize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, (float)w / (float)h, 0.1, 50.0);
}
void display() {
glClearColor(0.7f, 0.7f, 0.7f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// set camera
gluLookAt(8.0, -2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
//gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0);
// draw scene
glRotatef(t, 0.0f, 0.0f, 1.0f);
drawTexturedPlane();
}
// returns a valid textureID on success, otherwise 0
GLuint loadTexture(std::string& filename) {
unsigned width;
unsigned height;
int level = 0;
int border = 0;
std::vector <unsigned char> imgData;
// load image data
if (!loadPPMImageFlipped(filename, width, height, imgData)) return 0;
// data is aligned in byte order
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//request textureID
GLuint textureID;
glGenTextures(1, &textureID);
// bind texture
glBindTexture(GL_TEXTURE_2D, textureID);
// parameters that define how to warp the texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
GLfloat borderColor[4] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
// parameters that define how to filter the texture
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_GENERATE_MIPMAP, GL_TRUE);
// texture colors should replace the original color values
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //GL_MODULATE
// specify the 2D texture map
glTexImage2D(GL_TEXTURE_2D, level, GL_RGB, width, height, border, GL_RGB, GL_UNSIGNED_BYTE, &imgData[0]);
// return unique texture identifier
return textureID;
}
void setTextureParameters() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
}
void drawTexturedPlane() {
glEnable(GL_TEXTURE_2D);
if (selectedTexID == 0) {
glBindTexture(GL_TEXTURE_2D, texID0);
}
else {
glBindTexture(GL_TEXTURE_2D, texID1);
}
setTextureParameters();
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_POLYGON);
glTexCoord2f(5.00f, 5.00f); glVertex3f(-10.0f, 10.0f, 0.0f);
glTexCoord2f(5.00f, -4.00f); glVertex3f(-10.0f, -10.0f, 0.0f);
glTexCoord2f(-4.00f, -4.00f); glVertex3f(10.0f, -10.0f, 0.0f);
glTexCoord2f(-4.00f, 5.00f); glVertex3f(10.0f, 10.0f, 0.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
}
bool loadPPMImageFlipped(std::string& filename, unsigned& width, unsigned& height, std::vector<unsigned char>& imgData) {
ifstream input(filename.c_str(), ifstream::in | ifstream::binary);
if (!input) { // cast istream to bool to see if something went wrong
cerr << "Can not find texture data file " << filename.c_str() << endl;
return false;
}
input.unsetf(std::ios_base::skipws);
string line;
input >> line >> std::ws;
if (line != "P6") {
cerr << "File is not PPM P6 raw format" << endl;
return false;
}
width = 0;
height = 0;
unsigned depth = 0;
unsigned readItems = 0;
unsigned char lastCharBeforeBinary;
while (readItems < 3) {
input >> std::ws;
if (input.peek() != '#') {
if (readItems == 0) input >> width;
if (readItems == 1) input >> height;
if (readItems == 2) input >> depth >> lastCharBeforeBinary;
readItems++;
}
else { // skip comments
std::getline(input, line);
}
}
if (depth >= 256) {
cerr << "Only 8-bit PPM format is supported" << endl;
return false;
}
unsigned byteCount = width * height * 3;
imgData.resize(byteCount);
input.read((char*)&imgData[0], byteCount * sizeof(unsigned char));
// vertically flip the image because the image origin
// in OpenGL is the lower-left corner
unsigned char tmpData;
for (unsigned y = 0; y < height / 2; y++) {
int sourceIndex = y * width * 3;
int targetIndex = (height - 1 - y) * width * 3;
for (unsigned x = 0; x < width * 3; x++) {
tmpData = imgData[targetIndex];
imgData[targetIndex] = imgData[sourceIndex];
imgData[sourceIndex] = tmpData;
sourceIndex++;
targetIndex++;
}
}
return true;
}
};
//this is a static pointer to a Renderer used in the glut callback functions
static Renderer* renderer;
//glut static callbacks start
static void glutResize(int w, int h)
{
renderer->resize(w, h);
}
static void glutDisplay()
{
renderer->display();
glutSwapBuffers();
glutReportErrors();
}
static void timer(int v)
{
float offset = 0.25f;
renderer->t += offset;
glutDisplay();
glutTimerFunc(unsigned(20), timer, ++v);
}
static void glutKeyboard(unsigned char key, int x, int y) {
bool redraw = false;
std::string modeStr;
switch (key) {
case '1':
if (renderer->wrapS == GL_REPEAT) {
renderer->wrapS = GL_CLAMP;
modeStr = "wrapS = GL_CLAMP";
}
else if (renderer->wrapS == GL_CLAMP) {
renderer->wrapS = GL_MIRRORED_REPEAT;
modeStr = "wrapS = GL_MIRRORED_REPEAT";
}
else if (renderer->wrapS == GL_MIRRORED_REPEAT) {
renderer->wrapS = GL_CLAMP_TO_BORDER;
modeStr = "wrapS = GL_CLAMP_TO_BORDER";
}
else if (renderer->wrapS == GL_CLAMP_TO_BORDER) {
renderer->wrapS = GL_REPEAT;
modeStr = "wrapS = GL_REPEAT";
}
redraw = true;
break;
case '2':
if (renderer->wrapT == GL_REPEAT) {
renderer->wrapT = GL_CLAMP;
modeStr = "wrapT = GL_CLAMP";
}
else if (renderer->wrapT == GL_CLAMP) {
renderer->wrapT = GL_MIRRORED_REPEAT;
modeStr = "wrapT = GL_MIRRORED_REPEAT";
}
else if (renderer->wrapT == GL_MIRRORED_REPEAT) {
renderer->wrapT = GL_CLAMP_TO_BORDER;
modeStr = "wrapT = GL_CLAMP_TO_BORDER";
}
else if (renderer->wrapT == GL_CLAMP_TO_BORDER) {
renderer->wrapT = GL_REPEAT;
modeStr = "wrapT = GL_REPEAT";
}
redraw = true;
break;
case '3':
if (renderer->minFilter == GL_NEAREST) {
renderer->minFilter = GL_LINEAR;
modeStr = "minFilter = GL_LINEAR";
}
else if (renderer->minFilter == GL_LINEAR) {
renderer->minFilter = GL_NEAREST_MIPMAP_NEAREST;
modeStr = "minFilter = GL_NEAREST_MIPMAP_NEAREST";
}
else if (renderer->minFilter == GL_NEAREST_MIPMAP_NEAREST) {
renderer->minFilter = GL_LINEAR_MIPMAP_NEAREST;
modeStr = "minFilter = GL_LINEAR_MIPMAP_NEAREST";
}
else if (renderer->minFilter == GL_LINEAR_MIPMAP_NEAREST) {
renderer->minFilter = GL_NEAREST_MIPMAP_LINEAR;
modeStr = "minFilter = GL_NEAREST_MIPMAP_LINEAR";
}
else if (renderer->minFilter == GL_NEAREST_MIPMAP_LINEAR) {
renderer->minFilter = GL_LINEAR_MIPMAP_LINEAR;
modeStr = "minFilter = GL_LINEAR_MIPMAP_LINEAR";
}
else if (renderer->minFilter == GL_LINEAR_MIPMAP_LINEAR) {
renderer->minFilter = GL_NEAREST;
modeStr = "minFilter = GL_NEAREST";
}
redraw = true;
break;
case '4':
if (renderer->magFilter == GL_NEAREST) {
renderer->magFilter = GL_LINEAR;
modeStr = "magFilter = GL_LINEAR";
}
else if (renderer->magFilter == GL_LINEAR) {
renderer->magFilter = GL_NEAREST;
modeStr = "magFilter = GL_NEAREST";
}
redraw = true;
break;
case '5':
if (renderer->selectedTexID == 0) {
renderer->selectedTexID = 1;
modeStr = "texture resolution 32x32 pixels";
}
else {
renderer->selectedTexID = 0;
modeStr = "texture resolution 512x512 pixels";
}
redraw = true;
break;
}
if (redraw) {
glutDisplay();
cout << modeStr << endl;
glutSetWindowTitle(modeStr.c_str());
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(320, 320);
glutCreateWindow("Use the 1 to 5 keys to change the texture parameters");
glutDisplayFunc(glutDisplay);
//glutIdleFunc(glutDisplay);
glutReshapeFunc(glutResize);
glutKeyboardFunc(glutKeyboard);
renderer = new Renderer;
renderer->init();
glutTimerFunc(unsigned(20), timer, 0);
glutMainLoop();
}


Effect of the Texture


'전공 > 컴퓨터 그래픽스' 카테고리의 다른 글
텍스처 (3)3D 텍스쳐 (0) | 2023.05.28 |
---|---|
텍스처 (2)텍스쳐 매핑 기법 (0) | 2023.05.20 |
투상 변환과 뷰 포트 변환 (3)지엘의 뷰 포트 변환 (0) | 2023.04.23 |
투상 변환과 뷰 포트 변환 (2)지엘의 투상변환 (0) | 2023.04.23 |
투상 변환과 뷰 포트 변환 (1)투상 (0) | 2023.04.23 |
댓글