1. 程式人生 > >計算機圖形學:虛擬服裝設計

計算機圖形學:虛擬服裝設計

要求:

1)讀取給定的模型檔案並能夠分別使用線模式、點模式、填充模式進行渲染。

2)對模型進行平移、縮放和旋轉。

3)改變視點,對模型進行三維漫遊。

4)為模型中的衣裙新增物理模型,要求能夠拖動某個節點或面片展示區域性形變效果。

5)為模型中的衣裙新增碰撞檢測,使得衣裙能在重力作用下懸掛在衣架上,以及模擬風力作用下的衣裙飄動效果。


一、實驗環境

1. 作業系統:windows 8.1

2. 程式設計軟體:visual studio 2013

 

二、實驗內容



關鍵程式碼分析

(1)讀取obj模型

void ReadPIC()

 {

int dianshu;

dianshu = 0;

 

ifstream ifs("dress.obj"); //用檔案輸入流讀入檔案

string s;

Mian *f;

POINT3 *v;

FaXiangLiang *vn;

WenLi *vt;

while (getline(ifs, s))  //從標準輸入流中讀取一個字串,儲存到字串string(物件)中

{

if (s.length()<2)continue

;

if (s[0] == 'v')

{

if (s[1] == 't') //vt 紋理 0.001992 0.001992

{

istringstream in(s); //定義一個字串輸入流的物件in,將s中所包含的字串放入in 物件中

    vt = new WenLi();

string head;

in >> head >> vt->TU >> vt->TV;

m_pic.VT.push_back(*vt);

}

else if (s[1] == 'n') //vn 法向量 0.000000 -1.000000 0.000000

{

istringstream in(s);

vn = new FaXiangLiang();

string head;

in >> head >> vn->NX >> vn->NY >> vn->NZ;

m_pic.VN.push_back(*vn);

}

else //v 點 - 0.500000 - 0.500000 0.500000

{

istringstream in(s);

v = new POINT3();

string head;

in >> head >> v->X >> v->Y >> v->Z;

m_pic.V.push_back(*v);

dianshu++;

}

//printf("dianshu=%d",dianshu);

}

else if (s[0] == 'f')//f 面 1/1/1 2/2/2 3/3/3  這個面的頂點、紋理座標、法向量的索引  //f 2443//2656 2442//2656 2444//2656 面

{

for (int k = s.size() - 1; k >= 0; k--)

{

if (s[k] == '/')s[k] = ' ';

}

istringstream in(s);

f = new Mian();

string head;

in >> head;

int i = 0;

while (i<3)

{

if (m_pic.V.size() != 0)

{

in >> f->V[i];

f->V[i] -= 1;

}

if (m_pic.VT.size() != 0)

{

in >> f->T[i];

f->T[i] -= 1;

}

if (m_pic.VN.size() != 0)

{

in >> f->N[i];

f->N[i] -= 1;

}

i++;

}

m_pic.F.push_back(*f);

}

}

}

讀取檔案dress.obj,依據檔案中的索引將資料分別存入法向量m_pic.VN紋理座標m_pic.VT,頂點m_pic.V依據面的索引,法向量紋理座標頂點按所在三角形面分別存入m_pic.F中,方便後面繪製以及變換操作。由於資料量大,讀取檔案函式ReadPIC()設定了標誌位,只在檔案啟動時執行1次。

(2)繪製模型

void InitScene()

