📄 physenv.cpp
字号:
///////////////////////////////////////////////////////////////////////////////
//
// PhysEnv.cpp : Physical World implementation file
//
// Purpose: Implementation of Particle Physics System
//
// Created:
// JL 2/10/99 Modified from Mass-Spring Particle demo to handle cloth
// Modified:
// JL 3/6/99 - FIXED GRAVITY FORCE CALCULATION BUG
// JL 3/8/99 - ADDED MORE POSSIBLE CONTACTS AS EACH VERTEX CAN CONTACT MORE
// THEN ONE COLLISION SURFACE (SHOULD IT BE DYNAMICALLY ALLOC'ED?)
// JL 3/20/99 - ADDED THE MIDPOINT AND RK INTEGRATOR NEEDED TO ALLOC 5 TEMP PARTICLE ARRAYS
//
// Notes: A bit of this along with the organization comes from Chris Hecker's
// Physics Articles from last year www.d6.com. Hopefully this will get
// everyone back up to speed before we dig deeper into the world of Dynamics.
///////////////////////////////////////////////////////////////////////////////
//
// Copyright 1998-1999 Jeff Lander, All Rights Reserved.
// For educational purposes only.
// Please do not republish in electronic or print form without permission
// Thanks - jeffl@darwin3d.com
//
///////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <assert.h>
#include <math.h>
#include "ClothSimulation.h"
#include "PhysEnv.h"
#include "DlgSimProp.h"
#include "DlgVertexMass.h"
#include "DlgAddSphere.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define OGL_AXIS_DLIST 1 // OPENGL显示列表ID
#pragma warning (disable:4244)
/////////////////////////////////////////////////////////////////////////////
// CPhysEnv
// 初始化仿真环境函数
CPhysEnv::CPhysEnv()
{
m_IntegratorType = EULER_INTEGRATOR;
m_Pick[0] = -1;
m_Pick[1] = -1;
m_ParticleSys[0] = NULL;
m_ParticleSys[1] = NULL;
m_ParticleSys[2] = NULL;
for (int i = 0; i < 5; i++)
m_TempSys[i] = NULL;
m_ParticleCnt = 0;
m_Contact = NULL;
m_Spring = NULL;
m_SpringCnt = 0;
m_MouseForceActive = FALSE;
m_UseGravity = TRUE;
m_DrawSprings = TRUE;
m_DrawStructural = TRUE; // 缺省状态下绘制结构弹簧
m_DrawBend = FALSE;
m_DrawShear = FALSE;
m_DrawVertices = TRUE;
m_CollisionActive = TRUE;
m_CollisionRootFinding = FALSE;
MAKEVECTOR(m_Gravity, 0.0f, -0.2f, 0.0f)
m_UserForceMag = 100.0;
m_UserForceActive = FALSE;
m_MouseForceKs = 2.0f;
m_Kd = 0.04f; // 阻尼因子
m_Kr = 0.1f;
m_Ksh = 5.0f; // HOOK弹簧常数
m_Ksd = 0.1f; // 弹簧阻尼常数
m_WorldSizeX = 15.0f;
m_WorldSizeY = 15.0f;
m_WorldSizeZ = 15.0f;
m_CollisionPlane = (tCollisionPlane *)malloc(sizeof(tCollisionPlane) * 6);
m_CollisionPlaneCnt = 6;
// 碰撞平面(上)
MAKEVECTOR(m_CollisionPlane[0].normal,0.0f, -1.0f, 0.0f)
m_CollisionPlane[0].d = m_WorldSizeY / 2.0f;
// 碰撞平面(下)
MAKEVECTOR(m_CollisionPlane[1].normal,0.0f, 1.0f, 0.0f)
m_CollisionPlane[1].d = m_WorldSizeY / 2.0f;
// 碰撞平面(左)
MAKEVECTOR(m_CollisionPlane[2].normal,-1.0f, 0.0f, 0.0f)
m_CollisionPlane[2].d = m_WorldSizeX / 2.0f;
// 碰撞平面(右)
MAKEVECTOR(m_CollisionPlane[3].normal,1.0f, 0.0f, 0.0f)
m_CollisionPlane[3].d = m_WorldSizeX / 2.0f;
// 碰撞平面(前)
MAKEVECTOR(m_CollisionPlane[4].normal,0.0f, 0.0f, -1.0f)
m_CollisionPlane[4].d = m_WorldSizeZ / 2.0f;
// 碰撞平面(后)
MAKEVECTOR(m_CollisionPlane[5].normal,0.0f, 0.0f, 1.0f)
m_CollisionPlane[5].d = m_WorldSizeZ / 2.0f;
m_SphereCnt = 0;
}
CPhysEnv::~CPhysEnv()
{
if (m_ParticleSys[0])
free(m_ParticleSys[0]);
if (m_ParticleSys[1])
free(m_ParticleSys[1]);
if (m_ParticleSys[2])
free(m_ParticleSys[2]);
for (int i = 0; i < 5; i++)
{
if (m_TempSys[i])
free(m_TempSys[i]);
}
if (m_Contact)
free(m_Contact);
free(m_CollisionPlane);
free(m_Spring);
free(m_Sphere);
}
void CPhysEnv::RenderWorld()
{
tParticle *tempParticle;
tSpring *tempSpring;
glColor3f(1.0f,1.0f,1.0f);
glBegin(GL_LINE_STRIP);
glVertex3f(-m_WorldSizeX/2.0f, m_WorldSizeY/2.0f,-m_WorldSizeZ/2.0f);
glVertex3f( m_WorldSizeX/2.0f, m_WorldSizeY/2.0f,-m_WorldSizeZ/2.0f);
glVertex3f( m_WorldSizeX/2.0f, m_WorldSizeY/2.0f, m_WorldSizeZ/2.0f);
glVertex3f(-m_WorldSizeX/2.0f, m_WorldSizeY/2.0f, m_WorldSizeZ/2.0f);
glVertex3f(-m_WorldSizeX/2.0f, m_WorldSizeY/2.0f,-m_WorldSizeZ/2.0f);
glVertex3f(-m_WorldSizeX/2.0f,-m_WorldSizeY/2.0f,-m_WorldSizeZ/2.0f);
glEnd();
glBegin(GL_LINES);
glVertex3f( m_WorldSizeX/2.0f, m_WorldSizeY/2.0f,-m_WorldSizeZ/2.0f);
glVertex3f( m_WorldSizeX/2.0f,-m_WorldSizeY/2.0f,-m_WorldSizeZ/2.0f);
glVertex3f( m_WorldSizeX/2.0f, m_WorldSizeY/2.0f, m_WorldSizeZ/2.0f);
glVertex3f( m_WorldSizeX/2.0f,-m_WorldSizeY/2.0f, m_WorldSizeZ/2.0f);
glVertex3f(-m_WorldSizeX/2.0f, m_WorldSizeY/2.0f, m_WorldSizeZ/2.0f);
glVertex3f(-m_WorldSizeX/2.0f,-m_WorldSizeY/2.0f, m_WorldSizeZ/2.0f);
glEnd();
glDisable(GL_CULL_FACE);
glBegin(GL_QUADS);
glColor3f(0.0f,0.0f,0.5f);
glVertex3f(-m_WorldSizeX/2.0f,-m_WorldSizeY/2.0f,-m_WorldSizeZ/2.0f);
glVertex3f( m_WorldSizeX/2.0f,-m_WorldSizeY/2.0f,-m_WorldSizeZ/2.0f);
glVertex3f( m_WorldSizeX/2.0f,-m_WorldSizeY/2.0f, m_WorldSizeZ/2.0f);
glVertex3f(-m_WorldSizeX/2.0f,-m_WorldSizeY/2.0f, m_WorldSizeZ/2.0f);
glEnd();
glEnable(GL_CULL_FACE);
if (m_ParticleSys)
{
if (m_Spring && m_DrawSprings)
{
glBegin(GL_LINES);
glColor3f(0.0f,0.8f,0.8f);
tempSpring = m_Spring;
for (int loop = 0; loop < m_SpringCnt; loop++)
{
if ((tempSpring->type == MANUAL_SPRING) ||
(tempSpring->type == STRUCTURAL_SPRING && m_DrawStructural) ||
(tempSpring->type == SHEAR_SPRING && m_DrawShear) ||
(tempSpring->type == BEND_SPRING && m_DrawBend))
{
glVertex3fv((float *)&m_CurrentSys[tempSpring->p1].pos);
glVertex3fv((float *)&m_CurrentSys[tempSpring->p2].pos);
}
tempSpring++;
}
if (m_MouseForceActive)
{
if (m_Pick[0] > -1)
{
glColor3f(0.8f,0.0f,0.8f);
glVertex3fv((float *)&m_CurrentSys[m_Pick[0]].pos);
glVertex3fv((float *)&m_MouseDragPos[0]);
}
if (m_Pick[1] > -1)
{
glColor3f(0.8f,0.0f,0.8f);
glVertex3fv((float *)&m_CurrentSys[m_Pick[1]].pos);
glVertex3fv((float *)&m_MouseDragPos[1]);
}
}
glEnd();
}
if (m_DrawVertices)
{
glBegin(GL_POINTS);
tempParticle = m_CurrentSys;
for (int loop = 0; loop < m_ParticleCnt; loop++)
{
if (loop == m_Pick[0])
glColor3f(0.0f,0.8f,0.0f);
else if (loop == m_Pick[1])
glColor3f(0.8f,0.0f,0.0f);
else
glColor3f(0.8f,0.8f,0.0f);
glVertex3fv((float *)&tempParticle->pos);
tempParticle++;
}
glEnd();
}
}
if (m_SphereCnt > 0 && m_CollisionActive)
{
glColor3f(0.5f,0.0f,0.0f);
for (int loop = 0; loop < m_SphereCnt; loop++)
{
glPushMatrix();
glTranslatef(m_Sphere[loop].pos.x, m_Sphere[loop].pos.y, m_Sphere[loop].pos.z);
glScalef(m_Sphere[loop].radius,m_Sphere[loop].radius,m_Sphere[loop].radius);
glCallList(OGL_AXIS_DLIST);
glPopMatrix();
}
}
}
void CPhysEnv::GetNearestPoint(int x, int y)
{
/// 局部变量定义 ///////////////////////////////////////////////////////////
float *feedBuffer;
int hitCount;
tParticle *tempParticle;
int loop;
///////////////////////////////////////////////////////////////////////////////
feedBuffer = (float *)malloc(sizeof(GLfloat) * m_ParticleCnt * 6);
glFeedbackBuffer(m_ParticleCnt * 6,GL_3D,feedBuffer);
(void)glRenderMode(GL_FEEDBACK);
tempParticle = m_CurrentSys;
for (loop = 0; loop < m_ParticleCnt; loop++)
{
glPassThrough((float)loop);
glBegin(GL_POINTS);
glVertex3fv((float *)&tempParticle->pos);
glEnd();
tempParticle++;
}
hitCount = glRenderMode(GL_RENDER);
CompareBuffer(hitCount,feedBuffer,(float)x,(float)y);
free(feedBuffer);
}
///////////////////////////////////////////////////////////////////////////////
// Function: CompareBuffer
// Purpose: Check the feedback buffer to see if anything is hit
// Arguments: Number of hits, pointer to buffer, point to test
///////////////////////////////////////////////////////////////////////////////
void CPhysEnv::CompareBuffer(int size, float *buffer,float x, float y)
{
/// Local Variables ///////////////////////////////////////////////////////////
GLint count;
GLfloat token,point[3];
int loop,currentVertex,result = -1;
long nearest = -1, dist;
///////////////////////////////////////////////////////////////////////////////
count = size;
while (count)
{
token = buffer[size - count]; // CHECK THE TOKEN
count--;
if (token == GL_PASS_THROUGH_TOKEN) // VERTEX MARKER
{
currentVertex = (int)buffer[size - count]; // WHAT VERTEX
count--;
}
else if (token == GL_POINT_TOKEN)
{
// THERE ARE THREE ELEMENTS TO A POINT TOKEN
for (loop = 0; loop < 3; loop++)
{
point[loop] = buffer[size - count];
count--;
}
dist = ((x - point[0]) * (x - point[0])) + ((y - point[1]) * (y - point[1]));
if (result == -1 || dist < nearest)
{
nearest = dist;
result = currentVertex;
}
}
}
if (nearest < 50.0f)
{
if (m_Pick[0] == -1)
m_Pick[0] = result;
else if (m_Pick[1] == -1)
m_Pick[1] = result;
else
{
m_Pick[0] = result;
m_Pick[1] = -1;
}
}
}
////// CompareBuffer //////////////////////////////////////////////////////////
void CPhysEnv::SetWorldParticles(tTexturedVertex *coords,int particleCnt)
{
tParticle *tempParticle;
if (m_ParticleSys[0])
free(m_ParticleSys[0]);
if (m_ParticleSys[1])
free(m_ParticleSys[1]);
if (m_ParticleSys[2])
free(m_ParticleSys[2]);
for (int i = 0; i < 5; i++)
{
if (m_TempSys[i])
free(m_TempSys[i]);
}
if (m_Contact)
free(m_Contact);
// THE SYSTEM IS DOUBLE BUFFERED TO MAKE THINGS EASIER
m_CurrentSys = (tParticle *)malloc(sizeof(tParticle) * particleCnt);
m_TargetSys = (tParticle *)malloc(sizeof(tParticle) * particleCnt);
m_ParticleSys[2] = (tParticle *)malloc(sizeof(tParticle) * particleCnt);
for (i = 0; i < 5; i++)
{
m_TempSys[i] = (tParticle *)malloc(sizeof(tParticle) * particleCnt);
}
m_ParticleCnt = particleCnt;
// MULTIPLIED PARTICLE COUNT * 2 SINCE THEY CAN COLLIDE WITH MULTIPLE WALLS
m_Contact = (tContact *)malloc(sizeof(tContact) * particleCnt * 2);
m_ContactCnt = 0;
tempParticle = m_CurrentSys;
for (int loop = 0; loop < particleCnt; loop++)
{
MAKEVECTOR(tempParticle->pos, coords->x, coords->y, coords->z)
MAKEVECTOR(tempParticle->v, 0.0f, 0.0f, 0.0f)
MAKEVECTOR(tempParticle->f, 0.0f, 0.0f, 0.0f)
tempParticle->oneOverM = 1.0f; // MASS OF 1
tempParticle++;
coords++;
}
// COPY THE SYSTEM TO THE SECOND ONE ALSO
memcpy(m_TargetSys,m_CurrentSys,sizeof(tParticle) * particleCnt);
// COPY THE SYSTEM TO THE RESET BUFFER ALSO
memcpy(m_ParticleSys[2],m_CurrentSys,sizeof(tParticle) * particleCnt);
m_ParticleSys[0] = m_CurrentSys;
m_ParticleSys[1] = m_TargetSys;
}
///////////////////////////////////////////////////////////////////////////////
// Function: FreeSystem
// Purpose: Remove all particles and clear it out
///////////////////////////////////////////////////////////////////////////////
void CPhysEnv::FreeSystem()
{
m_Pick[0] = -1;
m_Pick[1] = -1;
if (m_ParticleSys[0])
{
m_ParticleSys[0] = NULL;
free(m_ParticleSys[0]);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -