Pages

Senin, 24 Mei 2010

Membuat Sebuah Actor menggunakan Delta 3D

Tutorial ini akan menunjukkan bagaimana membuat seorang aktor baru, impor ke Editor, dan kemudian melihatnya dalam sebuah dtCore:: Scene. Aktor yang akan kita ciptakan menerapkan sebuah gelombang sinus untuk vertex sebagai simulasi fisika kain, contoh seperti bendera melambai tertiup angin. Aktor ini juga akan mengekspos sifat yang tepat yang terkait dengan fisika flag yang kemudian dapat diubah dalam Editor. Beberapa langkah yang harus dilakukan untuk mencapai pembuatan aktor, yaitu :
1.Anda harus mengetahui kode aktor yang akan ditempatkan di dalam layar kerja.
2.Anda harus mengetahui kode proxy aktor yang akan mewakili aktor di Editor.
3.Anda harus menulis sebuah library tempat aktor harus diekspor.
Sebelum semua langkah-langkah diatas kita lakukan, kita perlu menyiapkan sebuah proyek. Tutorial ini menggunakan Microsoft Visual Studio 2003. Untuk mengatur Delta3D, silakan lihat tutorial ini. Sekarang kita perlu link ke library yang tepat untuk menggunakan, Buka Scene Grafik fungsi. Klik kanan pada proyek Anda dan pilih "Properties". Di bawah tab "Linker, pilih Input". Di bawah seleksi "additional dependencies ", tambahkan library berikut: dtcored.lib, dtUtild.lib, dtDALd.lib, dtActorsd.lib, dtvis_d.lib, sg_d.lib, ul_d.lib, osgd.lib, osgDBd.lib, osgUtild . lib.
Ini adalah Delta3D dan Scene Buka Grafik library Anda harus link agar berhasil membangun proyek ini.
Anda juga perlu menambahkan DT_PLUGIN ke definisi preprocessor dalam properti proyek -> c / c + + -> Preprocessor.
Setelah proyek diatur dengan benar, saatnya untuk mulai coding aktor yang sebenarnya. Harap dicatat bahwa aktor ini menggunakan gambar perilaku kompleks yang memerlukan pemahaman dasar-dasar bagaimana Terbuka Scene Grafik bekerja. Secara khusus, penggunaan fungsi callback dan traversal adegan grafik. Mayoritas dari kode ini untuk benar-benar tessellate (melambaikan gerak) aktor dapat ditemukan dalam contoh Scene Terbuka Grafik "osgprerender" yang didistribusikan secara bebas dengan sumber Scene Open Grafik.
Mari kita mulai dengan membuat dua file untuk TessellationActor kelas. Dalam file header, kita perlu menyatakan kelas callback untuk menyelesaikan Scene Grafik yang akan digunakan untuk memperbarui pesawat tessellation. Letakkan kode berikut dalam TessellationActor.h:
#include
#include
#include