{

static GLint flag = 1;//設定標誌 位,第一次讀取obj檔案到陣列,後面直接顯示

if (flag == 1)

{

flag = 0;

ReadPIC();

}

 

glClearColor(1.000f, 1.000f, 1.000f, 1.0f); //Background color

// TODO: Replace the following sample code with your initialization code.

// Activate lighting and a light source

//用於啟用各種功能。具體功能由引數決定。與glDisable相對應。glDisable用以關閉各項功能。

glEnable(GL_LIGHT0);//啟用0號燈到7號燈(光源)  光源要求由函式glLight函式來完成

glEnable(GL_LIGHTING);//啟用燈源

glEnable(GL_DEPTH_TEST);//啟用深度測試。  根據座標的遠近自動隱藏被遮住的圖形(材料)

glEnable(GL_TEXTURE_2D);   // 啟用二維紋理

// Define material parameters

static GLfloat glfMatAmbient[] = { 0.000f, 0.450f, 1.000f, 1.0f };

static GLfloat glfMatDiffuse[] = { 0.000f, 0.000f, 0.580f, 1.0f };

static GLfloat glfMatSpecular[] = { 1.000f, 1.000f, 1.000f, 1.0f };

static GLfloat glfMatEmission[] = { 0.000f, 0.000f, 0.000f, 1.0f };

static GLfloat fShininess = 128.000f;

// Set material parameters

//指定用於光照計算的當前材質屬性。引數face的取值可以是GL_FRONT、GL_BACK或GL_FRONT_AND_BACK,指出材質屬性將應用於物體的哪面。

//void glMaterial{if}(GLenum face, GLenum pname, TYPE param);

glMaterialfv(GL_FRONT, GL_AMBIENT, glfMatAmbient);

glMaterialfv(GL_FRONT, GL_DIFFUSE, glfMatDiffuse);

glMaterialfv(GL_FRONT, GL_SPECULAR, glfMatSpecular);

glMaterialfv(GL_FRONT, GL_EMISSION, glfMatEmission);

glMaterialf(GL_FRONT, GL_SHININESS, fShininess);

}

 

void DrawScene()

 {

// TODO: Replace the following sample code with your code to draw the scene.

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // 清除螢幕及深度快取

glLoadIdentity(); // 重置模型觀察矩陣

 

gluLookAt(viewer[0], viewer[1], viewer[2], 0.0f, -4.0f, -9.0f, 0.0, 1.0, 0.0);

 

glTranslatef(0.0f, -13.0f, -8.0f); // 移入螢幕 5.0

 

if (trackballMove&&translating&&!scaling&&!rotating)

{

glTranslatef(tran[0], tran[1], tran[2]);

//printf("tran[0]=%f, tran[1]=%f, tran[2]=%f\n", tran[0], tran[1], tran[2]);

}

if (trackballMove&&!translating&&scaling&&!rotating)

{

glScalef(scale[0], scale[1], scale[2]);

}

if (trackballMove&&!translating&&!scaling&&rotating)

{

glRotatef(angle0, axis[0], axis[1], axis[2]);//旋轉(角度,軸)

}

GLCube();// Draw a cube

glFlush();

}

 

void GLCube()

