뫼비우스의 띠(CMobiusStripSceneNode)

Dev.Write 2011. 5. 24. 22:37 Posted by zetz
네이버 오늘의 과학 참조 (뫼비우스의 띠 씬노드)
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