A Texture is 2D image that can be wrapped around a 3D object like a gift wrapper. For example, resources\textures\bricks2.jpg is a 2D Texture file.
Unlike cartesian coordinates, Texture follow UV System as shown below.
TextureUtil Class is used for loading textures. It uses SOIL2 library discussed earlier to implement it.
It's located in VOGLLib\Geometry\TextureUtil.h.
Loading Texture
OpenGL supports up to 80 Textures and each with its own identifier. Loading textures is implemented in LoadTexture method in TextureUtil class.
SOIL_load_OGL_texture(filename.c_str(), SOIL_LOAD_AUTO, 0, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
MIPMAP
Mipmapping is a technique where a high-resolution texture is downscaled and filtered so that each subsequent mip level is a quarter of the area of the previous level. This means that the texture and all of its generated mips requires no more than 1.5 times the original texture size. An example is shown below.
Inversion of Y Axis
After loading the image needs to be inverted since the V axis of the texture and Y axis of OpenGL have opposite polarity.
As shown below, determines how the texture is wrapped.
Applying Texture
Texture Filtering
Texture filtering is a method that is used to improve the texture quality in a scene. Without texture filtering, artifacts like aliasing generally look worse. Texture filtering makes textures look better and less blocky.
As discussed previously, Texture coordinates are passed during rendering. The following mapping in relation to the UxV axes is used as texture coordinates for the vertices consecutively.
//first triangle
{ 0.0, 1.0, 0.0 },
{ -1.0, 0.0, 0.0 },
{ 0.0, -1.0, 0.0 },
//second triangle
{ 1.0, 0.0, 0.0 },
{ 0.0, 0.0, -1.0 },
{ 0.0, 0.0, 1.0 },
Implementation
TexturedCube class is implemented as below to draw the textured cube.
It's located in VOGLLib\Geometry\Cube\TexturedCube .h.
#pragma once
#include "..\BaseGeometry.h"
#include "..\TextureUtil.h"
#include "CubeMesh.h"
//implements texturedcube
class TexturedCube:public BaseGeometry
{
public:
//initialize
void Init(GLushort texunit, const string& filename)
{
//create mesh and the window
BaseGeometry::Init(new CubeMesh());
//generate VBOs for position and Texture coordinates
kount = mesh->GenerateVerticesData(false, VAOUtil::POS | VAOUtil::TEX, vaoutl);
//setup vertices
vaoutl.SetupVBO(0, VAOUtil::POS);
vaoutl.SetupVBO(1, VAOUtil::TEX);
vaoutl.unbindVAO();
this->filename = filename;
//Load Texture from the file
texutl.Init(texunit);
texutl.LoadTexture(filename);
}
//update uniforms
void UpdateUniforms()
{
//pass builtin texture to the fragment shader
texutl.MakeActive(shader.GetUniformLocation("tex"));
BaseGeometry::UpdateUniforms();
}
//release resources
void Cleanup()
{
BaseGeometry::Cleanup();
texutl.Cleanup();
}
//override
virtual string vertexShaderSource()
{
return R"(
#version 330 core
layout (location = 0) in vec3 vVertex;
layout (location = 1) in vec2 vTexCrd;
uniform mat4 transform;
out vec2 FragTexCrd;
void main()
{
gl_Position = transform * vec4(vVertex, 1.0);
FragTexCrd=vTexCrd;
};
)";
}
//override
virtual string fragmentShaderSource()
{
return R"(
#version 330 core
in vec2 FragTexCrd;
out vec4 FragColor;
uniform sampler2D tex;
void main()
{
FragColor = texture(tex, FragTexCrd);
};
)";
}
private:
TextureUtil texutl;
std::string filename;
};
This purpose of this Lesson04 project is to create a Window initialized with OpenGL context and draw a TexturedCube wrapped with texture.
As discussed in introduction create tutorial lesson project Lesson04 under Lessons folder.
Add a header file Scene.h as shown below. The class itself is self explanatory.
The WM_CLOSE event is handled in OnCloseWindow function and the window is destroyed and application is shutdown.
The Init method calls BaseScene's Init to create hosting window and OpenGL Context. It also attaches BaseCameraInputHandler to rotate the cube either by keyboard or mouse inputs. It initializes the IndexedCube with texture.
The DrawScene method draws the cube with loaded texture and rotates as per keyboard or mouse inputs.
The Cleanup method release the resources.
The Scene class is implemented as below. It's located in Lessons\Lesson03\Scene.h file.
#include "Scene\BaseScene.h"
#include "Geometry\Cube\TexturedCube.h"
class Scene:public BaseScene
{
public:
//message handler
BEGIN_MSG_MAP(Scene0)
MESSAGE_HANDLER(WM_CLOSE, OnCloseWindow)
CHAIN_MSG_MAP(BaseScene)
END_MSG_MAP()
//override
int Init(RECT rect, WCHAR *windowname)
{
//create host window and context
BaseScene::Init(rect, windowname);
//attach mouse keyboard input handler
mskbd = new BaseCameraInputHandler(m_hWnd);
//Create cube an set texture filename
cube.Init(0, R"(..\..\resources\textures\bricks2.jpg)");
return 0;
}
//release resources
void Cleanup()
{
cube.Cleanup();
delete mskbd;
}
//draw the scene
void DrawScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//get model view projection matrix.
//only model is modified
//view and projection will be identity matrix
mskbd->fetchCameraData(&cube.camera);
cube.Draw();
}
//Close the window
LRESULT OnCloseWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
bHandled = TRUE;
DestroyWindow();
PostQuitMessage(0);
return 0;
}
private:
TexturedCube cube;
};
The main.cpp is located in Lessons\Lesson03\main.cpp file. It creates the scene object and calls its init method.
#include "Scene.h"
Scene scene;
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd_line, int show)
{
scene.Init(RECT{ 100, 100, 780, 500 }, L"Modern OpenGL-Tutorial - Lesson04");
scene.ShowWindow(show);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
return 0;
}
The output looks as shown in the top. The cube is rotated by 20 degrees pitch and 20 degrees yaw. The camera position at the origin looking down on -Z axis or the back face of the cube.
To rotate the cube X,Y and Z keys can be used. They rotate respectively pitch, yaw and roll the cube by 10 degrees,
In the next post we shall create a colored cube with transformation.
No comments:
Post a Comment