{

if (dian_model&&!xian_model&&!mian_model)

//if (0)

{

for (int i = 0; i < (m_pic.F.size()); i++)

//for (int i = 0; i<7959; i++)

{

glBegin(GL_POINTS);//點模式

if (qizhi0 == 1)

{

printf("dianmoshi");

qizhi0 = 0;

}

/*glVertex3f(m_pic.V[m_pic.F[3 * i].V[0]].X / YU, m_pic.V[m_pic.F[3 * i].V[0]].Y / YU, m_pic.V[m_pic.F[3 * i].V[0]].Z / YU);

glVertex3f(m_pic.V[m_pic.F[3 * i].V[1]].X / YU, m_pic.V[m_pic.F[3 * i].V[1]].Y / YU, m_pic.V[m_pic.F[3 * i].V[1]].Z / YU);

glVertex3f(m_pic.V[m_pic.F[3 * i].V[2]].X / YU, m_pic.V[m_pic.F[3 * i].V[2]].Y / YU, m_pic.V[m_pic.F[3 * i].V[2]].Z / YU);

*/

 

glVertex3f(m_pic.V[m_pic.F[i].V[0]].X / YU, m_pic.V[m_pic.F[i].V[0]].Y / YU, m_pic.V[m_pic.F[i].V[0]].Z / YU);

glVertex3f(m_pic.V[m_pic.F[i].V[1]].X / YU, m_pic.V[m_pic.F[i].V[1]].Y / YU, m_pic.V[m_pic.F[i].V[1]].Z / YU);

glVertex3f(m_pic.V[m_pic.F[i].V[2]].X / YU, m_pic.V[m_pic.F[i].V[2]].Y / YU, m_pic.V[m_pic.F[i].V[2]].Z / YU);

 

//glVertex3f(10*(model.vertices[3 * i]), 10*(model.vertices[3 * i + 1]), 10*(model.vertices[3 * i + 2]));

glEnd();

}

}

if (!dian_model&&xian_model&&!mian_model)

//if (0)

{

for (int i = 0; i<(m_pic.F.size()); i++)

{

glBegin(GL_LINES);//線模式

if (qizhi1 == 1)

{

printf("xianmoshi");

qizhi1 = 0;

}

glVertex3f(m_pic.V[m_pic.F[i].V[0]].X / YU, m_pic.V[m_pic.F[i].V[0]].Y / YU, m_pic.V[m_pic.F[i].V[0]].Z / YU);

glVertex3f(m_pic.V[m_pic.F[i].V[1]].X / YU, m_pic.V[m_pic.F[i].V[1]].Y / YU, m_pic.V[m_pic.F[i].V[1]].Z / YU);

//glVertex3f(m_pic.V[m_pic.F[i].V[2]].X / YU, m_pic.V[m_pic.F[i].V[2]].Y / YU, m_pic.V[m_pic.F[i].V[2]].Z / YU);

glEnd();

glBegin(GL_LINES);

//glVertex3f(m_pic.V[m_pic.F[i].V[0]].X / YU, m_pic.V[m_pic.F[i].V[0]].Y / YU, m_pic.V[m_pic.F[i].V[0]].Z / YU);

glVertex3f(m_pic.V[m_pic.F[i].V[1]].X / YU, m_pic.V[m_pic.F[i].V[1]].Y / YU, m_pic.V[m_pic.F[i].V[1]].Z / YU);

glVertex3f(m_pic.V[m_pic.F[i].V[2]].X / YU, m_pic.V[m_pic.F[i].V[2]].Y / YU, m_pic.V[m_pic.F[i].V[2]].Z / YU);

glEnd();

glBegin(GL_LINES);

glVertex3f(m_pic.V[m_pic.F[i].V[0]].X / YU, m_pic.V[m_pic.F[i].V[0]].Y / YU, m_pic.V[m_pic.F[i].V[0]].Z / YU);

//glVertex3f(m_pic.V[m_pic.F[i].V[1]].X / YU, m_pic.V[m_pic.F[i].V[1]].Y / YU, m_pic.V[m_pic.F[i].V[1]].Z / YU);

glVertex3f(m_pic.V[m_pic.F[i].V[2]].X / YU, m_pic.V[m_pic.F[i].V[2]].Y / YU, m_pic.V[m_pic.F[i].V[2]].Z / YU);

glEnd();

}

}

if (!dian_model&&!xian_model&&mian_model)

//if (1)

{

for (int i = 0; i<(m_pic.F.size()); i++)

{

//printf("m_pic.F.size()=%d", m_pic.F.size());//16213

glBegin(GL_TRIANGLES);//面模式// 繪製三角形

if (qizhi2 == 1)

{

printf("mianmoshi");

qizhi2 = 0;

}

if (m_pic.VT.size() != 0)glTexCoord2f(m_pic.VT[m_pic.F[i].T[0]].TU, m_pic.VT[m_pic.F[i].T[0]].TV);  //紋理

if (m_pic.VN.size() != 0)glNormal3f(m_pic.VN[m_pic.F[i].N[0]].NX, m_pic.VN[m_pic.F[i].N[0]].NY, m_pic.VN[m_pic.F[i].N[0]].NZ);//法向量

glVertex3f(m_pic.V[m_pic.F[i].V[0]].X / YU, m_pic.V[m_pic.F[i].V[0]].Y / YU, m_pic.V[m_pic.F[i].V[0]].Z / YU); // 上頂點

//printf("dian:%f,%f,%f\n",m_pic.V[m_pic.F[i].V[0]].X / YU, m_pic.V[m_pic.F[i].V[0]].Y / YU, m_pic.V[m_pic.F[i].V[0]].Z / YU);

if (m_pic.VT.size() != 0)glTexCoord2f(m_pic.VT[m_pic.F[i].T[1]].TU, m_pic.VT[m_pic.F[i].T[1]].TV);  //紋理

if (m_pic.VN.size() != 0)glNormal3f(m_pic.VN[m_pic.F[i].N[1]].NX, m_pic.VN[m_pic.F[i].N[1]].NY, m_pic.VN[m_pic.F[i].N[1]].NZ);//法向量

glVertex3f(m_pic.V[m_pic.F[i].V[1]].X / YU, m_pic.V[m_pic.F[i].V[1]].Y / YU, m_pic.V[m_pic.F[i].V[1]].Z / YU); // 左下

if (m_pic.VT.size() != 0)glTexCoord2f(m_pic.VT[m_pic.F[i].T[2]].TU, m_pic.VT[m_pic.F[i].T[2]].TV);  //紋理

if (m_pic.VN.size() != 0)glNormal3f(m_pic.VN[m_pic.F[i].N[2]].NX, m_pic.VN[m_pic.F[i].N[2]].NY, m_pic.VN[m_pic.F[i].N[2]].NZ);//法向量

glVertex3f(m_pic.V[m_pic.F[i].V[2]].X / YU, m_pic.V[m_pic.F[i].V[2]].Y / YU, m_pic.V[m_pic.F[i].V[2]].Z / YU); // 右下

glEnd(); // 三角形繪製結束

}

}

}