class GeometryCallback : public osg::Drawable::UpdateCallback,
public osg::Drawable::AttributeFunctor
{
public:
GeometryCallback(const osg::Vec3& o, const osg::Vec3& x,
const osg::Vec3& y, const osg::Vec3& z, double period, double xphase,
double amplitude): _firstCall(true),_startTime(0.0),_time(0.0),_period(period),
_xphase(xphase), _amplitude(amplitude),_origin(o),_xAxis(x),_yAxis(y), _zAxis(z)
{}
virtual void update(osg::NodeVisitor* nv,osg::Drawable* drawable)
{
const osg::FrameStamp* fs = nv->getFrameStamp();
double referenceTime = fs->getReferenceTime();
if (_firstCall)
{
_firstCall = false;
_startTime = referenceTime;
}

_time = referenceTime-_startTime;

drawable->accept(*this);
drawable->dirtyBound();
}

virtual void apply(osg::Drawable::AttributeType type,unsigned int count,osg::Vec3* begin)
{
if (type == osg::Drawable::VERTICES)
{
const float TwoPI=2.0f*osg::PI;
const float phase = -_time/_period;

osg::Vec3* end = begin+count;
for (osg::Vec3* itr=begin;itr {
osg::Vec3 dv(*itr-_origin);
osg::Vec3 local(dv*_xAxis,dv*_yAxis,dv*_zAxis);

local.z() = local.x()*_amplitude*
sinf(TwoPI*(phase+local.x()*_xphase));

(*itr) = _origin +
_xAxis*local.x()+
_yAxis*local.y()+
_zAxis*local.z();
}
}
}

bool _firstCall;
double _startTime, _time, _period, _xphase;
float _amplitude;

osg::Vec3 _origin, _xAxis, _yAxis, _zAxis;
};
Kode ini mendefinisikan panggilan kembali kelas yang Terbuka Scene Grafik yang akan digunakan untuk tessellate aktor. Sekarang, kita perlu mendefinisikan kelas tessellation aktor yang baru. Tambahkan kode berikut ke file TessellationActor.h:
class TessellationActor : public dtCore::Transformable
{
public:
TessellationActor();
virtual ~TessellationActor();

void GeneratePlane();

// Accessors
inline float GetPeriod() { return period; }
inline float GetAmplitude() { return amplitude; }
inline float GetPhase() { return phase; }
inline int GetNumberOfSteps() { return numberOfSteps; }
inline int GetWidth() { return width; }
inline int GetHeight() { return height; }
inline std::string GetTextureFile() { return textureFile; }
// Mutators
inline void SetPeriod(float newPeriod) { period = newPeriod; GeneratePlane(); }
inline void SetAmplitude(float newAmp) { amplitude = newAmp; GeneratePlane(); }
inline void SetPhase(float newPhase) { phase = newPhase; GeneratePlane(); }
inline void SetWidth(int newWidth) { width = newWidth; GeneratePlane(); }
inline void SetHeight(int newHeight) { height = newHeight; GeneratePlane(); }
inline void SetNumberOfSteps(int numSteps) { numberOfSteps = numSteps; GeneratePlane();}
inline void SetTextureFile(const std::string &fileName) { textureFile = fileName; GeneratePlane(); }

private:
osg::Geode *geode;
std::string textureFile;
int width, height, numberOfSteps;
float period, amplitude, phase;
};
Sekarang kita telah menetapkan TessellationActor, kita mungkin melihat beberapa anggota variabel. File tekstur, misalnya, adalah properti sumber daya. Lebar, tinggi, sejumlah langkah di antara setiap segmen pesawat, periode, amplitudo, dan fasa adalah semua sifat pesawat ini tessellating yang dapat diedit di Tingkat Editor. Sekarang, mari kita kepala ke TessellationActor.cpp file dan menentukan fungsi kelas kami. Fungsi GeneratePlane () bertanggung jawab untuk menghasilkan sebuah pesawat tessellation baru setiap kali sebuah properti diedit. Letakkan kode berikut dalam file TessellationActor.cpp:

#include "TessellationActor.h"

#include
#include
#include
#include
#include
#include
#include
#include

TessellationActor::TessellationActor() :
geode(NULL),width(200), height(100),
numberOfSteps(20), period(1.0), amplitude(0.2)
{
phase = 1.0 / width;
GeneratePlane();
}

TessellationActor::~TessellationActor()
{
}

void TessellationActor::GeneratePlane()
{
// Since the actor will only ever have one plane, remove the old one
// if it contains it
if(geode && geode->getDrawable(0))
geode->removeDrawables(0, 1);

// Initialize the data
osg::Geometry *geometry = new osg::Geometry;
osg::Vec3Array *verts = new osg::Vec3Array;
geode = new osg::Geode;

osg::Vec3 origin(0.0f,0.0f,0.0f);
osg::Vec3 xAxis(1.0f,0.0f,0.0f);
osg::Vec3 yAxis(0.0f,0.0f,1.0f);
osg::Vec3 zAxis(0.0f,-1.0f,0.0f);

osg::Vec3 bottom = origin;
osg::Vec3 top = origin;
top.z() += height;
osg::Vec3 dv = xAxis*(width/((float)(numberOfSteps-1)));

osg::Vec2Array* texcoords = new osg::Vec2Array;
osg::Vec2 bottom_texcoord(0.0f,0.0f);
osg::Vec2 top_texcoord(0.0f,1.0f);
osg::Vec2 dv_texcoord(1.0f/(float)(numberOfSteps-1),0.0f);

// Set up the vertices and texture coordinates
for(int i = 0; i < numberOfSteps; i++)
{
verts->push_back(top);
verts->push_back(bottom);
top += dv;
bottom += dv;

texcoords->push_back(top_texcoord);
texcoords->push_back(bottom_texcoord);
top_texcoord += dv_texcoord;
bottom_texcoord += dv_texcoord;
}

// Apply the texture
osg::Image *texture = osgDB::readImageFile(textureFile);
osg::Texture2D *temp = new osg::Texture2D(texture);
temp->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
temp->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
osg::StateSet *ss = new osg::StateSet;
ss->setTextureAttributeAndModes(0, temp, osg::StateAttribute::ON);
temp->setUnRefImageDataAfterApply(true);

// Set up the geometry
geode->setStateSet(ss);
geometry->setVertexArray(verts);
geometry->setTexCoordArray(0, texcoords);
geode->addDrawable(geometry);
geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP, 0, verts->size()));
geometry->setUpdateCallback(new
GeometryCallback(origin,xAxis,yAxis,zAxis,period,phase,amplitude));
geometry->setSupportsDisplayList(false);

