コード例 #1
0
ファイル: main.cpp プロジェクト: asylum2010/Asylum_Tutorials
void UpdateParticles(float dt, bool generate)
{
	// NOTE: runs on 10 fps

	OpenGLAABox tmpbox = scenebox;
	float center[3];

	if( lightbuffer == 0 )
		return;

	glBindBuffer(GL_SHADER_STORAGE_BUFFER, lightbuffer);
	LightParticle* particles = (LightParticle*)glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_WRITE);

	tmpbox.GetCenter(center);

	if( generate )
	{
		int segments = GLISqrt(NUM_LIGHTS);
		float theta, phi;

		OpenGLColor randomcolors[3] =
		{
			OpenGLColor(1, 0, 0, 1),
			OpenGLColor(0, 1, 0, 1),
			OpenGLColor(0, 0, 1, 1)
		};

		for( int i = 0; i < segments; ++i )
		{
			for( int j = 0; j < segments; ++j )
			{
				LightParticle& p = particles[i * segments + j];

				theta = ((float)j / (segments - 1)) * M_PI;
				phi = ((float)i / (segments - 1)) * M_2PI;

				p.previous[0] = center[0];
				p.previous[1] = center[1];
				p.previous[2] = center[2];
				p.previous[3] = 1;

				p.velocity[0] = sinf(theta) * cosf(phi) * 2;
				p.velocity[1] = cosf(theta) * 2;
				p.velocity[2] = sinf(theta) * sinf(phi) * 2;

				p.current[0] = p.previous[0];
				p.current[1] = p.previous[1];
				p.current[2] = p.previous[2];
				p.current[3] = 1;

				p.radius = LIGHT_RADIUS;
				p.color = randomcolors[(i + j) % 3];
			}
		}
	}
	else
	{
		float vx[3], vy[3], vz[3];
		float b[3];
		float A[16], Ainv[16];
		float planes[6][4];
		float denom, energy;
		float toi, besttoi;
		float impulse, noise;
		float (*bestplane)[4];
		bool pastcollision;

		tmpbox.GetPlanes(planes);

		for( int i = 0; i < NUM_LIGHTS; ++i )
		{
			LightParticle& p = particles[i];

			// integrate
			p.previous[0] = p.current[0];
			p.previous[1] = p.current[1];
			p.previous[2] = p.current[2];

			p.current[0] += p.velocity[0] * dt;
			p.current[1] += p.velocity[1] * dt;
			p.current[2] += p.velocity[2] * dt;

			// detect collision
			besttoi = 2;

			b[0] = p.current[0] - p.previous[0];
			b[1] = p.current[1] - p.previous[1];
			b[2] = p.current[2] - p.previous[2];

			for( int j = 0; j < 6; ++j )
			{
				// use radius == 0.5
				denom = GLVec3Dot(b, planes[j]);
				pastcollision = (GLVec3Dot(p.previous, planes[j]) + planes[j][3] < 0.5f);

				if( denom < -1e-4f )
				{
					toi = (0.5f - GLVec3Dot(p.previous, planes[j]) - planes[j][3]) / denom;

					if( ((toi <= 1 && toi >= 0) ||		// normal case
						(toi < 0 && pastcollision)) &&	// allow past collision
						toi < besttoi )
					{
						besttoi = toi;
						bestplane = &planes[j];
					}
				}
			}

			if( besttoi <= 1 )
			{
				// resolve constraint
				p.current[0] = (1 - besttoi) * p.previous[0] + besttoi * p.current[0];
				p.current[1] = (1 - besttoi) * p.previous[1] + besttoi * p.current[1];
				p.current[2] = (1 - besttoi) * p.previous[2] + besttoi * p.current[2];

				impulse = -GLVec3Dot(*bestplane, p.velocity);

				// perturb normal vector
				noise = ((rand() % 100) / 100.0f) * M_PI * 0.333333f - M_PI * 0.166666f; // [-pi/6, pi/6]

				b[0] = cosf(noise + M_PI * 0.5f);
				b[1] = cosf(noise);
				b[2] = 0;

				GLVec3Normalize(vy, (*bestplane));
				GLGetOrthogonalVectors(vx, vz, vy);

				A[0] = vx[0];	A[1] = vy[0];	A[2] = vz[0];	A[3] = 0;
				A[4] = vx[1];	A[5] = vy[1];	A[6] = vz[1];	A[7] = 0;
				A[8] = vx[2];	A[9] = vy[2];	A[10] = vz[2];	A[11] = 0;
				A[12] = 0;		A[13] = 0;		A[14] = 0;		A[15] = 1;

				GLMatrixInverse(Ainv, A);
				GLVec3Transform(vy, b, Ainv);

				energy = GLVec3Length(p.velocity);

				p.velocity[0] += 2 * impulse * vy[0];
				p.velocity[1] += 2 * impulse * vy[1];
				p.velocity[2] += 2 * impulse * vy[2];

				// must conserve energy
				GLVec3Normalize(p.velocity, p.velocity);

				p.velocity[0] *= energy;
				p.velocity[1] *= energy;
				p.velocity[2] *= energy;
			}

#ifdef _DEBUG
			// test if a light fell through
			tmpbox.GetCenter(center);

			if( GLVec3Distance(p.current, center) > tmpbox.Radius() )
				::_CrtDbgBreak();
#endif
		}
	}

	glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
	glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
}
コード例 #2
0
void FPSCamera::Update(float dt)
{
	float forward[3], right[3], up[3];
	float diff[3];
	float movedir[2] = { 0, 0 };

	// rotate
	targetangles[1] = GLClamp(targetangles[1], -GL_HALF_PI, GL_HALF_PI);

	diff[0] = (targetangles[0] - anglecurve.curr[0]) * dt * ROTATIONAL_INVINTERTIA;
	diff[1] = (targetangles[1] - anglecurve.curr[1]) * dt * ROTATIONAL_INVINTERTIA;
	diff[2] = 0;

	anglecurve.extend(diff);
	
	// move
	GLVec3Set(diff, 0, 0, 0);

	if( state & State_Moving )
	{
		if( state & State_Left )
			movedir[0] = -1;

		if( state & State_Right )
			movedir[0] = 1;

		if( state & State_Forward )
			movedir[1] = 1;

		if( state & State_Backward )
			movedir[1] = -1;

		GetViewVectors(forward, right, up);

		if( forward[1] > 0.98f )
			GLVec3Set(forward, -up[0], -up[1], -up[2]);

		if( forward[1] < -0.98f )
			GLVec3Set(forward, up[0], up[1], up[2]);

		forward[1] = right[1] = 0;

		GLVec3Scale(forward, forward, movedir[1]);
		GLVec3Scale(right, right, movedir[0]);
		GLVec3Add(diff, forward, right);

		GLVec3Normalize(diff, diff);
		GLVec3Scale(diff, diff, MOVEMENT_SPEED);
	}

	// update body (NOTE: don't even try it with physics)
	CollisionData	data;
	RigidBody*		groundbody = 0;
	float			groundplane[4];
	float			hitparams[4];
	float			hitpos[3];
	float			prevpos[3];
	float			vel[3];
	float			deltavel[3] = { 0, 0, 0 };
	float			down[3] = { 0, -1, 0 };
	bool			wasonground = isonground;

	GLVec3Assign(prevpos, body->GetPosition());

	if( wasonground )
		body->SetVelocity(diff);
	
	body->Integrate(dt);

	// look for ground first
	groundbody = collworld->RayIntersect(hitparams, prevpos, down);
	isonground = false;

	if( groundbody && hitparams[3] >= 0 ) // && hitparams[1] > 0.64f
	{
		GLVec3Mad(hitpos, prevpos, down, hitparams[3]);
		GLPlaneFromRay(groundplane, hitpos, hitparams);
		GLVec3Subtract(vel, body->GetPosition(), prevpos);

		hitparams[3] = (CAMERA_RADIUS - groundplane[3] - GLVec3Dot(hitparams, prevpos)) / GLVec3Dot(hitparams, vel);

		if( hitparams[3] > -0.1f && hitparams[3] < 1.0f )
		{
			// resolve position
			body->ResolvePenetration(hitparams[3] * dt);
			isonground = true;

			// resolve velocity and integrate
			float length = GLVec3Length(diff);
			float cosa = GLVec3Dot(diff, hitparams);

			GLVec3Mad(diff, diff, hitparams, -cosa);

			if( fabs(length) > 1e-5f )
				GLVec3Scale(diff, diff, length / GLVec3Length(diff));

			body->SetVelocity(diff);
			body->IntegratePosition(dt);
		}
	}

	body->GetVelocity(vel);

	// now test every other object
	collworld->DetectCollisions(data, body);

	for( size_t i = 0; i < data.contacts.size(); ++i )
	{
		const Contact& contact = data.contacts[i];

		if( contact.body2 == groundbody )
			continue;

		if( contact.depth > 0 )
		{
			body->ResolvePenetration(contact);

			float rel_vel = GLVec3Dot(contact.normal, vel);
			float impulse = rel_vel;

			GLVec3Mad(deltavel, deltavel, contact.normal, -impulse);
		}
	}

	GLVec3Add(vel, vel, deltavel);
	body->SetVelocity(vel);
}