InitScene()函式中設定了場景的光源和模型的材質。DrawScene()中繪製模型,呼叫函式GLCube()實現具體繪製,並由標誌位設定繪製模式:點模式,線模式和麵模式;同時使用庫函式實現模型旋轉縮放平移變換操作,具體引數由虛擬球設定;同時gluLookAt(viewer[0], viewer[1], viewer[2], 0.0f, -4.0f, -9.0f, 0.0, 1.0, 0.0);函式實現三維漫遊,viewer[0], viewer[1], viewer[2]數值由鍵盤設定,後面的視點方向等用於使模型位於世界座標系正中間。

(3)物理模型

Cloth::Cloth(GLMmodel *model)

{

//

SpringConstant = 1000;//彈力

DampingFactor = 10;//阻尼

density = 1.2;//密度

drag = 0.4;//阻力

 

//set vert

Myvertex vert;

verts_.push_back(vert);

for (int i = 1; i <= 7959; i++) // m_pic.V[m_pic.F[i].V[2]].X

{

//printf("%d\n", m_pic.V.size());//7959

vert.id_ = i;

vert.position_ = point(model->vertices[3 * i], model->vertices[3 * i + 1], model->vertices[3 * i + 2]);//point: vec

//printf("[1]=%lf\n", model->vertices[3 * i]);

//printf("[2]=%lf\n", model->vertices[3 * i+1]);

//printf("[3]=%lf\n", model->vertices[3 * i+2]);

//vert.texCoord_ = Vec2f(model->)

verts_.push_back(vert);

}

 

 

//calculate hanger_aabb 衣架aabb包圍盒

for (int i = 3381; i <= model->numvertices; i++)

{

if (model->vertices[3 * i] > hanger_aabb.max_x)

{

hanger_aabb.max_x = model->vertices[3 * i];

}

if (model->vertices[3 * i] < hanger_aabb.min_x)

{

hanger_aabb.min_x = model->vertices[3 * i];

}

if (model->vertices[3 * i + 1] > hanger_aabb.max_y)

{

hanger_aabb.max_y = model->vertices[3 * i + 1];

}

if (model->vertices[3 * i + 1] < hanger_aabb.min_y)

{

hanger_aabb.min_y = model->vertices[3 * i + 1];

}

if (model->vertices[3 * i + 2] > hanger_aabb.max_z)

{

hanger_aabb.max_z = model->vertices[3 * i + 2];

}

if (model->vertices[3 * i + 2] < hanger_aabb.min_z)

{

hanger_aabb.min_z = model->vertices[3 * i + 2];

}

}

 

update_aabb(); //calculate_cloth_aabb

 

for (int i = 1; i <= model->numvertices; i++) //if points in hanger_aabb,point is static

{

if (p_in_aabb(verts_[i].position_))

{

verts_[i].is_fixed = true;

}

else

verts_[i].is_fixed = false;

}

 

//set face

Myface face;

for (int i = 0; i < model->numtriangles; i++)

{

face.id_ = i;

int nid = model->triangles[i].findex;

face.verId = ivec3(model->triangles[i].vindices[0], model->triangles[i].vindices[1], model->triangles[i].vindices[2]);

face.normal_ = Vec3f(model->facetnorms[nid * 3], model->facetnorms[nid * 3 + 1], model->facetnorms[nid * 3 + 2]);

for (int j = 0; j < 3; j++)

{

int tid = model->triangles[i].tindices[j];

face.texCoord_[j] = Vec2f(model->texcoords[tid * 2], model->texcoords[2 * tid + 1]);

}

int id[3];

for (int j = 0; j < 3; j++)

{

id[j] = face.verId[j];

face.vertex3[j] = &verts_[id[j]];

}

face.s = fabs(((verts_[id[1]].position_ - verts_[id[0]].position_)CROSS(verts_[id[2]].position_ - verts_[id[0]].position_)).length() / 2.0);

faces_.push_back(face);

 

}

 

//delete some bad faces

for (int i = 0; i < 6546; i++)

{

if ((faces_[i].normal_[0] * faces_[i].vertex3[0]->position_[0] + faces_[i].normal_[2] * faces_[i].vertex3[0]->position_[2]) < -0.05)

{

faces_[i].badface = true;

}

}

 

 

 

//delete some bad verts,and find bound

for (int i = 0; i < 6546; i++)

{

if (faces_[i].badface)

{

for (int j = 0; j < 3; j++)

{

faces_[i].vertex3[j]->kengdie = true;

faces_[i].vertex3[j]->is_bound = true;

}

 

}

}

for (int i = 0; i < 6546; i++)

{

if (!faces_[i].badface)

{

for (int j = 0; j < 3; j++)

{

faces_[i].vertex3[j]->kengdie = false;

}

}

}

 

 

 

set_neighbor();

set_weight();

//Update(float deltatime);

 

}

}

