Sign in to follow this  

Mass and Scale Factor Problem

This topic is 4340 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

After reading one of the GameDev articles, I saw some awesome code that would allow me to have very accurate physics with a fixed time step. Here's the code I saw:
// Timestep Example Source Code
// Copyright (c) Glenn Fiedler 2004
// http://www.gaffer.org/articles

bool openDisplay(int width, int height);
void updateDisplay();
void closeDisplay();
void onQuit();
float time();

#include "Apple.h"
#include "Windows.h"

bool quit = false;

void onQuit()
{
	quit = true;
}

struct State
{
	float x;
	float v;
};

struct Derivative
{
	float dx;
	float dv;
};

State interpolate(const State &previous, const State &current, float alpha)
{
	State state;
	state.x = current.x*alpha + previous.x*(1-alpha);
	state.v = current.v*alpha + previous.v*(1-alpha);
	return state;
}

float acceleration(const State &state, float t)
{
	const float k = 10;
	const float b = 1;
	return - k*state.x - b*state.v;
}

Derivative evaluate(const State &initial, float t)
{
	Derivative output;
	output.dx = initial.v;
	output.dv = acceleration(initial, t);
	return output;
}

Derivative evaluate(const State &initial, float t, float dt, const Derivative &d)
{
	State state;
	state.x = initial.x + d.dx*dt;
	state.v = initial.v + d.dv*dt;
	Derivative output;
	output.dx = state.v;
	output.dv = acceleration(state, t+dt);
	return output;
}

void integrate(State &state, float t, float dt)
{
	Derivative a = evaluate(state, t);
	Derivative b = evaluate(state, t, dt*0.5f, a);
	Derivative c = evaluate(state, t, dt*0.5f, b);
	Derivative d = evaluate(state, t, dt, c);
	
	const float dxdt = 1.0f/6.0f * (a.dx + 2.0f*(b.dx + c.dx) + d.dx);
	const float dvdt = 1.0f/6.0f * (a.dv + 2.0f*(b.dv + c.dv) + d.dv);
	
	state.x = state.x + dxdt*dt;
	state.v = state.v + dvdt*dt;
}

int main()
{
	const int width = 640;
	const int height = 480;
	
	if (!openDisplay("Timestep", width, height))
        return 1;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0, 4.0/3.0, 1, 1000);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0,0,150, 0,0,0, 0,1,0);
	
	glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
	glEnable(GL_POINT_SMOOTH);
	glPointSize(4);	
	
	glClearColor(0.3f, 0.3f, 0.3f, 1);

	State current;
	current.x = 100;
	current.v = 0;
	
	State previous = current;

	float t = 0.0f;
	float dt = 0.1f;
	
	float currentTime = 0.0f;
	float accumulator = 0.0f;
	
	while (!quit) 
	{			
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		
		const float newTime = time();
		float deltaTime = newTime - currentTime;
		currentTime = newTime;
		
		if (deltaTime>0.25f)
			deltaTime = 0.25f;
		
		accumulator += deltaTime;
		
		while (accumulator>=dt)
		{
			accumulator -= dt;
			previous = current;
			integrate(current, t, dt);
			t += dt;
		}
		
		State state = interpolate(previous, current, accumulator/dt);
		
		glBegin(GL_POINTS);
		glColor3f(1,1,1);
		glVertex3f(state.x, 0, 0);
		glEnd();
		
		updateDisplay();
	}
	
	closeDisplay();
	
	return 0;
}

I tried converting the C++ code into VB and it was a success! But instead of his spring equation, I wanted to implement this equation: x = x0 + v0 * t + 0.5 * a * t * t And I sorta got it working properly, except I would like mass to be incorporated, as well as a scale factor to size the coordinates however I want my real world simulation to be. Any ideas on how I can do this? C++ code is fine.

Share this post


Link to post
Share on other sites
Hopefully you aren't just using the code without understanding what it is or what it does. I don't care either way, but it helps if you know what the tool is. I'm assuming the code is based on the articles here, but if not then that link contains a bunch of useful information.

Quote:
Original post by Jacob Roman
And I sorta got it working properly, except I would like mass to be incorporated, as well as a scale factor to size the coordinates however I want my real world simulation to be.

The integrator uses acceleration as the driving force (no pun intended) of the simulation. The code you have assumes unit mass as mentioned in the above link, but I'm confident that you can use Newton's second law of motion to figure out how to modify that. However the equation you wish to model is for an object undergoing constant acceleration, so mass cancels out and you don't have to worry about it. This would work just swell for some constant acceleration A:

float acceleration(const State &state, float t) { return -A; }

The units themselves are arbitrary. They can be inches, feet, miles, pixels, meters, lightyears, or whatever else you need them to be.

Share this post


Link to post
Share on other sites
The mass will not be within acceleration, but for initial velocity. That way I can use f/m in that. Just have to code it correctly.

And yes I understand what it does, but I only have little experience with coding physics in my games. Needed the runge kutta for better accuracy though (found in the integrator function). May seem like overkill but the accuracy is worth it.

Share this post


Link to post
Share on other sites
As far as this simulation is concerned, whatever values are already in state.x and state.v when you begin are considered the initial position and initial velocity. They're generated before the simulation starts by whatever means you chose.

Share this post


Link to post
Share on other sites
I always wondered about that code...the line for RK4:

Derivative b = evaluate(state, t, dt*0.5f, a);
Derivative c = evaluate(state, t, dt*0.5f, b);

Shouldn't that be:

Derivative b = evaluate(state, t, dt*0.5f, a * 0.5f);
Derivative c = evaluate(state, t, dt*0.5f, b * 0.5f);

Or maybe it's another variant of RK4 that works just as well?

Shadx

Share this post


Link to post
Share on other sites
I know what you're thinking, and it just so happens that this implementation takes care of that. The quantity Δt/2 passed to the evaluator is added to the initial time, and multiplied by the passed derivative. Take a look at it this way, paying particular attention to the substitution:

k2 = (Δt)f(xn + Δt/2, yn + k1/2) = (Δt)f(xn + Δt/2, yn + (Δt/2)f(xn, yn))

That's of course the midpoint for an RK2 integrator but it extends into any order RK integrator. Hope that clears it up.

Share this post


Link to post
Share on other sites
Your absolutely right, I'm kinda annoyed at myself for missing it. It's not the equation that caused me to miss it, it's the dt/2 becoming dt inside the evaluate function. I had my math hat on at the time and didn't make the substitution.

Thanks,

Shadx

Share this post


Link to post
Share on other sites

This topic is 4340 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this