Upload
bertha-simpson
View
236
Download
5
Embed Size (px)
Citation preview
Game Programming 07OGRE3D Mesh in Action
2010 년 2 학기디지털콘텐츠전공
Rendering in Video Games
• Depth-Buffered Triangle Rasterization– Virtual Scene– Virtual Camera– Various Light Sources– Visual Properties
Solving the Rendering Equation (Shading Equation)
Rendering in OGRE3D
• Depth-Buffered Triangle Rasterization– Virtual Scene createScene()– Virtual Camera createCamera()/
createViewport()
– Various Light Sources createScene()– Visual Properties material
Solving the Rendering Equation (OGRE3D engine)
Camera Setting in OGRE3D
• Two classes: Ogre::Camera, OgreBites::CameraManvoid BaseApplication::createCamera(void)
{ // Create the camera mCamera = mSceneMgr->createCamera("PlayerCam");
// Position it at 500 in Z direction mCamera->setPosition(Ogre::Vector3(0,0,80)); // Look back along -Z mCamera->lookAt(Ogre::Vector3(0,0,-300)); mCamera->setNearClipDistance(5);
mCameraMan = new OgreBites::SdkCameraMan(mCamera);}
void BaseApplication::createCamera(void){ // Create the camera mCamera = mSceneMgr->createCamera("PlayerCam");
// Position it at 500 in Z direction mCamera->setPosition(Ogre::Vector3(0,0,80)); // Look back along -Z mCamera->lookAt(Ogre::Vector3(0,0,-300)); mCamera->setNearClipDistance(5);
mCameraMan = new OgreBites::SdkCameraMan(mCamera);}
Camera Control in OGRE3D
• OgreBites::CameraMan
CameraMan::injectKeyDown(const OIS::KeyEvent& evt)CameraMan::injectKeyDown(const OIS::KeyEvent& evt)
CameraMan:: injectKeyUp(const OIS::KeyEvent& evt)CameraMan:: injectKeyUp(const OIS::KeyEvent& evt)
CameraMan:: injectMouseMove(const OIS::MouseEvent& evt)CameraMan:: injectMouseMove(const OIS::MouseEvent& evt)
OGRE::Mesh in action
• .mesh files for loading a mesh in Ogre
– .mesh is a binary file only for the ogre’s use. – There is no way to create your own .mesh file
from the scratch.
• Meshes are located at a specific folder– Resources.cfg file says where you can find the
filesex.)FileSystem=../../media/modelsex.)FileSystem=../../media/models
Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");
Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");
OGRE::Mesh in Action
• You can create your own mesh, too!– Using primitive mesh structure:
For example, a Plane
– Or, Define your own mesh manually
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1500, 1500, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);
Ogre::Entity* entGround = mSceneMgr->createEntity("GroundEntity", "ground");
Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1500, 1500, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);
Ogre::Entity* entGround = mSceneMgr->createEntity("GroundEntity", "ground");
OGRE::Mesh in Action
• createPlane function to generate the meshMeshPtr Ogre::MeshManager::createPlane ( const String & name, const String & groupName, const Plane & plane, Real width, Real height, int xsegments = 1, int ysegments = 1, bool normals = true, int numTexCoordSets = 1, Real uTile = 1.0f, Real vTile = 1.0f, const Vector3 & upVector = Vector3::UNIT_Y )
MeshPtr Ogre::MeshManager::createPlane ( const String & name, const String & groupName, const Plane & plane, Real width, Real height, int xsegments = 1, int ysegments = 1, bool normals = true, int numTexCoordSets = 1, Real uTile = 1.0f, Real vTile = 1.0f, const Vector3 & upVector = Vector3::UNIT_Y )
Singleton pattern in OGRE3D• Which class will be useful if you can access
it from anywhere?– Resources should be used anywhere!
• Mesh• Material
• Manager classes for the resources:
TextureManager::getSingleton() MeshManager::getSingleton()TextureManager::getSingleton() MeshManager::getSingleton() What is singleton? What is singleton?
C++ Design Patterns 10
The Singleton Pattern
Sometimes it is appropriate to have exactly one instance of a class:
window managers, print spoolers, filesystems.
Typically, those types of objects known as singletons, are accessed by disparate objects throughout a software system, and therefore require a global point of access.
The Singleton pattern addresses all the concerns above. With the Singleton design pattern you can:
Ensure that only one instance of a class is created. Provide a global point of access to the object. Allow multiple instances in the future without
affecting a singleton class' clients.
:: Definition & Applicability - I
C++ Design Patterns 11
The Singleton Pattern
The Singleton pattern ensures a class has only one instance, and provides a global point of access to it.
The class itself is responsible for keeping track of its sole instance. The class can ensure that no other instance can be created (by intercepting requests to create new objects), and it can provide a way to access the instance.
Singletons maintain a static reference to the sole singleton instance and return a reference to that instance from a static instance() method.
:: Definition & Applicability - II
C++ Design Patterns 12
The Singleton Pattern
The Singleton class maintains a static reference to the sinle singleton instance (pinstance) and returns that reference from the static Instance() method.
:: The Classic Singleton - I
C++ Design Patterns 13
The Singleton Pattern
The Singleton class employs a technique known as lazy instantiation to create the singleton; as a result, the singleton instance is not created until the Instance() method is called for the first time. This technique ensures that singleton instances are created only when needed.
The Singleton class implements a protected constructor so clients cannot instantiate Singleton instances.
Protected constructors can be called by subclasses.
Solutions:Solutions:We can make the Singleton constructor private so that only Singleton’s methods call it;
:: The Classic Singleton - II
C++ Design Patterns 14
The Singleton Pattern
It can be difficult to subclass a Singleton, since this can only work if the base Singleton class has not yet been instantiated.
We can easily change a Singleton to allow a small number of instances where this is allowable and meaningful.
We can use the same approach to control the number of instances that the application uses. Only the operation that grants access to the Singleton instance needs to change.
The Singleton pattern permits refinement of operations and representation. The Singleton class may be subclassed, and it is easy to configure an application with an instance of this extended class. You can configure the application with an instance of the class you need at run-time.
:: Consequences of the Singleton Pattern
Back to Ogre3D
• How to make your own mesh??– 1. Define the geometry.
Mesh
– 2. Define the appearance. Material
Geometry data in Ogre3D
• Indexed Triangle List
1v
2v
3v4v
5v
6v
7v
1v 2v 3v 4v 5v 6v 7v 8v
: 점의 좌표iv
Vertex Data:
0 1 3 1 2 3 0 4 1 Indexed triangle list:
0 1 2 3 4 5 6 7
Mesh and submesh
• In Ogre, a model is called Mesh.– A mesh can represent a whole ‘’object‘’.
• Ex.) a character, a car, a monster
– Mesh is composed of different parts. • Ex.) a character head, arm, leg, and so on. • Different part can have a different material.
• A part in a model is called SubMesh. – A mesh is a set of SubMesh. – A SubMesh has the actual geometry data. – A SubMesh has a unique material.
Entity and subentity
• A mesh can be instanced as an Entity.• Then, Submeshes are automatically
instanced as SubEntities. – A SubEntity can has its own material different
from the submesh. Ex.) cars with different colors.
How to write the geometry data• Hardware Buffer for the vertex and index
data– Hardware buffer is any memory outside of core
system.– Usually, it means for the video RAM. – It is very efficient once the data are transferred
from CPU to GPU. – But, it has very restrictive usage such as only
a sequential write is allowed.
OGRE::Mesh in action
• Get the sample file at our home page
• Create your own cylinder mesh from scratch.
• Reference to read: http://www.ogre3d.org/tikiwiki/Manual+Resource+Loading&structure=Tutorials
OGRE::Mesh in action
• How to make your own mesh:1. Create Mesh in Mesh Manager
2. Create a SubMesh on the mesh
3. Create a vertex declaration4. Create a vertex buffer5. Fill the vertex buffer6. Create an index buffer7. Fill the index buffer
Ogre::Mesh* mMesh = Ogre::MeshManager::getSingleton() .createManual(yourMeshName, "General");Ogre::Mesh* mMesh = Ogre::MeshManager::getSingleton() .createManual(yourMeshName, "General");
Ogre::SubMesh* mSubMesh = mMesh->createSubMesh(SubMeshName);Ogre::SubMesh* mSubMesh = mMesh->createSubMesh(SubMeshName);
Create a Vertex Declaration (1/2)1. Create Vertex Data
2. Connect it to the mesh submeshes share the vertex buffer
3. Declare the data format through an interface
Ogre::VertexData* data = new Ogre::VertexData();Ogre::VertexData* data = new Ogre::VertexData();
mMesh->sharedVertexData = data;mMesh->sharedVertexData = data;
data->vertexCount = iVertexCount;Ogre::VertexDeclaration* decl = data->vertexDeclaration;data->vertexCount = iVertexCount;Ogre::VertexDeclaration* decl = data->vertexDeclaration;
Create a Vertex Declaration (2/2)• Using Vertex Declaration
– A simplest case: Position only
– Position + Normal
– Position + Normal + UV Coord
decl->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);decl->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
size_t offset = 0; decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
size_t offset = 0; decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
size_t offset = 0; decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); decl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
size_t offset = 0; decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); decl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
Create a Vertex Buffer
• Using HardwareBufferManager To Create BufferOgre::HardwareVertexBufferSharedPtr vbuf =
Ogre::HardwareBufferManager::getSingleton().createVertexBuffer ( decl->getVertexSize(0), // This value is the size of a vertex in memory iVertexNbr, // The number of vertices you'll put into this buffer Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY // Properties )
Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer ( decl->getVertexSize(0), // This value is the size of a vertex in memory iVertexNbr, // The number of vertices you'll put into this buffer Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY // Properties )
Fill the vertex buffer
• Prepare your vertex data as an array
• Write the data to the buffer
• Link the buffer to the mesh
vbuf->writeData(0, vbuf->getSizeInBytes(), yourVertexArray, true);vbuf->writeData(0, vbuf->getSizeInBytes(), yourVertexArray, true);
float array[vbufCount];array[0] = vertices[1].x; array[1] = vertices[1].y;array[2] = vertices[1].z;array[3] = vertices[1].normal.x; array[4] = vertices[1].normal.y;array[5] = vertices[1].normal.z;
array[6] = vertices[2].x; …
float array[vbufCount];array[0] = vertices[1].x; array[1] = vertices[1].y;array[2] = vertices[1].z;array[3] = vertices[1].normal.x; array[4] = vertices[1].normal.y;array[5] = vertices[1].normal.z;
array[6] = vertices[2].x; …
In this case, each vertex is declared to have only position + normal data In this case, each vertex is declared to have only position + normal data
Ogre::VertexBufferBinding* bind = data->vertexBufferBinding; bind->setBinding(0, vbuf);Ogre::VertexBufferBinding* bind = data->vertexBufferBinding; bind->setBinding(0, vbuf);
Create an Index Buffer
• Using HardwareIndexBufferManager
Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer ( Ogre::HardwareIndexBuffer::IT_16BIT, // value type: 16bit integer iIndexNbr, // The number of indices you'll put in that buffer Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY // Properties )
Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer ( Ogre::HardwareIndexBuffer::IT_16BIT, // value type: 16bit integer iIndexNbr, // The number of indices you'll put in that buffer Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY // Properties )
Fill the Index Buffer
• Prepare your index data as an array
• Write the index buffer
• Link the index with the submesh
unsigned short index[ibufCount];
index[0] = subMesh[0].vertexIndices[0];index[1] = subMesh[0].vertexIndices[1]; index[2] = subMesh[0].vertexIndices[2]; index[3] = subMesh[1].vertexIndices[0];index[4] = subMesh[1].vertexIndices[1];index[5] = subMesh[1].vertexIndices[2];
unsigned short index[ibufCount];
index[0] = subMesh[0].vertexIndices[0];index[1] = subMesh[0].vertexIndices[1]; index[2] = subMesh[0].vertexIndices[2]; index[3] = subMesh[1].vertexIndices[0];index[4] = subMesh[1].vertexIndices[1];index[5] = subMesh[1].vertexIndices[2];
mSubMesh->indexData->indexBuffer = ibuf; // The pointer to the index buffer mSubMesh->indexData->indexCount = iIndexNbr; // The number of indices mSubMesh->indexData->indexStart = 0; // The offset from the beginning
mSubMesh->indexData->indexBuffer = ibuf; // The pointer to the index buffer mSubMesh->indexData->indexCount = iIndexNbr; // The number of indices mSubMesh->indexData->indexStart = 0; // The offset from the beginning
ibuf->writeData(0, ibuf->getSizeInBytes(), index, true);ibuf->writeData(0, ibuf->getSizeInBytes(), index, true);
Final touch by loading the mesh• Define bounding box for efficient culling
• Notify that the Mesh is loaded
mMesh->_setBounds(Ogre::AxisAlignedBox(xMin,yMin,zMin,xMax,yMax,zMax));mMesh->_setBoundingSphereRadius (std::max(xMax-xMin, std::max(yMax-yMin, zMax-zMin))/2.0f)
mMesh->_setBounds(Ogre::AxisAlignedBox(xMin,yMin,zMin,xMax,yMax,zMax));mMesh->_setBoundingSphereRadius (std::max(xMax-xMin, std::max(yMax-yMin, zMax-zMin))/2.0f)
mMesh->load();mMesh->load();
Material basic attributes• ambient reflectance = ColourValue::White (full) • diffuse reflectance = ColourValue::White (full) • specular reflectance = ColourValue::Black (none) • emmissive = ColourValue::Black (none) • shininess = 0 (not shiny) • No texture layers (& hence no textures) • SourceBlendFactor = SBF_ONE, DestBlendFactor =
SBF_ZERO (opaque) • Depth buffer checking = on • Depth buffer writing = on • Depth buffer comparison function = CMPF_LESS_EQUAL • Culling mode = CULL_CLOCKWISE • Ambient lighting in scene = ColourValue(0.5, 0.5, 0.5) (mid-
grey) • Dynamic lighting = enabled • Gourad shading mode • Solid polygon mode • Bilinear texture filtering