OGRE Wiki
Support and community documentation for Ogre3D
Ogre Forums
ogre3d.org
Log in
Username:
Password:
CapsLock is on.
Remember me (for 1 year)
Log in
Home
Tutorials
Tutorials Home
Basic Tutorials
Intermediate Tutorials
Mad Marx Tutorials
In Depth Tutorials
Older Tutorials
External Tutorials
Cookbook
Cookbook Home
CodeBank
Snippets
Experiences
Ogre Articles
Libraries
Libraries Home
Alternative Languages
Assembling A Toolset
Development Tools
OGRE Libraries
List of Libraries
Tools
Tools Home
DCC Tools
DCC Tutorials
DCC Articles
DCC Resources
Assembling a production pipeline
Development
Development Home
Roadmap
Building Ogre
Installing the Ogre SDK
Setting Up An Application
Ogre Wiki Tutorial Framework
Frequently Asked Questions
Google Summer Of Code
Help Requested
Ogre Core Articles
Community
Community Home
Projects Using Ogre
Recommended Reading
Contractors
Wiki
Immediate Wiki Tasklist
Wiki Ideas
Wiki Guidelines
Article Writing Guidelines
Wiki Styles
Wiki Page Tracker
Ogre Wiki Help
Ogre Wiki Help Overview
Help - Basic Syntax
Help - Images
Help - Pages and Structures
Help - Wiki Plugins
Toolbox
Freetags
Categories
List Pages
Structures
Trackers
Statistics
Rankings
List Galleries
Ogre Lexicon
Comments
History: A Series Of Tubes
View page
Source of version: 4
(current)
{maketoc} !!A Series of Tubes A member of the forums (StillmatikX) needed some tubes for his application, and I might need something like it in the future, so I whipped this up: {img src="img/wiki_up/Tubes3.jpg" alt="Tubes3.jpg"} It may not look amazing, but it does the job. Adjusting the material and some initial settings will let you control size, shape and any material attributes. I haven't tested it thoroughly, but you can update your list of points that the tubes follow if you need to add/remove points on the tube. !!The Code This is the header for the SeriesOfTubes class. !!!!Tubes.h {CODE(wrap="1", colors="c++")}#ifndef _TUBES_H_ #define _TUBES_H_ #include <OgrePrerequisites.h> #include <OgreMaterial.h> #include <OgreMesh.h> namespace Ogre { class SeriesOfTubes { public: SeriesOfTubes( Ogre::SceneManager* sceneMgr, const Ogre::uint numberOfSides = 0, const Ogre::Real radius = 0.0, const Ogre::uint sphereRings = 0, const Ogre::uint sphereSegments = 0, const Ogre::Real sphereRadius = 0.0, const Ogre::Real sphereMaxVisibilityDistance = 0.0); ~SeriesOfTubes(); void addPoint(const Ogre::Vector3& pos); void removePoint(const Ogre::uint pointNumber); void setRadius(const Ogre::Real radius){mRadius = radius;} void setSides(const Ogre::uint numberOfSides){mSideCount = numberOfSides;} const Ogre::Real getRadius(){return mRadius;} const Ogre::uint getSides(){return mSideCount;} void setSceneNode(Ogre::SceneNode* sceneNode){mSceneNode = sceneNode;} Ogre::SceneNode* getSceneNode(){return mSceneNode;} Ogre::MaterialPtr getMaterial(){return mMaterial;} Ogre::ManualObject* createTubes( const Ogre::String& name, const Ogre::String& materialName, bool uniqueMaterial = false, bool isDynamic = false, bool disableUVs = false, bool disableNormals = false); void _update(bool disableUVs = false, bool disableNormals = false); void _destroy(); void _createSphere(const Ogre::String& strName); Ogre::ManualObject* createDebug(const Ogre::String& name); private: Ogre::SceneManager* mSceneMgr; typedef std::vector<Ogre::Vector3> VVec; VVec mLineVertices; Ogre::uint mSideCount; Ogre::Real mRadius; bool mUniqueMaterial; Ogre::uint mSphereRings; Ogre::uint mSphereSegments; Ogre::Real mSphereRadius; Ogre::Real mSphereMaxVisDistance; Ogre::MaterialPtr mMaterial; Ogre::ManualObject* mTubeObject; typedef std::vector<Ogre::Entity*> SphereStorage; SphereStorage mSpheresJoints; Ogre::MeshPtr mSphereMesh; Ogre::SceneNode* mSceneNode; }; } #endif{CODE} --- Here's the matching source file for Tubes.h !!!!Tubes.cpp {CODE(wrap="1", colors="c++")}#include "Tubes.h" #include <OgreManualObject.h> #include <OgreMaterialManager.h> #include <OgreSceneManager.h> #include <OgreStringConverter.h> #include <OgreEntity.h> #include <OgreMeshManager.h> #include <OgreHardwareVertexBuffer.h> #include <OgreHardwareIndexBuffer.h> #include <OgreSubMesh.h> using namespace Ogre; namespace Ogre { SeriesOfTubes::SeriesOfTubes( Ogre::SceneManager* sceneMgr, const Ogre::uint numberOfSides /*= 0*/, const Ogre::Real radius /*= 0.0*/, const Ogre::uint sphereRings /*= 0*/, const Ogre::uint sphereSegments /*= 0*/, const Ogre::Real sphereRadius /*= 0.0*/, const Ogre::Real sphereMaxVisibilityDistance /*= 0.0*/ ) : mSceneMgr(sceneMgr), mSideCount(numberOfSides), mRadius(radius), mTubeObject(0), mUniqueMaterial(false), mSphereRings(sphereRings), mSphereSegments(sphereSegments), mSphereRadius(sphereRadius), mSphereMaxVisDistance(sphereMaxVisibilityDistance), mSceneNode(0) { } SeriesOfTubes::~SeriesOfTubes() { _destroy(); } void SeriesOfTubes::addPoint( const Ogre::Vector3& pos ) { mLineVertices.push_back(pos); } void SeriesOfTubes::removePoint( const Ogre::uint pointNumber ) { if (pointNumber < mLineVertices.size()) { VVec::iterator it = mLineVertices.begin() + pointNumber; mLineVertices.erase(it); } } Ogre::ManualObject* SeriesOfTubes::createTubes( const Ogre::String& name, const Ogre::String& materialName, bool uniqueMaterial /* = false*/, bool isDynamic /*= false*/, bool disableUVs /*= false*/, bool disableNormals /*= false*/) { if (mTubeObject) return mTubeObject; mMaterial = MaterialManager::getSingleton().getByName(materialName); mUniqueMaterial = uniqueMaterial; if (mUniqueMaterial) mMaterial = mMaterial->clone(materialName + "_" + name); mTubeObject = mSceneMgr->createManualObject(name); mTubeObject->setDynamic(isDynamic); _update(disableUVs,disableNormals); if (mSceneNode) mSceneNode->attachObject(mTubeObject); return mTubeObject; } void SeriesOfTubes::_update(bool disableUVs /*= false*/, bool disableNormals /*= false*/) { if (mTubeObject == 0 || mLineVertices.size() < 2) return; if (mTubeObject->getDynamic() == true && mTubeObject->getNumSections() > 0) mTubeObject->beginUpdate(0); else mTubeObject->begin(mMaterial->getName()); Quaternion qRotation(Degree(360.0/(Real)mSideCount),Vector3::UNIT_Z); const uint iVertCount = mSideCount + 1; Vector3* vCoreVerts = new Vector3[iVertCount]; Vector3 vPos = Vector3::UNIT_Y * mRadius; for (int i=0;i<iVertCount;i++) { vCoreVerts[i] = vPos; vPos = qRotation * vPos; } Vector3 vLineVertA, vLineVertB; Vector3 vLine; Real dDistance; int A,B,C,D; int iOffset; Vector3* vCylinderVerts = new Vector3[iVertCount * 2]; for (int i=1;i<mLineVertices.size();i++) { vLineVertA = mLineVertices[i-1]; vLineVertB = mLineVertices[i]; vLine = vLineVertB - vLineVertA; dDistance = vLine.normalise(); qRotation = Vector3::UNIT_Z.getRotationTo(vLine); for (int j=0;j<iVertCount;j++) { vCylinderVerts[j] = (qRotation * vCoreVerts[j]); vCylinderVerts[j + iVertCount] = (qRotation * (vCoreVerts[j] + (Vector3::UNIT_Z * dDistance))); } Real u,v,delta; delta = 1.0 / (Real)(iVertCount-1); u = 0.0; v = 1.0; for (int j=0;j<(iVertCount*2);j++) { mTubeObject->position(vCylinderVerts[j] + vLineVertA); if (disableNormals == false) { mTubeObject->normal(vCylinderVerts[j].normalisedCopy()); } if (disableUVs == false) { if (j == iVertCount){ u = 0.0; v = 0.0; } mTubeObject->textureCoord(u,v); u += delta; } } iOffset = (i-1) * (iVertCount*2); for (int j=0;j<iVertCount;j++) { // End A: 0-(Sides-1) // End B: Sides-(Sides*2-1) // Verts: /* A = (j+1)%Sides C = A + Sides B = j D = B + Sides */ A = ((j+1) % iVertCount); B = j; C = A + iVertCount; D = B + iVertCount; A += iOffset; B += iOffset; C += iOffset; D += iOffset; // Tri #1 // C,B,A mTubeObject->triangle(C,B,A); // Tri #2 // C,D,B mTubeObject->triangle(C,D,B); } } delete[] vCoreVerts; delete[] vCylinderVerts; vCoreVerts = 0; vCylinderVerts = 0; if (mSphereMesh.isNull() == true) _createSphere(mTubeObject->getName() + "_SphereMesh"); if (mSceneNode) mSceneNode->removeAndDestroyAllChildren(); Entity* pEnt = 0; SceneNode* pChildNode = 0; VVec::iterator it = mLineVertices.begin()+1; for (int i=1; it != (mLineVertices.end()-1);++it,i++) { if (mSpheresJoints.size() < i) { pEnt = mSceneMgr->createEntity(mTubeObject->getName() + "_SphereEnt" + StringConverter::toString(i),mSphereMesh->getName()); pEnt->setMaterialName(mMaterial->getName()); mSpheresJoints.push_back(pEnt); } else { pEnt = mSpheresJoints[i-1]; } pEnt->setRenderingDistance(mSphereMaxVisDistance); if (mSceneNode) { pChildNode = mSceneNode->createChildSceneNode(); pChildNode->setPosition((*it)); pChildNode->attachObject(pEnt); } } mTubeObject->end(); } void SeriesOfTubes::_destroy() { if (mTubeObject) { if (mTubeObject->getParentSceneNode()) mTubeObject->getParentSceneNode()->detachObject(mTubeObject); mSceneMgr->destroyManualObject(mTubeObject); } if (mUniqueMaterial) { MaterialManager::getSingleton().remove(mMaterial->getName()); } mMaterial.setNull(); if (mSpheresJoints.size() > 0) { Entity* pEnt = 0; SphereStorage::iterator it = mSpheresJoints.begin(); for (; it != mSpheresJoints.end(); ++it) { pEnt = (*it); pEnt->getParentSceneNode()->detachObject(pEnt); mSceneMgr->destroyEntity(pEnt); } } if (mSphereMesh.isNull() == false) { MeshManager::getSingleton().remove(mSphereMesh->getName()); mSphereMesh.setNull(); } if (mSceneNode) { mSceneNode->removeAndDestroyAllChildren(); mSceneNode->getParentSceneNode()->removeAndDestroyChild(mSceneNode->getName()); mSceneNode = 0; } } Ogre::ManualObject* SeriesOfTubes::createDebug( const Ogre::String& name ) { ManualObject* pObj = mSceneMgr->createManualObject(name); pObj->begin("BaseWhiteNoLighting",RenderOperation::OT_LINE_STRIP); VVec::iterator it = mLineVertices.begin(); for (; it != mLineVertices.end();++it) { pObj->position((*it)); pObj->colour(Math::UnitRandom(),Math::UnitRandom(),Math::UnitRandom()); } pObj->end(); return pObj; } /////////////////////////////////////////////////////////////////////////////////// // Courtesy of the Wiki: http://www.ogre3d.org/wiki/index.php/ManualSphereMeshes // /////////////////////////////////////////////////////////////////////////////////// void SeriesOfTubes::_createSphere( const Ogre::String& strName) { mSphereMesh = MeshManager::getSingleton().createManual(strName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); SubMesh *pSphereVertex = mSphereMesh->createSubMesh(); mSphereMesh->sharedVertexData = new VertexData(); VertexData* vertexData = mSphereMesh->sharedVertexData; // define the vertex format VertexDeclaration* vertexDecl = vertexData->vertexDeclaration; size_t currOffset = 0; // positions vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION); currOffset += VertexElement::getTypeSize(VET_FLOAT3); // normals vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL); currOffset += VertexElement::getTypeSize(VET_FLOAT3); // two dimensional texture coordinates vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); currOffset += VertexElement::getTypeSize(VET_FLOAT2); // allocate the vertex buffer vertexData->vertexCount = (mSphereRings + 1) * (mSphereSegments+1); HardwareVertexBufferSharedPtr vBuf = HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); VertexBufferBinding* binding = vertexData->vertexBufferBinding; binding->setBinding(0, vBuf); float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD)); // allocate index buffer pSphereVertex->indexData->indexCount = 6 * mSphereRings * (mSphereSegments + 1); pSphereVertex->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_16BIT, pSphereVertex->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); HardwareIndexBufferSharedPtr iBuf = pSphereVertex->indexData->indexBuffer; unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD)); float fDeltaRingAngle = (Math::PI / mSphereRings); float fDeltaSegAngle = (2 * Math::PI / mSphereSegments); unsigned short wVerticeIndex = 0 ; // Generate the group of rings for the sphere for( int ring = 0; ring <= mSphereRings; ring++ ) { float r0 = mSphereRadius * sinf (ring * fDeltaRingAngle); float y0 = mSphereRadius * cosf (ring * fDeltaRingAngle); // Generate the group of segments for the current ring for(int seg = 0; seg <= mSphereSegments; seg++) { float x0 = r0 * sinf(seg * fDeltaSegAngle); float z0 = r0 * cosf(seg * fDeltaSegAngle); // Add one vertex to the strip which makes up the sphere *pVertex++ = x0; *pVertex++ = y0; *pVertex++ = z0; Vector3 vNormal = Vector3(x0, y0, z0).normalisedCopy(); *pVertex++ = vNormal.x; *pVertex++ = vNormal.y; *pVertex++ = vNormal.z; *pVertex++ = (float) seg / (float) mSphereSegments; *pVertex++ = (float) ring / (float) mSphereRings; if (ring != mSphereRings) { // each vertex (except the last) has six indices pointing to it *pIndices++ = wVerticeIndex + mSphereSegments + 1; *pIndices++ = wVerticeIndex; *pIndices++ = wVerticeIndex + mSphereSegments; *pIndices++ = wVerticeIndex + mSphereSegments + 1; *pIndices++ = wVerticeIndex + 1; *pIndices++ = wVerticeIndex; wVerticeIndex ++; } }; // end for seg } // end for ring // Unlock vBuf->unlock(); iBuf->unlock(); // Generate face list pSphereVertex->useSharedVertices = true; // the original code was missing this line: mSphereMesh->_setBounds( AxisAlignedBox( Vector3(-mSphereRadius, -mSphereRadius, -mSphereRadius), Vector3(mSphereRadius, mSphereRadius, mSphereRadius) ), false ); mSphereMesh->_setBoundingSphereRadius(mSphereRadius); // this line makes clear the mesh is loaded (avoids memory leaks) mSphereMesh->load(); } }{CODE} !!Usage It's pretty simple to use, but has a few options to make it suit your application: !!!Example {CODE(wrap="1", colors="c++")} SceneNode* pNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); SeriesOfTubes* mTubes = new SeriesOfTubes(mSceneMgr,16,10.0,12,12,12.0); mTubes->addPoint(Vector3(0,0,0)); mTubes->addPoint(Vector3(100,0,200)); mTubes->addPoint(Vector3(0,200,400)); mTubes->addPoint(Vector3(50,340,300)); mTubes->addPoint(Vector3(500,340,200)); mTubes->addPoint(Vector3(400,100,100)); mTubes->addPoint(Vector3(50,-20,10)); mTubes->addPoint(Vector3(0,-100,-300)); mTubes->setSceneNode(pNode); mTubes->createTubes("MyTubes","Examples/GrassFloor");{CODE} --- That created a simple, bendy tube with spheres at the joints (the joints I originally had were far uglier - feel free to improve on that!). It's got the "Example/GrassFloor" material, 16 sided cylinders for the tubes at 10.0 units radius and spheres with 12 rings, 12 segments and radius of 12.0 units. It also has vertex normals and UV coordinates. !!!Some customization info Here is the function for the tube creation {CODE(wrap="1", colors="c++")} Ogre::ManualObject* createTubes( const Ogre::String& name, const Ogre::String& materialName, bool uniqueMaterial = false, bool isDynamic = false, bool disableUVs = false, bool disableNormals = false);{CODE} As you can see, you're able to name it and give it a material. The optional functions are as follows: {CODE(wrap="1", colors="c++")} '''uniqueMaterial''' - If you plan on manipulating materials separately for each SeriesOfTubes, set this to true. '''isDynamic''' - This is if you plan on adding and/or removing points from the line; this might cause some weird issues as I haven't tested this much. '''disableUVs''' - If you're not going to have a texture in your material, you can set this to false to save some vertex data space. '''disableNormals''' - If you're not using lighting information at all, set this to false and save more vertex data space. {CODE} !!Conclusion Well that's pretty much all there is to it. It might be a bit quirky if you have it dynamic, but I don't have much time to test it out now. It should be fairly straight forward to deal with otherwise, following the Example code. Just create a new SeriesOfTubes for each separate set of tubes you want to make - just don't forget to destroy them when you're done (it handles all the cleanup!) --- Alias: (alias(A_Series_Of_Tubes))
Search by Tags
Search Wiki by Freetags
Latest Changes
IDE Eclipse
FMOD SoundManager
HDRlib
Building Ogre V2 with CMake
Ogre 2.1 FAQ
Minimal Ogre Collision
Artifex Terra
OpenMB
Advanced Mogre Framework
MogreSocks
...more
Search
Find
Advanced
Search Help
Online Users
110 online users