bool LightSquare::getLight( const TWorld &world, const TRay &ray, TRay &lightRay ) { // If point not in light volume, return false (no diffuse component) if ( !isLighten( ray.intersection.pointWorldSpace ) ) return false; if ( !globalSettings::shadowOn ) return true; stats.increase( TStatistic::STATISTIC_LIGHT_RAY ); // Compute vector from intersection to light lightRay.direction = location - ray.intersection.pointWorldSpace; float dist2 = lightRay.direction.magnitudeSquared(); // get vector length //--TODO // test attenuation //--TODO float att = brightness; //--TODO if ( attenuation ) //--TODO att = ( brightness / ( 1.0f + dist2 ) ); //--TODO if ( att < lightAttenuation ) //--TODO return false; lightRay.direction *= fastInvSqrt( dist2 ); // normalize vector lightRay.origin = ray.intersection.pointWorldSpace + lightRay.direction * 0.1f; // origin is intersection lightRay.reverseDirection = inverseVector( lightRay.direction ); lightRay.target = location; lightRay.kind = TRay::RAY_SHADOW; // Compute amount of shadow receive 0: full shadow 1: no shadow if ( world.findFirstIntersection( lightRay, ray.intersection, dist2, shadowCache ) ) return false; return true; }
float LightSquare::getAmountShadow( const TWorld &world, const TRay &ray ) { float shadow = 0.0f; // for each dot light in square: create a light ray and compute intersection TRay shadowRay; TPoint3 *dotGridIdx = dotGrid; for ( int i = 0; i < numDots; i++ ) { // create a lightRay from dot in grid to intersection shadowRay.direction = *dotGridIdx - ray.intersection.pointWorldSpace; float dist2 = shadowRay.direction.magnitudeSquared(); //--TODO // test attenuation //--TODO float att = brightness; //--TODO if ( attenuation ) //--TODO att = ( brightness / ( 1.0f + dist2 ) ); //--TODO if ( att < lightAttenuation ) { //--TODO dotGridIdx++; // next dot in grid //--TODO continue; //--TODO } shadowRay.direction *= fastInvSqrt( dist2 ); // normalize vector shadowRay.origin = ray.intersection.pointWorldSpace + shadowRay.direction * 0.1f; // origin is intersection shadowRay.reverseDirection = inverseVector( shadowRay.direction ); shadowRay.target = *dotGridIdx; shadowRay.kind = TRay::RAY_SHADOW; //-- // if shadow: add 0.0f //-- if ( world.findFirstIntersection( shadowRay, ray.intersection, dist2, shadowCache ) ) //-- shadowCache = shadowRay.intersectionObject; // store object in cache //-- // if no shadow: add 1.0f //-- else //-- shadow += 1.0f; // if no shadow: add 1.0f, shadow cache is updated in findFirstIntersection if ( !world.findFirstIntersection( shadowRay, ray.intersection, dist2, shadowCache ) ) shadow += 1.0f; // if shadow: add 0.0f dotGridIdx++; // next dot in grid } return shadow * oneOverNumDots; }
bool Particle::update() { if (!mMap) return false; if (mLifetimeLeft == 0) { mAlive = false; } if (mAlive) { //calculate particle movement if (mMomentum != 1.0f) { mVelocity *= mMomentum; } if (mTarget && mAcceleration != 0.0f) { Vector dist = mPos - mTarget->getPosition(); dist.x *= SIN45; float invHypotenuse; switch (Particle::fastPhysics) { case 1: invHypotenuse = fastInvSqrt( dist.x * dist.x + dist.y * dist.y + dist.z * dist.z); break; case 2: invHypotenuse = 2.0f / fabs(dist.x) + fabs(dist.y) + fabs(dist.z); break; default: invHypotenuse = 1.0f / sqrt( dist.x * dist.x + dist.y * dist.y + dist.z * dist.z); break; } if (invHypotenuse) { if (mInvDieDistance > 0.0f && invHypotenuse > mInvDieDistance) { mAlive = false; } float accFactor = invHypotenuse * mAcceleration; mVelocity -= dist * accFactor; } } if (mRandomnes > 0) { mVelocity.x += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; mVelocity.y += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; mVelocity.z += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f; } mVelocity.z -= mGravity; // Update position mPos.x += mVelocity.x; mPos.y += mVelocity.y * SIN45; mPos.z += mVelocity.z * SIN45; // Update other stuff if (mLifetimeLeft > 0) { mLifetimeLeft--; } mLifetimePast++; if (mPos.z > PARTICLE_SKY || mPos.z < 0.0f) { if (mBounce > 0.0f) { mPos.z *= -mBounce; mVelocity *= mBounce; mVelocity.z = -mVelocity.z; } else { mAlive = false; } } // Update child emitters if (mLifetimePast%Particle::emitterSkip == 0) { for ( EmitterIterator e = mChildEmitters.begin(); e != mChildEmitters.end(); e++ ) { Particles newParticles = (*e)->createParticles(); for ( ParticleIterator p = newParticles.begin(); p != newParticles.end(); p++ ) { (*p)->moveBy(mPos.x, mPos.y, mPos.z); mChildParticles.push_back (*p); } } } } // Update child particles for (ParticleIterator p = mChildParticles.begin(); p != mChildParticles.end();) { if ((*p)->update()) { p++; } else { delete (*p); p = mChildParticles.erase(p); } } if (!mAlive && mChildParticles.empty() && mAutoDelete) { return false; } return true; }
bool LightSquare::computeLighting( const TWorld &world, const TRay &ray, TLighting &lighting ) { lighting.light = this; lighting.visible = isLighten( ray.intersection.pointWorldSpace ); // If point not in light volume, return false (no diffuse component) if ( !lighting.visible ) return false; const TFinish *finish = ray.intersection.texture->finish; // reset lighting lighting.shadow = 0.0f; lighting.diffuse = 0.0f; lighting.specular = 0.0f; lighting.phong = 0.0f; float att = 0.0f; TRay lightRay; TPoint3 *dotGridIdx = dotGrid; for ( int i = 0; i < numDots; i++, dotGridIdx++ ) { // create a lightRay from dot in grid to intersection lightRay.direction = *dotGridIdx - ray.intersection.pointWorldSpace; float dist2 = lightRay.direction.magnitudeSquared(); lightRay.direction *= fastInvSqrt( dist2 ); // normalize vector lightRay.origin = ray.intersection.pointWorldSpace + lightRay.direction * 0.1f; // origin is intersection lightRay.reverseDirection = inverseVector( lightRay.direction ); lightRay.target = *dotGridIdx; stats.increase( TStatistic::STATISTIC_LIGHT_RAY ); // TODO att += brightness; // if shadow: proceed with next lightRay if ( world.findFirstIntersection( lightRay, ray.intersection, dist2, shadowCache ) ) continue; // if no shadow: add 1.0f (no shadow) to lighting.shadow lighting.shadow += 1.0f; stats.increase( TStatistic::STATISTIC_DIFFUSE ); // Diffuse if ( finish->diffuseFactor > 0.0f ) { float angleLight = ray.intersection.normal | lightRay.direction; if ( angleLight > 0.0f ) //--float intensity = powf( angleLight, finish->brilliance ); // FIXME lighting.diffuse += angleLight * finish->diffuseFactor; } // Specular if ( finish->specularFactor > 0.0f ) { TVector3 H = lightRay.direction - ray.direction; H.normalize(); float angleSpecular = H | ray.intersection.normal; if ( angleSpecular > 0.0f ) { float intensity = powf( angleSpecular, finish->specularRoughness ); lighting.specular += intensity * finish->specularFactor; } } // Phong if ( finish->phongFactor > 0.0f ) { TVector3 R = reflectVector( ray.direction, ray.intersection.normal ); float anglePhong = R | lightRay.direction; if ( anglePhong > 0.0f ) { float intensity = powf( anglePhong, finish->phongSize ); lighting.phong += intensity * finish->phongFactor; } } } // If full shadow, return false (no diffuse component) if ( lighting.shadow <= 0.0f ) return false; // att, shadow, diffuse, specular and phong must be scaled by oneOverNumDots (=N) // att * N * shadow * N * ( diffuse * N + specular * N + phong * N ) // = N*N * ( att * shadow * ( N * ( diffuse + specular + phong ) ) // = N*N*N * ( att * shadow * ( diffuse + specular + phong ) ) lighting.color = color * ( (oneOverNumDots*oneOverNumDots*oneOverNumDots) * att * lighting.shadow * ( lighting.diffuse + lighting.specular + lighting.phong ) ); return true; }
bool LightSquare::computeLighting( const TWorld &world, const TRay &ray, TLighting &lighting ) { lighting.light = this; lighting.visible = isLighten( ray.intersection.pointWorldSpace ); // If point not in light volume, return false (no diffuse component) if ( !lighting.visible ) return false; stats.increase( TStatistic::STATISTIC_LIGHT_RAY ); // Compute vector from intersection to light TRay lightRay; lightRay.direction = location - ray.intersection.pointWorldSpace; float dist2 = lightRay.direction.magnitudeSquared(); // get vector length // test attenuation float att = brightness; //--TODO if ( attenuation ) //--TODO att = ( brightness / ( 1.0f + dist2 ) ); //--TODO if ( att < lightAttenuation ) //--TODO return false; lightRay.direction *= fastInvSqrt( dist2 ); // normalize vector //-- lightRay.origin = ray.intersection.pointWorldSpace + lightRay.direction * 0.1f; // origin is intersection //-- lightRay.reverseDirection = inverseVector( lightRay.direction ); //-- lightRay.target = location; lightRay.kind = TRay::RAY_SHADOW; // Shadow //-- if ( globalSettings::shadowOn //-- && world.findFirstIntersection( lightRay, ray.intersection, dist2, shadowCache ) ) { //-- // If full shadow, return false (no diffuse component) //-- lighting.shadow = 0.0f; // shadow //-- return false; //-- } //-- else //-- lighting.shadow = 1.0f; // no shadow if ( globalSettings::shadowOn ) { lighting.shadow = getAmountShadow( world, ray ); // If full shadow, return false (no diffuse component) if ( lighting.shadow <= 0.0f ) return false; } else lighting.shadow = 1.0f; const TFinish *finish = ray.intersection.texture->finish; stats.increase( TStatistic::STATISTIC_DIFFUSE ); // Diffuse lighting.diffuse = 0.0f; if ( finish->diffuseFactor > 0.0f ) { // FIXME: create a light ray for each dot in square and compute average value // we compute angle between lightRay (from intersection to center of square) // this "trick" is a good approximation if dotSize is small float angleLight = ray.intersection.normal | lightRay.direction; if ( angleLight > 0.0f ) //--float intensity = powf( angleLight, finish->brilliance ); // FIXME lighting.diffuse = angleLight * finish->diffuseFactor; } // Specular lighting.specular = 0.0f; if ( finish->specularFactor > 0.0f ) { TVector3 H = lightRay.direction - ray.direction; H.normalize(); float angleSpecular = H | ray.intersection.normal; if ( angleSpecular > 0.0f ) { float intensity = powf( angleSpecular, finish->specularRoughness ); lighting.specular = intensity * finish->specularFactor; } } // Phong lighting.phong = 0.0f; if ( finish->phongFactor > 0.0f ) { TVector3 R = reflectVector( ray.direction, ray.intersection.normal ); float anglePhong = R | lightRay.direction; if ( anglePhong > 0.0f ) { float intensity = powf( anglePhong, finish->phongSize ); lighting.phong = intensity * finish->phongFactor; } } lighting.color = color * ( att * lighting.shadow * ( lighting.diffuse + lighting.specular + lighting.phong ) ); return true; }
bool Particle::update() { if (!mMap) return false; if (mLifetimeLeft == 0 && mAlive == ALIVE) mAlive = DEAD_TIMEOUT; Vector oldPos = mPos; if (mAlive == ALIVE) { //calculate particle movement if (mMomentum != 1.0f) { mVelocity *= mMomentum; } if (mTarget && mAcceleration != 0.0f) { Vector dist = mPos - mTarget->getPosition(); dist.x *= SIN45; float invHypotenuse; switch (Particle::fastPhysics) { case 1: invHypotenuse = fastInvSqrt( dist.x * dist.x + dist.y * dist.y + dist.z * dist.z); break; case 2: invHypotenuse = 2.0f / fabs(dist.x) + fabs(dist.y) + fabs(dist.z); break; default: invHypotenuse = 1.0f / sqrt( dist.x * dist.x + dist.y * dist.y + dist.z * dist.z); break; } if (invHypotenuse) { if (mInvDieDistance > 0.0f && invHypotenuse > mInvDieDistance) { mAlive = DEAD_IMPACT; } float accFactor = invHypotenuse * mAcceleration; mVelocity -= dist * accFactor; } } if (mRandomness > 0) { mVelocity.x += (rand()%mRandomness - rand()%mRandomness) / 1000.0f; mVelocity.y += (rand()%mRandomness - rand()%mRandomness) / 1000.0f; mVelocity.z += (rand()%mRandomness - rand()%mRandomness) / 1000.0f; } mVelocity.z -= mGravity; // Update position mPos.x += mVelocity.x; mPos.y += mVelocity.y * SIN45; mPos.z += mVelocity.z * SIN45; // Update other stuff if (mLifetimeLeft > 0) { mLifetimeLeft--; } mLifetimePast++; if (mPos.z < 0.0f) { if (mBounce > 0.0f) { mPos.z *= -mBounce; mVelocity *= mBounce; mVelocity.z = -mVelocity.z; } else { mAlive = DEAD_FLOOR; } } else if (mPos.z > PARTICLE_SKY) { mAlive = DEAD_SKY; } // Update child emitters if ((mLifetimePast-1)%Particle::emitterSkip == 0) { for (EmitterIterator e = mChildEmitters.begin(); e != mChildEmitters.end(); e++) { Particles newParticles = (*e)->createParticles(mLifetimePast); for (ParticleIterator p = newParticles.begin(); p != newParticles.end(); p++) { (*p)->moveBy(mPos); mChildParticles.push_back (*p); } } } } // create death effect when the particle died if (mAlive != ALIVE && mAlive != DEAD_LONG_AGO) { if ((mAlive & mDeathEffectConditions) > 0x00 && !mDeathEffect.empty()) { Particle* deathEffect = particleEngine->addEffect(mDeathEffect, 0, 0); deathEffect->moveBy(mPos); } mAlive = DEAD_LONG_AGO; } Vector change = mPos - oldPos; // Update child particles for (ParticleIterator p = mChildParticles.begin(); p != mChildParticles.end();) { //move particle with its parent if desired if ((*p)->doesFollow()) { (*p)->moveBy(change); } //update particle if ((*p)->update()) { p++; } else { delete (*p); p = mChildParticles.erase(p); } } if (mAlive != ALIVE && mChildParticles.empty() && mAutoDelete) { return false; } return true; }