Re: [Algorithms] Scrolling starfield
Brought to you by:
vexxed72
From: Thatcher U. <tu...@tu...> - 2002-07-31 03:25:44
|
On Jul 30, 2002 at 09:51 -0500, brian hook wrote: > > For the snow in Soul Ride I made a set of particles inside a "weather > > cube" (concept due to Mike Linkovich). I used 32-bit ints for the 3D > > coordinate of each snowflake, scaled such that my cube used the entire > > 32 bits. To simulate snowfall and viewpoint motion, I computed the > > sum of those displacements and scaled them into my weather cube > > coords, and ripped through all the snowflakes adding the same > > displacement to each one (all integer ops). No need to check for > > overflow; the flakes would just wrap around correctly. The display > > was just a simple billboard, in a loop inside glBegin(GL_QUADS). I > > was planning to do some turbulent motion by adding in offsets from a > > short pseudo-random table, but never got around to it. > > This sounds pretty much like what I want, I think, except I have no > idea what it means =) Can you elaborate a bit? Heh :) Working code pasted below. > FWIW, the star field is only there to provide a sense of motion, which > is why I want the parallax effect even though it's unrealistic. I > don't need a lot of stars -- in fact, with my current system I only > have about 200 visible and it feels fine. Cool; it should hopefully work then. The sizing of the stars is still an issue; I guess the solution depends on the effect you're going for. -T -------------------------- // // Falling snow. // bool FlakesInited = false; float SnowDensity = 0.6; // Particles per cubic meter. Exaggeratedly small. vec3 SnowVelocity(0, -1.0, 0); //const float SNOWFLAKE_SIZE = 0.04; // Exaggeratedly large. const float WEATHER_BLOCK_SIZE = 14; vec3 PreviousViewpoint(0, 0, 0); Render::Texture* SnowflakeTexture = NULL; float SnowflakeWidth = 0.04, SnowflakeHeight = 0.04; struct FlakeInfo { uint32 x, y, z; } *Flake = NULL; int FlakeCount; int DeltaTicks = 0; void InitFlakes() // Set up a set of random flakes within the weather block. { SnowDensity = Config::GetFloatValue("SnowDensity"); FlakeCount = SnowDensity * WEATHER_BLOCK_SIZE * WEATHER_BLOCK_SIZE * WEATHER_BLOCK_SIZE; if (FlakeCount > 10000) FlakeCount = 10000; // Sanity limit. if (Flake) delete [] Flake; if (FlakeCount > 0) { Flake = new FlakeInfo[FlakeCount]; } else { Flake = NULL; return; } int i; // Initialize flakes. for (i = 0; i < FlakeCount; i++) { Flake[i].x = rand() << 17; Flake[i].y = rand() << 17; Flake[i].z = rand() << 17; } // Load flake texture. bitmap32* b = PSDRead::ReadImageData32("snowflake.psd", &SnowflakeWidth, &SnowflakeHeight); if (b == NULL) { Error e; e << "Can't open snowflake.psd"; throw e; } SnowflakeWidth *= 0.01; SnowflakeHeight *= 0.01; if (SnowflakeTexture) { SnowflakeTexture->ReplaceImage(b); } else { SnowflakeTexture = Render::NewTextureFromBitmap(b, true, true, false); } delete b; } void FlakesUpdate(const UpdateState& u) // Defer the actual update until the Render() call. But, keep track of the // amount of time which has passed. { DeltaTicks += u.DeltaTicks; } void RenderOverlay(const ViewState& s) // Update and then draw snowflakes. { if (FlakesInited == false || Config::GetBoolValue("F4Pressed")) { InitFlakes(); FlakesInited = true; } float dt = DeltaTicks / 1000.0 * GameLoop::GetSpeedScale(); DeltaTicks = 0; if (Flake == NULL) return; if (Config::GetBoolValue("Snowfall") == false) return; // Calculate the viewpoint shift. The flakes shift by an opposite amount. const vec3& Viewpoint = s.Viewpoint; vec3 Shift = -(Viewpoint - PreviousViewpoint); PreviousViewpoint = Viewpoint; // Calculate the shift due to the motion of the snowflakes. Shift += SnowVelocity * dt; // Calculate the shift in terms of weather-block fixed-point coords. Shift *= 1.0 / WEATHER_BLOCK_SIZE; uint32 dx, dy, dz; dx = int((Shift.X() - floor(Shift.X())) * 65536.0) << 16; dy = int((Shift.Y() - floor(Shift.Y())) * 65536.0) << 16; dz = int((Shift.Z() - floor(Shift.Z())) * 65536.0) << 16; // Move the flakes. Rely on integer wrap-around arithmetic to keep the flakes within the weather block. int i; for (i = 0; i < FlakeCount; i++) { Flake[i].x += dx; // Could throw in some turbulence or something? From a table, indexed on middle bits of coordinates? Scaling to dt is an issue. Flake[i].y += dy; Flake[i].z += dz; } // Now draw 'em. // Put the viewpoint right in the middle of the weather block. glPushMatrix(); glTranslatef(Viewpoint.X() - WEATHER_BLOCK_SIZE * 0.5, Viewpoint.Y() - WEATHER_BLOCK_SIZE * 0.5, Viewpoint.Z() - WEATHER_BLOCK_SIZE * 0.5); glColor3f(1, 1, 1); Render::SetTexture(SnowflakeTexture); Render::DisableAlphaTest(); Render::EnableZBuffer(); Render::CommitRenderState(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glDepthMask(GL_FALSE); vec3 Right, Up; s.ViewMatrix.ApplyInverseRotation(&Right, vec3(-SnowflakeWidth, 0, 0)); s.ViewMatrix.ApplyInverseRotation(&Up, vec3(0, SnowflakeHeight, 0)); // Draw each flake. glBegin(GL_QUADS); vec3 v; for (i = 0; i < FlakeCount; i++) { // four verts of the billboard; // (x >> 16) * (WEATHER_BLOCK_SIZE / 65536.0); v.SetX((Flake[i].x >> 16) * (WEATHER_BLOCK_SIZE / 65536.0)); v.SetY((Flake[i].y >> 16) * (WEATHER_BLOCK_SIZE / 65536.0)); v.SetZ((Flake[i].z >> 16) * (WEATHER_BLOCK_SIZE / 65536.0)); glTexCoord2f(0, 1); glVertex3fv((const float*) v); v += Right; glTexCoord2f(1, 1); glVertex3fv((const float*) v); v += Up; glTexCoord2f(1, 0); glVertex3fv((const float*) v); v -= Right; glTexCoord2f(0, 0); glVertex3fv((const float*) v); } glEnd(); Model::AddToTriangleCount(FlakeCount); glDepthMask(GL_TRUE); glDisable(GL_BLEND); // Restore viewpoint. glPopMatrix(); } |