// Add to the transformable
GetMatrixNode()->addChild(geode);
}
Sekarang kita telah mendefinisikan konstruktor berdasarkan nilai defaultnya, dan kami GeneratePlane fungsi didefinisikan untuk membuat pesawat, dan disebut dari masing-masing fungsi mutator kita sehingga pesawat kami akan dibuat ulang dengan nilai-nilai baru dengan benar.
Sekarang kita memiliki kelas TessellationActor yang telah kita siapakan, saatnya untuk membangun proxy nya aktor kelas. Fungsi utama untuk mengetahui dalam kelas proxy aktor adalah fungsi BuildPropertyMap. Fungsi ini bertanggung jawab untuk menambahkan sifat yang terkait dengan aktor. Fungsi lain yang perlu diperhatikan adalah fungsi CreateActor, yang sebenarnya instantiates aktor bahwa proxy adalah abstrak. Letakkan kode berikut dalam file bernama TessellationActorProxy.h:

#ifndef _TESSELLATION_ACTOR_PROXY_H_
#define _TESSELLATION_ACTOR_PROXY_H_

#include "dtDAL/transformableactorproxy.h"
#include "TessellationActor.h"

class TessellationActorProxy : public dtDAL::TransformableActorProxy
{
public:

void CreateActor() {

SetActor(*new TessellationActor);
}
TessellationActorProxy(void);
virtual ~TessellationActorProxy(void);

void BuildPropertyMap();

void SetTextureFile(const std::string &fileName)
{
TessellationActor *actor = dynamic_cast (GetActor());
if(!actor)
{
printf("Actor initialized incorrectly\n");
return;
}
actor->SetTextureFile(fileName);
}
};
#endif
Perhatikan bahwa kelas TessellationActorProxy mewarisi dari dtDAL:: TransformableActorProxy, cara yang mewarisi kelas TessellationActor dari dtCore:: Transformable. Kami juga memiliki fungsi SetTextureFile, yang bertanggung jawab untuk melacak file tekstur sumber daya yang diterapkan pada aktor. Sekarang, kita gunakan TessellationActorProxy.cpp file dan menentukan fungsi kami. Letakkan kode berikut dalam TessellationActorProxy.cpp:
#include "TessellationActorProxy.h"
#include "dtDAL/enginepropertytypes.h"
#include "dtDAL/datatype.h"

