代码大体与http://bbezxcy.iteye.com/blog/2204322相同,修改了部分不稳定的bug,增加了椭球碰撞以及旋转观察的实现
?
#ifndef GLUT_DISABLE_ATEXIT_HACK
#define GLUT_DISABLE_ATEXIT_HACK
#endif
#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/wglew.h>
#include <GL/freeglut.h>
#include <vector>
#include<cstring>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> //for matrices
#include <glm/gtc/type_ptr.hpp>
//undefine if u want to use the default bending constraint of pbd
#include<iostream>
using namespace std;
//using namespace glm;
GLfloat rtx = 0.0f, rty = 0.0f, rtz = 0.0;
glm::vec3 Up=glm::vec3(0,1,0), Right, viewDir;
const int GRID_SIZE=10; //地板砖边长
GLdouble MV[16];
GLint viewport[4];
GLdouble PP[16];
bool isfix[1000];
int dist = -23;
//椭球参数
int iStacks = 30;
int iSlices = 30;
float fRadius = 1;
float radius = 1; //object space radius of ellipsoid
//float exp1 = 1e-3;
const int numX = 20, numY=20; //一行有numx+1个点
const int total_points = (numX+1)*(numY+1); //总点数
//布料顶点位置 速度
glm::vec3 Pos[total_points];
glm::vec3 Veloc[total_points];
glm::vec3 force[total_points];
glm::mat4 ellipsoid,invreseEllipsoid;
int size = 4;
float hsize = size/2.0f;
const float frameTime = 1.0f/60.0f;
const float mass = 1.0/total_points;
const float globalDamp = 0.98; //速度衰减参数
const glm::vec3 gvat = glm::vec3(0,-9.8,0); //重力加速度
const float Spring_K = 2.5; //弹性系数
const float len0 = 4.0/numX; //单边长度
const float tolera = 1.08; //弹性限度
float fuck;//球体运动
//视角问题
int oldX=0, oldY=0;
const int width = 1024, height = 1024;
GLdouble P[16];
int selected_index = -1;
int state =1 ;
float rX=15, rY=0;
void initGL()
{
//初始化顶点位置
memset(Pos,0,sizeof(Pos));
memset(Veloc,0,sizeof(Veloc));
memset(force,0,sizeof(force));
//fill in positions
int count1 = 0;
int u = numX + 1;
int v = numY + 1;
for(int j=0;j<=numY;j++) {
for(int i=0;i<=numX;i++) {
Pos[count1++] = glm::vec3( ((float(i)/(u-1)) *2-1)* hsize, size+1, ((float(j)/(v-1) )* size));
printf("(%.1lf ,%.1lf)",((float(i)/(u-1)) *2-1)* hsize,((float(j)/(v-1) )* size));
}printf("\n");
//悬挂点为X[0] 和 X[numX]
}
memset(isfix,0,sizeof(isfix));
isfix[0] = isfix[numX] = 1;
fuck = 0;
}
void DrawEllipsoid(){//画绿色椭球
//设置椭球
ellipsoid = glm::translate(glm::mat4(1),glm::vec3(0,fuck,0));
fuck += 0.01;
if(fuck>=4.0)fuck = -1;
ellipsoid = glm::rotate(ellipsoid, 45.0f ,glm::vec3(1,0,0));
ellipsoid = glm::scale(ellipsoid, glm::vec3(fRadius,fRadius,fRadius/2));
invreseEllipsoid = glm::inverse(ellipsoid);
fuck +=0.005;
//画出椭球
glColor3f(0,1,0);
glPushMatrix();
glMultMatrixf(glm::value_ptr(ellipsoid));
//半径,经线条数,维线条数
glutWireSphere(fRadius, iSlices, iStacks);
glPopMatrix();
}
void DrawGrid() //画地板
{
glBegin(GL_LINES);
glColor3f(0.5f, 0.5f, 0.5f);
for(int i=-GRID_SIZE;i<=GRID_SIZE;i++)
{
glVertex3f((float)i,0,(float)-GRID_SIZE);
glVertex3f((float)i,0,(float)GRID_SIZE);
glVertex3f((float)-GRID_SIZE,0,(float)i);
glVertex3f((float)GRID_SIZE,0,(float)i);
}
glEnd();
}
void drawTextile(){ //画布料
//draw polygons
int k = 0;
glBegin(GL_LINES);
glColor3f(1,1,1);
for(int i = 0;i <= numX;i ++){
for(int j = 0;j <= numY;j ++){
// cout<<i<<" "<<j<<";";
if(j != numX){
glm::vec3 p1 = Pos[k];
glm::vec3 p2 = Pos[k+1];
glVertex3f(p1.x,p1.y,p1.z);
glVertex3f(p2.x,p2.y,p2.z);
// printf("add %d %d\n",k,k+1);
}
if(i != numY){
glm::vec3 p1 = Pos[k];
glm::vec3 p2 = Pos[k+numX+1];
glVertex3f(p1.x,p1.y,p1.z);
glVertex3f(p2.x,p2.y,p2.z);
}
k++;
}
// cout<<endl;
}
glEnd();
glPointSize(3);
glBegin(GL_POINTS);
glColor3f(1,0,0);
for(size_t i = 0;i < total_points;i ++){
glm::vec3 p = Pos[i];
glVertex3f(p.x,p.y,p.z);
}
glEnd();
}
void OnRender(void)
{
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//设置视角
glTranslatef(0,0,dist);
// glRotatef(15,1,0,0);
glRotatef(rX,1,0,0);
glRotatef(rY,0,1,0);
glGetDoublev(GL_MODELVIEW_MATRIX, MV);
viewDir.x = (float)-MV[2];
viewDir.y = (float)-MV[6];
viewDir.z = (float)-MV[10];
Right = glm::cross(viewDir, Up);
//做出地面
DrawGrid();
drawTextile();
DrawEllipsoid();
// drawblock();
glutSwapBuffers();
}
//求出b点对a点的作用力
glm::vec3 SpringForce(int a, int b, int is){
float inilen;
if(is == 1)inilen = len0;
if(is == 2) inilen = len0 * 2;
if(is == 3) inilen = len0 * 1.414213;
glm::vec3 res = glm::vec3(0);
glm::vec3 tmp = Pos[b] - Pos[a];
float dis = glm::length(tmp);
res = tmp/dis;
res *= (dis - inilen);
res *= Spring_K;
return res;
}
void ComputeForces(){
//重力
for(size_t i=0;i<total_points;i++) {
force[i] = glm::vec3(0);
if(!isfix[i])
force[i] += mass * gvat;
}
int i,j,k = 0;
//结构弹簧 上下左右
for(i = 0;i <= numY;i++){
for(j = 0;j <= numX;j ++){
if(i!=0){//上
force[k] += SpringForce(k, k - numX - 1, 1);
}
if(j!=numX){//右
force[k] += SpringForce(k, k+1, 1);
}
if(i!=numY){//下
force[k] += SpringForce(k, k + numX + 1, 1);
}
if(j!=0){//左
force[k] += SpringForce(k, k - 1, 1);
}
k++;
}
}
//柔性弹簧
k = 0;
for(i = 0;i <= numY;i++){
for(j = 0;j <= numX;j ++){
if(i>1){//上
force[k] += SpringForce(k, k - 2*numX - 2, 2);
}
if(j<numX-1){//右
force[k] += SpringForce(k, k+2, 2);
}
if(i<numY-1){//下
force[k] += SpringForce(k, k + 2*numX + 2, 2);
}
if(j>1){//左
force[k] += SpringForce(k, k - 2, 2);
}
k++;
}
}
//剪切弹簧
k = 0;
for(i = 0;i <= numY;i ++){
for(j = 0;j <= numX;j ++){
if(i>0&&j>0){ //左上
force[k] += SpringForce(k, k - numX - 2, 3);
}
if(i>0&&j<numX){ //右上
force[k] += SpringForce(k, k - numX, 3);
}
if(i<numY&&j<numX){ //右下
force[k] += SpringForce(k, k + numX + 2, 3);
}
if(i<numY&&j>0){ //坐下
force[k] += SpringForce(k, k + numX, 3);
}
k ++;
}
}
}
void EllipsoidCollision() { //检测与处理布料和椭球之间的碰撞
for(size_t i=0;i<total_points;i++) {
glm::vec3 tPos(Pos[i]);
glm::vec4 X_0 = (invreseEllipsoid*glm::vec4(tPos,1));
glm::vec3 delta0 = glm::vec3(X_0.x, X_0.y, X_0.z);
float distance = glm::length(delta0);
if (distance < 1.0f) {
delta0 = (radius - distance) * delta0 / distance;
// Transform the delta back to original space
glm::vec3 delta;
glm::vec3 transformInv;
transformInv = glm::vec3(ellipsoid[0].x, ellipsoid[1].x, ellipsoid[2].x);
transformInv /= glm::dot(transformInv, transformInv);
delta.x = glm::dot(delta0, transformInv);
transformInv = glm::vec3(ellipsoid[0].y, ellipsoid[1].y, ellipsoid[2].y);
transformInv /= glm::dot(transformInv, transformInv);
delta.y = glm::dot(delta0, transformInv);
transformInv = glm::vec3(ellipsoid[0].z, ellipsoid[1].z, ellipsoid[2].z);
transformInv /= glm::dot(transformInv, transformInv);
delta.z = glm::dot(delta0, transformInv);
tPos += delta ;
Veloc[i] += (tPos - Pos[i])/frameTime;
Veloc[i] *= globalDamp;
Pos[i] = tPos;
}
}
}
void CalcPos(){ //计算新的位置
// frameTime/=1000;
// printf("%.3lf\n",frameTime);
glm::vec3 acc = glm::vec3(0);
//得到的frame就是间隔时间 毫秒
for(size_t i = 0;i < total_points;i ++){
if(isfix[i])continue;
acc = force[i] / mass; //得到加速度向量
Veloc[i] = Veloc[i] + acc*frameTime; //得到新的速度值
Veloc[i] *= globalDamp;
Pos[i] = Pos[i] + Veloc[i] * frameTime;
}
}
void StepPhysics(){
ComputeForces();
CalcPos();
EllipsoidCollision();
glutPostRedisplay();
Sleep(5);
}
void OnReshape(int nw, int nh) {
glViewport(0,0,nw, nh);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (GLfloat)nw / (GLfloat)nh, 1.f, 100.0f);
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_PROJECTION_MATRIX, PP);
glMatrixMode(GL_MODELVIEW);
}
void OnMouseDown(int button, int s, int x, int y)
{
if (s == GLUT_DOWN)
{
oldX = x;
oldY = y;
int window_y = (height - y);
float norm_y = float(window_y)/float(height/2.0);
int window_x = x ;
float norm_x = float(window_x)/float(width/2.0);
float winZ=0;
glReadPixels( x, height-y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
if(winZ==1)
winZ=0;
double objX=0, objY=0, objZ=0;
gluUnProject(window_x,window_y, winZ, MV, P, viewport, &objX, &objY, &objZ);
glm::vec3 pt(objX,objY, objZ);
size_t i=0;
for(i=0;i<total_points;i++) {
if( glm::distance(Pos[i],pt)<0.1) {
selected_index = i;
printf("Intersected at %d\n",i);
break;
}
}
}
if(button == GLUT_MIDDLE_BUTTON)
state = 0;
else
state = 1;
if(s==GLUT_UP) {
selected_index= -1;
glutSetCursor(GLUT_CURSOR_INHERIT);
}
}
void OnMouseMove(int x, int y)
{
if(selected_index == -1) {
if (state == 0)
dist *= (1 + (y - oldY)/60.0f);
else
{
rY += (x - oldX)/5.0f;
rX += (y - oldY)/5.0f;
}
} else {
float delta = 1500/abs(dist);
float valX = (x - oldX)/delta;
float valY = (oldY - y)/delta;
if(abs(valX)>abs(valY))
glutSetCursor(GLUT_CURSOR_LEFT_RIGHT);
else
glutSetCursor(GLUT_CURSOR_UP_DOWN);
Veloc[selected_index] = glm::vec3(0);
Pos[selected_index].x += Right[0]*valX ;
float newValue = Pos[selected_index].y+Up[1]*valY;
if(newValue>0)
Pos[selected_index].y = newValue;
Pos[selected_index].z += Right[2]*valX + Up[2]*valY;
}
oldX = x;
oldY = y;
glutPostRedisplay();
}
int main(int argc, char * argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(1024, 1024);
glutCreateWindow("Mass-Spring Model");
initGL();
glutDisplayFunc(OnRender);
//指定窗口形状变化时的回调函数
glutReshapeFunc(OnReshape);
//指定程序空闲时调用函数
glutIdleFunc(StepPhysics);
glEnable(GL_DEPTH_TEST);
glutMouseFunc(OnMouseDown);
glutMotionFunc(OnMouseMove);
glutMainLoop();
return 0;
}
?
[opengl]弹簧质点法模拟柔性布料以及椭球碰撞的opengl实现
原文:http://bbezxcy.iteye.com/blog/2214558