네이버 오늘의 과학 참조 (뫼비우스의 띠 씬노드)
http://navercast.naver.com/contents.nhn?contents_id=3630&path=|186|206|268|&leafId=323
CMobiusStripSceneNode.h
CMobiusStripSceneNode.cpp
http://navercast.naver.com/contents.nhn?contents_id=3630&path=|186|206|268|&leafId=323
CMobiusStripSceneNode.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #pragma once #include <irrlicht.h> #include <cassert> namespace helper { struct IndexHelper { IndexHelper( int u_, int v_) : MaxU(u_), MaxV(v_) { } inline const int getIndex( int u, int v) const { return u * MaxV + v; } inline const int getTotalCount() const { return MaxU * MaxV; } int MaxU; int MaxV; }; } using namespace irr; class CMobiusStripSceneNode : public irr::scene::IMeshSceneNode { public : struct createParameter { createParameter(){ Size = 32.f; Width = 2.f; Stacks = 32; Slices = 7; } f32 Size; f32 Width; u32 Stacks; u32 Slices; }; CMobiusStripSceneNode( scene::ISceneNode* parent, scene::ISceneManager* smgr, s32 id, core::vector3df& pos, CMobiusStripSceneNode::createParameter& cp = CMobiusStripSceneNode::createParameter() ); virtual ~CMobiusStripSceneNode( void ); // virtual functions virtual void OnRegisterSceneNode(); virtual void render(); virtual const core::aabbox3d<f32>& getBoundingBox() const ; virtual u32 getMaterialCount() const { return 1; }; virtual video::SMaterial& getMaterial(u32 i); virtual void setMesh(scene::IMesh* mesh) {} virtual scene::IMesh* getMesh( void ) { return m_pMesh; } virtual void setReadOnlyMaterials( bool readonly) {} virtual bool isReadOnlyMaterials() const { return false ; } private : core::vector3df getMobiusVert(f32 u, f32 v); scene::IMesh* m_pMesh; }; |
CMobiusStripSceneNode.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | #include "StdAfx.h" #include "CMobiusStripSceneNode.h" #include "IndexHelper.h" CMobiusStripSceneNode::CMobiusStripSceneNode( scene::ISceneNode* parent, scene::ISceneManager* smgr, s32 id, core::vector3df& pos, createParameter& cp /*= createParameter() */ ) : scene::IMeshSceneNode(parent, smgr, id, pos) , m_pMesh(NULL) { using namespace core; using namespace scene; using namespace video; /** calculate torus knot buffer size */ const u32 numVertives = cp.Stacks * cp.Slices; const u32 numIndices = cp.Stacks * cp.Slices * 6; //< 마지막 라인은 렌더 제외 scene::SMeshBuffer* buffer = new scene::SMeshBuffer; buffer->Vertices.set_used(numVertives); buffer->Indices.set_used(numIndices); for (u32 i=0; i< cp.Stacks; ++i) { const f32 degree = (360.f / cp.Stacks) * i; const f32 u = core::DEGTORAD * degree; for (u32 j=0; j< cp.Slices; ++j) { const f32 width = (cp.Width / (cp.Slices-1)) * j; const f32 v = -(cp.Width * 0.5f) + width; const u32 vertexNumber = i* cp.Slices+j; buffer->Vertices[vertexNumber].Pos = getMobiusVert(u, v) * cp.Size; buffer->Vertices[vertexNumber].Color = video::SColor(255, 128, 128, 255); } } /** create tube index of torus knots */ helper::IndexHelper ih(cp.Stacks, cp.Slices); for (u32 i=0; i< cp.Stacks; ++i) { for (u32 j=0; j< cp.Slices; ++j) { /** 0 ------ 2 | /| | / | | / | 1 ------ 3 triangle 1 - index 0, 1, 2 triangle 2 - index 3, 2, 1 */ const bool is_last_slice = (j == (cp.Slices - 1)); const bool is_last_stack = (i == (cp.Stacks - 1)); if (is_last_slice) { /** @brief 띠의 가장 아래 부분은 메쉬를 생성 예외 */ u32 base_idx = ih.getIndex(i, j) * 6; buffer->Indices[base_idx ] = 0; buffer->Indices[base_idx+1] = 0; buffer->Indices[base_idx+2] = 0; buffer->Indices[base_idx+3] = 0; buffer->Indices[base_idx+4] = 0; buffer->Indices[base_idx+5] = 0; continue ; } u32 quad[4]; quad[0] = ih.getIndex(i, j); quad[1] = ih.getIndex(i, j+1); quad[2] = (is_last_stack) ? ih.getIndex(0, cp.Slices-1 - j) : ih.getIndex(i+1, j); quad[3] = (is_last_stack) ? ih.getIndex(0, cp.Slices-1 - j-1) : ih.getIndex(i+1, j+1); /** @brief 스택 마지막 경우 완전 중요!! 인덱스가 Slice 기준으로 뒤바뀌어야 한다. 뫼비우스라서 마지막 인덱스와 처음 인덱스를 바로 연결하면 이상함!!! */ u32 base_idx = ih.getIndex(i, j) * 6; buffer->Indices[base_idx ] = quad[0]; buffer->Indices[base_idx+1] = quad[1]; buffer->Indices[base_idx+2] = quad[2]; buffer->Indices[base_idx+3] = quad[3]; buffer->Indices[base_idx+4] = quad[2]; buffer->Indices[base_idx+5] = quad[1]; } } //< clear vertex normal for (u32 i=0; i< numVertives; ++i) buffer->Vertices[i].Normal = vector3df(0.f, 0.f, 0.f); //< summury normal of vertex (for smooth shading) for (u32 i=0; i< numIndices; i+=3) { S3DVertex& v1 = buffer->Vertices[buffer->Indices[i+0]]; S3DVertex& v2 = buffer->Vertices[buffer->Indices[i+1]]; S3DVertex& v3 = buffer->Vertices[buffer->Indices[i+2]]; plane3df triPlane(v1.Pos, v2.Pos, v3.Pos); v1.Normal += triPlane.Normal; v2.Normal += triPlane.Normal; v3.Normal += triPlane.Normal; } //< normalize of vertex normal for (u32 i=0; i< numVertives; ++i) buffer->Vertices[i].Normal.normalize(); buffer->getMaterial().setFlag(EMF_BACK_FACE_CULLING, false ); //buffer->getMaterial().setFlag(EMF_LIGHTING, false); buffer->getMaterial().setFlag(EMF_WIREFRAME, true ); SMesh* mesh = new SMesh; mesh->addMeshBuffer(buffer); buffer->drop(); mesh->recalculateBoundingBox(); m_pMesh = mesh; } CMobiusStripSceneNode::~CMobiusStripSceneNode( void ) { if (m_pMesh) m_pMesh->drop(); } core::vector3df CMobiusStripSceneNode::getMobiusVert(f32 u, f32 v) { /** u, v(0<=u<=2pi, -1<=v<=1) x(u, v) = (1 + 1/2*v*cos(1/2*u) )*cos(u) y(u, v) = (1 + 1/2*v*cos(1/2*u) )*sin(u) z(u, v) = 1/2*v*sin(1/2*u) */ f32 h_v = 0.5f*v; f32 h_u = 0.5f*u; f32 x = (1+ h_v* cos (h_u)) * cos (u); f32 y = (1+ h_v* cos (h_u)) * sin (u); f32 z = h_v* sin (h_u); return core::vector3df(x, y, z); } void CMobiusStripSceneNode::OnRegisterSceneNode() { if (IsVisible) SceneManager->registerNodeForRendering( this ); ISceneNode::OnRegisterSceneNode(); } void CMobiusStripSceneNode::render() { video::IVideoDriver* driver = SceneManager->getVideoDriver(); driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); driver->setMaterial( m_pMesh->getMeshBuffer(0)->getMaterial() ); driver->drawMeshBuffer(m_pMesh->getMeshBuffer(0)); } const core::aabbox3d<f32>& CMobiusStripSceneNode::getBoundingBox() const { return m_pMesh->getMeshBuffer(0)->getBoundingBox(); } video::SMaterial& CMobiusStripSceneNode::getMaterial( u32 i ) { return m_pMesh->getMeshBuffer(0)->getMaterial(); } |
'Dev.Write' 카테고리의 다른 글
Hook 관련 예제 아티클 (0) | 2011.06.09 |
---|---|
동적 코드 실행 계층구조(CEH) (0) | 2011.06.09 |
Irricht + bullet base sample (0) | 2011.05.11 |
TorusKNotSceneNode (0) | 2011.05.11 |
모서리가 둥근 박스 만들기 (0) | 2011.04.18 |