TessellationActorProxy::TessellationActorProxy()
{
}

TessellationActorProxy::~TessellationActorProxy()
{
}

void TessellationActorProxy::BuildPropertyMap()
{
// The property group
const std::string groupName = "PolyGrid";

// Make sure to build the base class properties
TransformableActorProxy::BuildPropertyMap();

// Make sure our actor is valid
TessellationActor *actor = dynamic_cast (GetActor());
if(!actor)
{
printf("Actor was initialized incorrectly\n");
return;
}

// Property for the width of the plane
AddProperty(new dtDAL::IntActorProperty("Width", "Width",
dtDAL::MakeFunctor(*actor, &TessellationActor::SetWidth),
dtDAL::MakeFunctorRet(*actor, &TessellationActor::GetWidth),
"Property for the width of the tessellation plane", groupName));

// Property for the height of the plane
AddProperty(new dtDAL::IntActorProperty("Height", "Height",
dtDAL::MakeFunctor(*actor, &TessellationActor::SetHeight),
dtDAL::MakeFunctorRet(*actor, &TessellationActor::GetHeight),
"Property for the height of the tessellation plane", groupName));

// Property for the number of steps in between each "slice" of the plane
AddProperty(new dtDAL::IntActorProperty("Number of Steps", "Number of Steps",
dtDAL::MakeFunctor(*actor, &TessellationActor::SetNumberOfSteps),
dtDAL::MakeFunctorRet(*actor, &TessellationActor::GetNumberOfSteps),
"Property for the number of steps in between each segment of the tessellation plane",
groupName));

// Property for the period of the tessellation
AddProperty(new dtDAL::FloatActorProperty("Period", "Period",
dtDAL::MakeFunctor(*actor, &TessellationActor::SetPeriod),
dtDAL::MakeFunctorRet(*actor, &TessellationActor::GetPeriod),
"Property for the period of the sine wave", groupName));

// Property for the amplitude of the tessellation
AddProperty(new dtDAL::FloatActorProperty("Amplitude", "Amplitude",
dtDAL::MakeFunctor(*actor, &TessellationActor::SetAmplitude),
dtDAL::MakeFunctorRet(*actor, &TessellationActor::GetAmplitude),
"Property for the amplitude of the sine wave", groupName));

// Property for the phase of the tessellation
AddProperty(new dtDAL::FloatActorProperty("Phase", "Phase",
dtDAL::MakeFunctor(*actor, &TessellationActor::SetPhase),
dtDAL::MakeFunctorRet(*actor, &TessellationActor::GetPhase),
"Property for the phase of the sine wave", groupName));

// Property for the texture file of the plane
// Note that resource properties are a little different that other properties. The editor
// DAL needs to store a reference to the actual proxy due to its internals, so all we do
// is add a function onto the proxy which simply calls the actual actor function.

AddProperty(new dtDAL::ResourceActorProperty(*this,dtDAL::DataType::TEXTURE,"Texture",
"Texture", dtDAL::MakeFunctor(*this, &TessellationActorProxy::SetTextureFile), groupName));
Fungsi BuildPropertyMap bertanggung jawab untuk menambahkan semua properti untuk aktor tessellation. Perhatikan bahwa kita menambahkan properti untuk mewakili masing-masing bagian data bahwa aktor tessellation berisi. Sekarang kami memastikan bahwa proxy kami akan tessellation aktor abstrak kita dengan benar dan bahwa sifat ini akan tersedia untuk perubahan di editor. Perlu diketahui bahwa bila menyesuaikan periode, amplitudo, atau fase bahwa tidak ada perubahan yang terlihat akan berlangsung di editor, karena ini adalah properti runtime. Sekarang kita telah aktor kami, dan proxy aktor mendirikan, saatnya untuk menulis sebuah library sehingga kita dapat mengimpor aktor baru kita ke dalam editor.


* Translate : http://www.delta3d.org/article.php?story=20050720135053455&topic=tutorials