服裝模型類,設定了服裝的物理模型,為服裝添加了SpringConstant彈力DampingFactor阻尼density密度drag 阻力屬性;分別找到衣架和服裝的頂點取值範圍,確定衣架和服裝的包圍盒;形變是針對服裝模型的三角形面片作變化,將模型的基本資料儲存到face中;由於原模型中裙襬雙層布料,碰撞檢測的效果不好,故刪去裙襬內襯,即badface。

 

 

4)碰撞檢測

static void idle() {

if (phy_){ if (loop < 16){ Update(); loop++; } else loop = 0; }

}

 

void keys(unsigned char key, int x, int y)

{

/* Use x, X, y, Y, z, and Z keys to move viewer */

if (key == 'x') viewer[0] -= 1.0;

if (key == 'X') viewer[0] += 1.0;

if (key == 'y') viewer[1] -= 1.0;

if (key == 'Y') viewer[1] += 1.0;

if (key == 'z') viewer[2] -= 1.0;

if (key == 'Z') viewer[2] += 1.0;

//display();

if (!phy_){

DrawScene();

}

 

if (key == 'p'){

phy_ = true; printf("phy_=true\n");

}

 

if (key == 'o'){

wind.x += 0.5;

wind.Print("New Wind:");

}

if (key == 'i'){

wind.y += 0.5;

wind.Print("New Wind:");

}

if (key == 'u'){

wind.z += 0.5;

wind.Print("New Wind:");

}

}

 

void Cloth::Update(float deltatime)

{

//set gravity

for (int i = 1; i < verts_.size(); i++)

{

verts_[i].applyForce(Vec3f(0, -0.1, 0)*verts_[i].weight);

//verts_[i].applyForce(Vec3f(0, 0, 0.01));

//verts_[i].Update(deltatime);

}

 

 

change_wind();

 

//set wind

for (int i = 0; i < faces_.size(); i++)

{

faces_[i].updateface();

}

 

 

//set  spring

for (int i = 0; i < springDampers.size(); i++)

{

springDampers[i].CalculateForces();

}

 

collision_detection();//碰撞檢測

 

//update verts

for (int i = 1; i < verts_.size(); i++)

{

verts_[i].Update(deltatime);

}

 

//update normals

update_normal();

}

 

void Cloth::change_wind()

{

for (int i = 0; i < 6546; i++)

{

faces_[i].Changewind(wind);

}

}

 

void Cloth::update_normal()

{

for (int i = 0; i < faces_.size(); i++)

{

Vec3f p = verts_[faces_[i].verId[0]].position_;

Vec3f q = verts_[faces_[i].verId[1]].position_;

Vec3f r = verts_[faces_[i].verId[2]].position_;

Vec3f normal_update = ((p - r) CROSS(q - r));

normal_update.normalize();

 

//normal is  continuous variable

 

if (normal_update DOT faces_[i].normal_>0)

{

faces_[i].normal_ = normal_update;

 

}

else

{

faces_[i].normal_ = -normal_update;

}

}

}

 

void Cloth::set_neighbor()

