c:這是地圖材質的更換效果.
路人:我看你就簡介好了,貼了一堆程式碼,也看不出重點.
c:其實把它想成是2D的平面地圖就好了,只是有很多層,有些材質永遠會蓋在其它材質上面.
路人:好簡單的介紹,我看你以後就放影片好了...
2011年3月16日 星期三
2011年3月12日 星期六
MapEdit - 介紹
c:另一個未完成的工具,編輯地圖的工具.
路人:很眼熟耶,就是那個Warcraft III的地圖嘛...,啊又偷拿別人的圖了哦.
c:別說偷嘛,練習總要素材嘛.
路人:我好像有看過別人做過了,而且做得比這個好耶.
c:當然了,這些東西不足以商業化,但是整理一番,做一些入門性質的教學也是不錯的.
路人:其實之前的BoneEdit有點混耶,很多東西都隨便帶過了.
c:嗯,確實是沒有好好的規劃,這次我想介紹仔細點.
路人:對啊,又沒人在趕你,寫詳細點再貼上來吧.
c:嗯,請耐心等待吧.
路人:很眼熟耶,就是那個Warcraft III的地圖嘛...,啊又偷拿別人的圖了哦.
c:別說偷嘛,練習總要素材嘛.
路人:我好像有看過別人做過了,而且做得比這個好耶.
c:當然了,這些東西不足以商業化,但是整理一番,做一些入門性質的教學也是不錯的.
路人:其實之前的BoneEdit有點混耶,很多東西都隨便帶過了.
c:嗯,確實是沒有好好的規劃,這次我想介紹仔細點.
路人:對啊,又沒人在趕你,寫詳細點再貼上來吧.
c:嗯,請耐心等待吧.
2011年3月9日 星期三
BoneEdit - 動作
c:終於完成了,看看最後的成果吧.
路人:為什麼我有種空虛的感覺啊,好像沒介紹什麼.
c:其實最後這個影片是有點多餘啦,因為前面的功能做好後,目地就是要可以編動作.
路人:移動那個左上角的刻度有什麼做用嗎?
c:那是一格一格的單張動作,編輯時,就選好某一格,然後調整骨骼的位置.
路人:哦,編了不少嘛...,你是不是很閒啊?
c:編動作確實是花了不少時間,現在不作這種事了.
路人:最後的那些動畫,就是那些單格的動作做內插所做出來的吧.
c:是啊,如果你有注意到,跑步的動作是8~15格作出來的,最後的出拳是43~45格.
路人:我覺得調的動作不夠細,很不專業耶.
c:別管這個了,下次就會再介紹新的工具.
路人:為什麼我有種空虛的感覺啊,好像沒介紹什麼.
c:其實最後這個影片是有點多餘啦,因為前面的功能做好後,目地就是要可以編動作.
路人:移動那個左上角的刻度有什麼做用嗎?
c:那是一格一格的單張動作,編輯時,就選好某一格,然後調整骨骼的位置.
路人:哦,編了不少嘛...,你是不是很閒啊?
c:編動作確實是花了不少時間,現在不作這種事了.
路人:最後的那些動畫,就是那些單格的動作做內插所做出來的吧.
c:是啊,如果你有注意到,跑步的動作是8~15格作出來的,最後的出拳是43~45格.
路人:我覺得調的動作不夠細,很不專業耶.
c:別管這個了,下次就會再介紹新的工具.
2011年3月8日 星期二
BoneEdit - 權重
c:先來瞧瞧頂點的權重設定:
路人:解釋一下左上角數值要怎麼填吧.
c:那個值就是你在選擇頂點的時候,頂點會被改成這個權重值,最大只能輸入1,
當你的一個頂點會被2個骨骼平均影響的話,那這個值要填0.5,
然後先選第一個影響的骨骼,再選那個頂點,之後再選第二個影響的骨骼,
最後再選同一個點頂就完成了.
路人:你是在繞口令嗎?這樣誰聽得懂呀!
c:配合影片,然後再自行體會吧...
//網格計算
memcpy(Form1->Mmd->Mesh, Form1->Mmd->MeshCopy, sizeof(Vector) * Form1->Mmd->MeshCount );
Form1->BoneCopy->ComputeWPos();
Form1->DeformBone( Form1->BoneCopy->Bone, Form1->Mmd->MeshCopy, Form1->Mmd->Mesh );
//最重要的,將頂點乘上權矩陣後,依對應的骨骼與權重作運算
void TForm1::DeformBone(gBone *rootBone, Vector *meshdata, Vector *defdata)
{
if( !rootBone || !meshdata || !CV_weight)
return;
int loop,boneloop;
float weight=0;
Vector pre,post;
gBone *curBone = rootBone->children;
for (boneloop = 0; boneloop < rootBone->childCnt; boneloop++)
{
for (loop=0;loop<Mmd->MeshCount;loop++)
{
weight = CV_weight[rootBone->children[boneloop].id][loop];
if (weight > 0.0)
{
pre[0] = meshdata[loop][0] - rootBone->children[boneloop].wpos[0];
pre[1] = meshdata[loop][1] - rootBone->children[boneloop].wpos[1];
pre[2] = meshdata[loop][2] - rootBone->children[boneloop].wpos[2];
gVector tpost;
MultVectorByMatrix(&rootBone->children[boneloop].matrix, pre, &tpost);
post[0]=tpost.x,post[1]=tpost.y,post[2]=tpost.z;
//處理權重
defdata[loop][0] += ((post[0] - meshdata[loop][0]) * weight);
defdata[loop][1] += ((post[1] - meshdata[loop][1]) * weight);
defdata[loop][2] += ((post[2] - meshdata[loop][2]) * weight);
}
}
if (curBone->childCnt > 0)
DeformBone(curBone, meshdata, defdata);
curBone++;
}
}
//頂點與矩陣做運算
void TForm1::MultVectorByMatrix(gMatrix *mat, Vector v, gVector *result)
{
result->x = (mat->m[0] * v[0]) +
(mat->m[4] * v[1]) +
(mat->m[8] * v[2]) +
mat->m[12];
result->y = (mat->m[1] * v[0]) +
(mat->m[5] * v[1]) +
(mat->m[9] * v[2]) +
mat->m[13];
result->z = (mat->m[2] * v[0]) +
(mat->m[6] * v[1]) +
(mat->m[10] * v[2]) +
mat->m[14];
}
路人:解釋一下左上角數值要怎麼填吧.
c:那個值就是你在選擇頂點的時候,頂點會被改成這個權重值,最大只能輸入1,
當你的一個頂點會被2個骨骼平均影響的話,那這個值要填0.5,
然後先選第一個影響的骨骼,再選那個頂點,之後再選第二個影響的骨骼,
最後再選同一個點頂就完成了.
路人:你是在繞口令嗎?這樣誰聽得懂呀!
c:配合影片,然後再自行體會吧...
//網格計算
memcpy(Form1->Mmd->Mesh, Form1->Mmd->MeshCopy, sizeof(Vector) * Form1->Mmd->MeshCount );
Form1->BoneCopy->ComputeWPos();
Form1->DeformBone( Form1->BoneCopy->Bone, Form1->Mmd->MeshCopy, Form1->Mmd->Mesh );
//最重要的,將頂點乘上權矩陣後,依對應的骨骼與權重作運算
void TForm1::DeformBone(gBone *rootBone, Vector *meshdata, Vector *defdata)
{
if( !rootBone || !meshdata || !CV_weight)
return;
int loop,boneloop;
float weight=0;
Vector pre,post;
gBone *curBone = rootBone->children;
for (boneloop = 0; boneloop < rootBone->childCnt; boneloop++)
{
for (loop=0;loop<Mmd->MeshCount;loop++)
{
weight = CV_weight[rootBone->children[boneloop].id][loop];
if (weight > 0.0)
{
pre[0] = meshdata[loop][0] - rootBone->children[boneloop].wpos[0];
pre[1] = meshdata[loop][1] - rootBone->children[boneloop].wpos[1];
pre[2] = meshdata[loop][2] - rootBone->children[boneloop].wpos[2];
gVector tpost;
MultVectorByMatrix(&rootBone->children[boneloop].matrix, pre, &tpost);
post[0]=tpost.x,post[1]=tpost.y,post[2]=tpost.z;
//處理權重
defdata[loop][0] += ((post[0] - meshdata[loop][0]) * weight);
defdata[loop][1] += ((post[1] - meshdata[loop][1]) * weight);
defdata[loop][2] += ((post[2] - meshdata[loop][2]) * weight);
}
}
if (curBone->childCnt > 0)
DeformBone(curBone, meshdata, defdata);
curBone++;
}
}
//頂點與矩陣做運算
void TForm1::MultVectorByMatrix(gMatrix *mat, Vector v, gVector *result)
{
result->x = (mat->m[0] * v[0]) +
(mat->m[4] * v[1]) +
(mat->m[8] * v[2]) +
mat->m[12];
result->y = (mat->m[1] * v[0]) +
(mat->m[5] * v[1]) +
(mat->m[9] * v[2]) +
mat->m[13];
result->z = (mat->m[2] * v[0]) +
(mat->m[6] * v[1]) +
(mat->m[10] * v[2]) +
mat->m[14];
}
2011年3月6日 星期日
BoneEdit - 骨骼
c:骨骼的功能操作過程如下:
路人:那個骨骼資料從那裡來的啊?
c:自己先定義一個文字檔,填入編號、位置、相依關係等...
主要是得到骨架的資料,載入工具後,就可以自由調整了.
路人:這種事用3DMAX來做,再導出骨骼不是更好?
c:沒錯,那這個工具也不用寫了,直接寫3DMAX外掛就好啦.
反正不是為工作而做的,從無到有弄個編輯器也是有其中的樂趣嘛.
路人:嗯,那就抓些重點出來吧.
c:先看一些定義吧.
typedef struct
{
float r,g,b;
} gColor;
struct gBone//一根骨骼
{
long id; // BONE ID
char name[32]; // BONE NAME
gBone *parent; // POINTER TO PARENT BONE
int childCnt;//子骨骼數量 // COUNT OF CHILD BONES
gBone *children;//指向的子骨骼位置 // POINTER TO CHILDREN
int childrenidx;//指向的子骨骼位置索引
gMatrix matrix;//矩形的值
Vector pos;
Vector rot;
Vector startrot;//初始旋轉量
Vector startpos;//初始位置
Vector wpos;//真實的世界位置
int length;//長
int width; //寬
gColor color;
};
最重要的變數就是matrix了,模型的頂點都要乘上這個值,這樣模型就會跟著骨骼動作了,
它的定義前幾篇就有貼出來了,這裡我再貼一次.
typedef struct
{
float m[16];
} gMatrix;
class CBone
{
public:
CBone();
virtual ~CBone();
bool LoadBone( char *filename );//載入文字檔
bool LoadBone_b( char *filename );//載入位元檔
bool SaveBone_b( char *filename );//存入位元檔
void Draw( GLenum mode );
void Destroy( void );
bool flag( void ){ if( Bone ) return true; else return false; }
void AllColor( float r, float g, float b );//設定所有骨骼顏色
void Color( int id, float r, float g, float b );//設定骨骼顏色
void ComputeWPos( void );//算出每個骨骼的世界位置
Vector CameraPoint;
Vector CameraView;
int BoneCount, Selectid;
bool Show; //是否顥示出來
gBone *Bone;
protected:
void DrawSkeleton( gBone *rootBone, GLenum mode );
void BoneBox( gBone *curBone );
void CWPos( gBone *rootBone );//算出每個骨骼的世界位置
};
matrix怎麼算出來的呢?呼叫DrawSkeleton就可得到
void CBone::Draw( GLenum mode )
{
if( !Bone )
return;
glPushMatrix();
glTranslatef(Bone->startpos[0]+Bone->pos[0],
Bone->startpos[1]+Bone->pos[1],
Bone->startpos[2]+Bone->pos[2]);
glRotatef(Bone->rot[2], 0.0f, 0.0f, 1.0f);
glRotatef(Bone->rot[1], 0.0f, 1.0f, 0.0f);
glRotatef(Bone->rot[0], 1.0f, 0.0f, 0.0f);
DrawSkeleton(Bone,mode);
glPopMatrix();
}
DrawSkeleton是個遞迴函式,因為骨頭是一層一層的
void CBone::DrawSkeleton( gBone *rootBone, GLenum mode )
{
int loop;
gBone *curBone;
curBone = rootBone->children;
for (loop = 0; loop < rootBone->childCnt; loop++)
{
glPushMatrix();
glTranslatef(curBone->startpos[0]+curBone->pos[0],
curBone->startpos[1]+curBone->pos[1],
curBone->startpos[2]+curBone->pos[2]);
glRotatef(curBone->rot[2], 0.0f, 0.0f, 1.0f);
glRotatef(curBone->rot[1], 0.0f, 1.0f, 0.0f);
glRotatef(curBone->rot[0], 1.0f, 0.0f, 0.0f);
if( mode == GL_SELECT )
{
if( Show )
{
glLoadName(curBone->id);
BoneBox( curBone );
}
}
else
{
if( Show )
BoneBox( curBone );
}
glGetFloatv(GL_MODELVIEW_MATRIX,curBone->matrix.m);///在這裡取得的矩陣就可以給模型用了
if (curBone->childCnt > 0)
DrawSkeleton( curBone, mode );
glPopMatrix();
curBone++;
}
}
路人:那個骨骼資料從那裡來的啊?
c:自己先定義一個文字檔,填入編號、位置、相依關係等...
主要是得到骨架的資料,載入工具後,就可以自由調整了.
路人:這種事用3DMAX來做,再導出骨骼不是更好?
c:沒錯,那這個工具也不用寫了,直接寫3DMAX外掛就好啦.
反正不是為工作而做的,從無到有弄個編輯器也是有其中的樂趣嘛.
路人:嗯,那就抓些重點出來吧.
c:先看一些定義吧.
typedef struct
{
float r,g,b;
} gColor;
struct gBone//一根骨骼
{
long id; // BONE ID
char name[32]; // BONE NAME
gBone *parent; // POINTER TO PARENT BONE
int childCnt;//子骨骼數量 // COUNT OF CHILD BONES
gBone *children;//指向的子骨骼位置 // POINTER TO CHILDREN
int childrenidx;//指向的子骨骼位置索引
gMatrix matrix;//矩形的值
Vector pos;
Vector rot;
Vector startrot;//初始旋轉量
Vector startpos;//初始位置
Vector wpos;//真實的世界位置
int length;//長
int width; //寬
gColor color;
};
最重要的變數就是matrix了,模型的頂點都要乘上這個值,這樣模型就會跟著骨骼動作了,
它的定義前幾篇就有貼出來了,這裡我再貼一次.
typedef struct
{
float m[16];
} gMatrix;
class CBone
{
public:
CBone();
virtual ~CBone();
bool LoadBone( char *filename );//載入文字檔
bool LoadBone_b( char *filename );//載入位元檔
bool SaveBone_b( char *filename );//存入位元檔
void Draw( GLenum mode );
void Destroy( void );
bool flag( void ){ if( Bone ) return true; else return false; }
void AllColor( float r, float g, float b );//設定所有骨骼顏色
void Color( int id, float r, float g, float b );//設定骨骼顏色
void ComputeWPos( void );//算出每個骨骼的世界位置
Vector CameraPoint;
Vector CameraView;
int BoneCount, Selectid;
bool Show; //是否顥示出來
gBone *Bone;
protected:
void DrawSkeleton( gBone *rootBone, GLenum mode );
void BoneBox( gBone *curBone );
void CWPos( gBone *rootBone );//算出每個骨骼的世界位置
};
matrix怎麼算出來的呢?呼叫DrawSkeleton就可得到
void CBone::Draw( GLenum mode )
{
if( !Bone )
return;
glPushMatrix();
glTranslatef(Bone->startpos[0]+Bone->pos[0],
Bone->startpos[1]+Bone->pos[1],
Bone->startpos[2]+Bone->pos[2]);
glRotatef(Bone->rot[2], 0.0f, 0.0f, 1.0f);
glRotatef(Bone->rot[1], 0.0f, 1.0f, 0.0f);
glRotatef(Bone->rot[0], 1.0f, 0.0f, 0.0f);
DrawSkeleton(Bone,mode);
glPopMatrix();
}
DrawSkeleton是個遞迴函式,因為骨頭是一層一層的
void CBone::DrawSkeleton( gBone *rootBone, GLenum mode )
{
int loop;
gBone *curBone;
curBone = rootBone->children;
for (loop = 0; loop < rootBone->childCnt; loop++)
{
glPushMatrix();
glTranslatef(curBone->startpos[0]+curBone->pos[0],
curBone->startpos[1]+curBone->pos[1],
curBone->startpos[2]+curBone->pos[2]);
glRotatef(curBone->rot[2], 0.0f, 0.0f, 1.0f);
glRotatef(curBone->rot[1], 0.0f, 1.0f, 0.0f);
glRotatef(curBone->rot[0], 1.0f, 0.0f, 0.0f);
if( mode == GL_SELECT )
{
if( Show )
{
glLoadName(curBone->id);
BoneBox( curBone );
}
}
else
{
if( Show )
BoneBox( curBone );
}
glGetFloatv(GL_MODELVIEW_MATRIX,curBone->matrix.m);///在這裡取得的矩陣就可以給模型用了
if (curBone->childCnt > 0)
DrawSkeleton( curBone, mode );
glPopMatrix();
curBone++;
}
}
訂閱:
文章 (Atom)