GLEW 설치
- GLEW(The OpenGL Extension Wrangler Library)는 여러 종류의 컴퓨터 플랫폼(Cross Platform) 환경에서 작동 가능한 오픈소스 형태의 C/C++ 확장 라이브러리임
- GLEW는 효율적인 실시간(run time) 메커니즘을 제공하는데, 이 메커니즘은 사용자의 플랫폼(Window, Mac 등…)에 적합한 OpenGL 기능들을 결정함
- GLEW는 다양한 운영체제를 지원 (GLEW에서지원하는 OS: Windows, Linux, Mac OS X, FreeBSD, Irix, Solaris)
3D Textures
3D Textures
- 3D textures are raster graphics with three dimensions
- Such volumetric data is often generated in medical imaging
- A CT or MRI machine takes several cuts through the investigated object
- Each slice represents a 2D raster graphics and can be assembled to a 3D volume by stacking the slice
- The texture coordinates $s$ and $t$, as known from 2D textures, are extended by a new dimension $r$, which is orthogonal to the two existing ones
더보기
3D 텍스처는 3차원의 래스터 그래픽
이러한 볼륨 데이터는 의료 영상에서 종종 생성됨
- CT 또는 MRI 기계가 조사 대상물을 여러 번 잘라냄.
- 각 슬라이스는 2D 래스터 그래픽을 나타내며 슬라이스를 적층하여 3D 볼륨으로 조립할 수 있음
2D 텍스처에서 알려진 텍스처 좌표 s와 t는 기존의 두 텍스처에 직교하는 새로운 치수 r에 의해 확장됨
3D Textures in OpenGL
- In OpenGL the command for creation and application of 3D textures are consistent with the commands for 2D texture
- The function glTexImage2D becomes glTexImages3D and GL_TEXTURE_2D becomes GL_TEXTURE_3D, etc.
- When passing texture data to glTeImage3D the memory layout can be interpreted as a series of 2D textures data
- That is, when filling the memory, the texel in $s$-direction is increased in each step, in $t$-direction after width texel values, and in $r$-direction only after width*height texel values
더보기
OpenGL에서는 3D 텍스처의 작성 및 적용을 위한 명령어는 2D 텍스처를 위한 명령어와 일치함
glTexImage2D 함수는 glTexImages3D가 되고 GL_TEXIture_2D는 GL_TEXIture_3D 등이 됨
텍스처 데이터를 glTeImage3D에 전달하면 메모리 레이아웃은 일련의 2D 텍스처 데이터로 해석할 수 있음.
즉, 메모리를 채울 때 s-방향의 텍스트는 각 단계에서 증가하고, 너비 텍스트 값 이후의 t-방향, 너비*높이 텍스트 값 이후의 r-방향으로만 증가함
Example: Texturing a Random Terrain
// This code example is created for educational purpose
// by Thorsten Thormaehlen (contact: www.thormae.de).
// It is distributed without any warranty.
#include <GL/glew.h>
#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;
std::vector <float> terrain;
public:
// constructor
Renderer() : t(0.0), texID(0) {}
//destructor
~Renderer() {
if (texID != 0) glDeleteTextures(1, &texID);
}
public:
void init() {
glEnable(GL_DEPTH_TEST);
std::vector< std::string > filenames;
filenames.push_back("deep_water.ppm");
filenames.push_back("shallow_water.ppm");
filenames.push_back("shore.ppm");
filenames.push_back("fields.ppm");
filenames.push_back("rocks.ppm");
filenames.push_back("snow.ppm");
texID = loadTexture3D(filenames);
rebuildTerrain();
}
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(1.5, -1.0, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
// draw scene
glRotatef(t, 0.0f, 0.0f, 1.0f);
drawTerrain();
}
void rebuildTerrain() { //1번 누르면
//create random values
int dim = 40;
terrain.resize(dim * dim);
for (int r = 0; r < dim * dim; r++) {
int rval = rand();
terrain[r] = (fabs(float(rval)) / float(RAND_MAX));
}
if (true) { // generate smooth terrain values
std::vector<float> smoothTerrain(dim * dim);
for (unsigned k = 0; k < 5; k++) {
float maxVal = 0.0f;
float minVal = 1.0f;
for (int x = 0; x < dim; x++) {
for (int y = 0; y < dim; y++) {
if (x == 0 || x == dim - 1) terrain[x * dim + y] = 0.0f;
else if (y == 0 || y == dim - 1) terrain[x * dim + y] = 0.0f;
else {
float a = 0.0f;
int counter = 0;
for (int s = -1; s <= 1; s++) {
for (int r = -1; r <= 1; r++) {
a += terrain[(x + s) * dim + (y + r)];
counter++;
}
}
float val = a / float(counter);
smoothTerrain[x * dim + y] = val;
if (val > maxVal) maxVal = val;
if (val < minVal) minVal = val;
}
}
}
for (int r = 0; r < dim * dim; r++) terrain[r] = (smoothTerrain[r] - minVal) / (maxVal - minVal);
}
}
}
private:
// returns a valid textureID on success, otherwise 0
GLuint loadTexture3D(std::vector< std::string >& filenames) {
unsigned width = 0;
unsigned height = 0;
unsigned depth = unsigned(filenames.size());
int level = 0;
int border = 0;
std::vector<unsigned char> imgData;
std::vector<unsigned char> data3d;
unsigned prevWidth = 0;
unsigned prevHeight = 0;
for (unsigned i = 0; i < depth; i++) {
// load image data
if (!loadPPMImageFlipped(filenames[i], width, height, imgData)) return 0;
if (i != 0 && (prevWidth != width || prevHeight != height)) return 0;
// pack 2D images subsequently into a large 3D buffer
data3d.insert(data3d.end(), imgData.begin(), imgData.end());
prevWidth = width;
prevHeight = height;
}
// data is aligned in byte order
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//request textureID
GLuint textureID;
glGenTextures(1, &textureID);
// bind texture
glBindTexture(GL_TEXTURE_3D, textureID);
//parameters the define how to warp the texture
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
GLfloat borderColor[4] = { 0.0f,0.0f,0.0f,1.0f };
glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, borderColor);
//define how to filter the texture
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, 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
glTexImage3D(GL_TEXTURE_3D, level, GL_RGB, width, height, depth, border, GL_RGB, GL_UNSIGNED_BYTE, &data3d[0]);
// return unique texture identifier
return textureID;
}
void drawTerrain() {
glEnable(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D, texID);
glColor3f(1.0f, 0.0f, 0.0f);
unsigned dim = unsigned(sqrt(double(terrain.size())));
float maxHeight = 0.2f;
float texHeight = 0.9f;
for (unsigned x = 1; x < dim; x++) {
for (unsigned y = 1; y < dim; y++) {
glBegin(GL_POLYGON);
glTexCoord3f(float(x - 1) / float(dim),
float(y - 1) / float(dim),
terrain[(x - 1) * dim + (y - 1)] * texHeight);
glVertex3f(float(x - 1) / float(dim) - 0.5f,
float(y - 1) / float(dim) - 0.5f,
terrain[(x - 1) * dim + (y - 1)] * maxHeight);
glTexCoord3f(float(x) / float(dim),
float(y - 1) / float(dim),
terrain[x * dim + (y - 1)] * texHeight);
glVertex3f(float(x) / float(dim) - 0.5f,
float(y - 1) / float(dim) - 0.5f,
terrain[x * dim + (y - 1)] * maxHeight);
glTexCoord3f(float(x) / float(dim),
float(y) / float(dim),
terrain[x * dim + y] * texHeight);
glVertex3f(float(x) / float(dim) - 0.5f,
float(y) / float(dim) - 0.5f,
terrain[x * dim + y] * maxHeight);
glTexCoord3f(float(x - 1) / float(dim),
float(y) / float(dim),
terrain[(x - 1) * dim + y] * texHeight);
glVertex3f(float(x - 1) / float(dim) - 0.5f,
float(y) / float(dim) - 0.5f,
terrain[(x - 1) * dim + y] * maxHeight);
glEnd();
}
}
glDisable(GL_TEXTURE_3D);
}
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;
switch (key) {
case '1':
renderer->rebuildTerrain();
redraw = true;
break;
}
if (redraw) {
glutDisplay();
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(320, 320);
glutCreateWindow("Press 1 to generate a new random terrain");
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "Glew error: %s\n", glewGetErrorString(err));
}
glutDisplayFunc(glutDisplay);
//glutIdleFunc(glutDisplay);
glutReshapeFunc(glutResize);
glutKeyboardFunc(glutKeyboard);
renderer = new Renderer;
renderer->init();
glutTimerFunc(unsigned(20), timer, 0);
glutMainLoop();
}
Texture Units
- A graphics card has multiple texture units
- This allows simultaneous access to multiple textures since each unit can provide a different texture
- This becomes especially interesting when we start writing our own shaders
- To support OpenGL 3.x, a graphics card must have at least 16 texture units
- The maximum number f texture units can be queried by the command:
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &noOfTextureUnits);
- The command glActiveTexture sets the currently modified texture unit:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texA);
//...
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXUTRE_2D, texB);
//...
더보기
그래픽 카드에는 여러 텍스처 유닛이 있음.
이를 통해 유닛마다 다른 텍스처를 제공할 수 있기 때문에 여러 텍스처에 동시에 액세스할 수 있음.
이것은 독자적인 셰이더를 쓰기 시작할 때 특히 흥미로워짐.
OpenGL 3.x를 지원하려면 그래픽 카드에 최소 16개의 텍스처 유닛이 있어야 함.
OpenGL Texture Mapping from an Object-Oriented View
- Texture ID (handle on texture object)
- Properties of a texture object
- Dimension (1D, 2D, 3D) and resolution (128x128, 256x256, …)
- Component Type (ubyte, ushort, uint, float16, float32)
- Number and semantic of the components (RGB, RGBA, BGR, …)
- Data block for raster graphics and mipmap
- Parameters for filtering and wrapping
- Properties of the texture unit
- Currently bounded texture object
- Texture environment color
- Parameters for the effect of the texture on the current fragment
- Texture access function (disabled, 1D, 2D, 3D)
- Texture transformation stack glMatrixMode(GL_TEXTURE)
'전공 > 컴퓨터 그래픽스' 카테고리의 다른 글
버퍼 오브젝트 (Buffer Objects) (1) (1) | 2023.05.29 |
---|---|
프레임 버퍼(Frame Buffer Object) (0) | 2023.05.28 |
텍스처 (2)텍스쳐 매핑 기법 (0) | 2023.05.20 |
텍스처 (1)2D 텍스쳐 (0) | 2023.05.07 |
투상 변환과 뷰 포트 변환 (3)지엘의 뷰 포트 변환 (0) | 2023.04.23 |
댓글