{

for (int i = 0; i < faces_.size(); i++)

{

if (!faces_[i].badface)

{

int vid1;

int vid2;

for (int j = 0; j < 3; j++)

{

vid1 = faces_[i].verId[j];

vid2 = faces_[i].verId[(j + 1) % 3];

verts_[vid1].neighborIdx.push_back(vid2);

float dis;

dis = (verts_[vid1].position_ - verts_[vid2].position_).length();

verts_[vid1].nei_dis.push_back(dis);

verts_[vid1].neighborfaceId.push_back(i);

if (verts_[vid1].is_bound&&verts_[vid2].is_bound)

{

verts_[vid2].neighborIdx.push_back(vid1);

verts_[vid2].nei_dis.push_back(dis);

}

}

 

}

}

 

for (int i = 1; i < verts_.size(); i++)

{

verts_[i].degree_ = verts_[i].neighborIdx.size();

}

 

for (int i = 0; i < faces_.size(); i++)

{

if (!faces_[i].badface)

{

int vid1;

int vid2;

for (int j = 0; j < 3; j++)

{

vid1 = faces_[i].verId[j];

vid2 = faces_[i].verId[(j + 1) % 3];

springDampers.push_back(springDamper(&verts_[vid1], &verts_[vid2], SpringConstant, DampingFactor));//彈簧阻尼

 

}

}

}

 

}

 

void Cloth::collision_detection()

{

update_aabb();

for (int i = 0; i < 40; i++)

for (int j = 0; j < 40; j++)

for (int k = 0; k < 40; k++)

{

voxels[i][j][k].clear();

}

 

 

for (int i = 0; i < 6546; i++)

{

faces_[i].voxel_pos.clear();

}

for (int i = 0; i < 6546; i++)

{

if (!faces_[i].badface)

{

aabb ab_ = faces_[i].get_aabb();

int l = floor((ab_.min_x - cloth_aabb.min_x) / (cloth_aabb.max_x - cloth_aabb.min_x)*40.f);

int m = floor((ab_.min_y - cloth_aabb.min_y) / (cloth_aabb.max_y - cloth_aabb.min_y)*40.f);

int n = floor((ab_.min_z - cloth_aabb.min_z) / (cloth_aabb.max_z - cloth_aabb.min_z)*40.f);

if (l < 0)

l = 0;

if (m < 0)

m = 0;

if (n < 0)

n = 0;

voxels[l][m][n].push_back(i);

faces_[i].voxel_pos = ivec3(l, m, n);

}

}

 

for (int i = 0; i < 6546; i++)

{

ivec3 voxel = faces_[i].voxel_pos;

for (int j = 0; j < voxels[voxel[0]][voxel[1]][voxel[2]].size(); j++)

{

int face_id = voxels[voxel[0]][voxel[1]][voxel[2]][j];

bool b = tri_collision_detection(i, face_id);

}

}

/*for (int i = 0; i < 6546; i++)

for (int j = 0; j < 6546; j++)

{

tri_collision_detection(i, j);

}*/

 

}

 

bool Cloth::tri_collision_detection(int id1, int id2)

{

if ((faces_[id1].normal_ DOT faces_[id2].normal_)>0)

return false;

if (faces_[id1].badface || faces_[id2].badface)

return false;

Vec3f dis(0, 0, 0);

for (int i = 0; i < 3; i++)

{

dis += (faces_[id1].vertex3[i]->position_ - faces_[id2].vertex3[i]->position_) / 3.0f;

}

if (dis.length() > 0.001)

return false;

 

else

{

Vec3f n = Vec3f(0, 0, 0);

 

for (int i = 0; i < 3; i++)

{

n = (faces_[id2].normal_ DOT(faces_[id1].vertex3[i]->position_ - faces_[id2].vertex3[1]->position_))*faces_[id2].normal_;

if (n.length() < 0.01)

{

n.normalize();

if (n DOT faces_[id1].vertex3[i]->velocity < 0)

{

Vec3f vv = Vec3f(0, 0, 0);

vv = (n DOT faces_[id1].vertex3[i]->velocity)*-1.1f*n;

faces_[id1].vertex3[i]->velocity += vv;

/*for (int j = 0; j < 3; j++)

{

faces_[id2].vertex3[j]->velocity += vv / -1.1f  / 3.0f;

}*/

//faces_[id1].vertex3[i]->velocity = Vec3f(0, faces_[id1].vertex3[i]->velocity[1], 0);

 

}

}

}

return true;

}

 

}

 

由鍵盤設定是否開啟碰撞檢測,按下’p’鍵即開啟碰撞檢測,風力大小也由鍵盤設定。碰撞檢測具體實現流程見上述程式碼。