static inline F32 mCbrt(F32 val) { if(val < 0.f) return(-mPow(-val, F32(1.f/3.f))); else return(mPow(val, F32(1.f/3.f))); }
void PSSMLightShadowMap::_calcSplitPos(const Frustum& currFrustum) { const F32 nearDist = 0.01f; // TODO: Should this be adjustable or different? const F32 farDist = currFrustum.getFarDist(); for ( U32 i = 1; i < mNumSplits; i++ ) { F32 step = (F32) i / (F32) mNumSplits; F32 logSplit = nearDist * mPow(farDist / nearDist, step); F32 linearSplit = nearDist + (farDist - nearDist) * step; mSplitDist[i] = mLerp( linearSplit, logSplit, mClampF( mLogWeight, 0.0f, 1.0f ) ); } mSplitDist[0] = nearDist; mSplitDist[mNumSplits] = farDist; }
ScatterSky::ScatterSky() { mPrimCount = 0; mVertCount = 0; // Rayleigh scattering constant. mRayleighScattering = 0.0035f; mRayleighScattering4PI = mRayleighScattering * 4.0f * M_PI_F; // Mie scattering constant. mMieScattering = 0.0045f; mMieScattering4PI = mMieScattering * 4.0f * M_PI_F; // Overall scatter scalar. mSkyBrightness = 25.0f; // The Mie phase asymmetry factor. mMiePhaseAssymetry = -0.75f; mSphereInnerRadius = 1.0f; mSphereOuterRadius = 1.0f * 1.025f; mScale = 1.0f / (mSphereOuterRadius - mSphereInnerRadius); // 650 nm for red // 570 nm for green // 475 nm for blue mWavelength.set( 0.650f, 0.570f, 0.475f, 0 ); mWavelength4[0] = mPow(mWavelength[0], 4.0f); mWavelength4[1] = mPow(mWavelength[1], 4.0f); mWavelength4[2] = mPow(mWavelength[2], 4.0f); mRayleighScaleDepth = 0.25f; mMieScaleDepth = 0.1f; mAmbientColor.set( 0, 0, 0, 1.0f ); mAmbientScale.set( 1.0f, 1.0f, 1.0f, 1.0f ); mSunColor.set( 0, 0, 0, 1.0f ); mSunScale = ColorF::WHITE; mFogColor.set( 0, 0, 0, 1.0f ); mFogScale = ColorF::WHITE; mExposure = 1.0f; mNightInterpolant = 0; mShader = NULL; mTimeOfDay = 0; mSunAzimuth = 0.0f; mSunElevation = 35.0f; mMoonAzimuth = 0.0f; mMoonElevation = 45.0f; mBrightness = 1.0f; mCastShadows = true; mDirty = true; mLight = LightManager::createLightInfo(); mLight->setType( LightInfo::Vector ); mFlareData = NULL; mFlareState.clear(); mFlareScale = 1.0f; mMoonEnabled = true; mMoonScale = 0.2f; mMoonTint.set( 0.192157f, 0.192157f, 0.192157f, 1.0f ); MathUtils::getVectorFromAngles( mMoonLightDir, 0.0f, 45.0f ); mMoonLightDir.normalize(); mMoonLightDir = -mMoonLightDir; mNightCubemap = NULL; mNightColor.set( 0.0196078f, 0.0117647f, 0.109804f, 1.0f ); mNightFogColor = mNightColor; mUseNightCubemap = false; mSunSize = 1.0f; mMoonMatInst = NULL; mNetFlags.set( Ghostable | ScopeAlways ); mTypeMask |= EnvironmentObjectType | LightObjectType | StaticObjectType; _generateSkyPoints(); mMatrixSet = reinterpret_cast<MatrixSet *>(dMalloc_aligned(sizeof(MatrixSet), 16)); constructInPlace(mMatrixSet); mColorizeAmt = 0; mColorize.set(0,0,0); }
void ScatterSky::unpackUpdate(NetConnection *con, BitStream *stream) { Parent::unpackUpdate(con, stream); if ( stream->readFlag() ) // TimeMask { F32 temp = 0; stream->read( &temp ); setAzimuth( temp ); stream->read( &temp ); setElevation( temp ); } if ( stream->readFlag() ) // UpdateMask { stream->read( &mRayleighScattering ); stream->read( &mRayleighScattering4PI ); stream->read( &mMieScattering ); stream->read( &mMieScattering4PI ); stream->read( &mSunSize ); stream->read( &mSkyBrightness ); stream->read( &mMiePhaseAssymetry ); stream->read( &mSphereInnerRadius ); stream->read( &mSphereOuterRadius ); stream->read( &mScale ); ColorF tmpColor( 0, 0, 0 ); stream->read( &tmpColor ); stream->read( &mWavelength4[0] ); stream->read( &mWavelength4[1] ); stream->read( &mWavelength4[2] ); stream->read( &mRayleighScaleDepth ); stream->read( &mMieScaleDepth ); stream->read( &mNightColor ); stream->read( &mNightFogColor ); stream->read( &mAmbientScale ); stream->read( &mSunScale ); stream->read( &mFogScale ); F32 colorizeAmt; stream->read( &colorizeAmt ); if(mColorizeAmt != colorizeAmt) { mColorizeAmt = colorizeAmt; mShader = NULL; //forces shader refresh } stream->read( &mColorize ); if ( tmpColor != mWavelength ) { mWavelength = tmpColor; mWavelength4[0] = mPow(mWavelength[0], 4.0f); mWavelength4[1] = mPow(mWavelength[1], 4.0f); mWavelength4[2] = mPow(mWavelength[2], 4.0f); } stream->read( &mExposure ); stream->read( &mBrightness ); mCastShadows = stream->readFlag(); stream->read( &mFlareScale ); if ( stream->readFlag() ) { SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); LightFlareData *datablock = NULL; if ( Sim::findObject( id, datablock ) ) mFlareData = datablock; else { con->setLastError( "ScatterSky::unpackUpdate() - invalid LightFlareData!" ); mFlareData = NULL; } } else mFlareData = NULL; mMoonEnabled = stream->readFlag(); stream->read( &mMoonMatName ); stream->read( &mMoonScale ); stream->read( &mMoonTint ); mUseNightCubemap = stream->readFlag(); stream->read( &mNightCubemapName ); stream->read( &mMoonAzimuth ); stream->read( &mMoonElevation ); mLight->unpackExtended( stream ); if ( isProperlyAdded() ) { mDirty = true; _initMoon(); Sim::findObject( mNightCubemapName, mNightCubemap ); } } }
F32 ScatterSky::_getMiePhase( F32 fCos, F32 fCos2, F32 g, F32 g2) { return 1.5f * ((1.0f - g2) / (2.0f + g2)) * (1.0f + fCos2) / mPow(mFabs(1.0f + g2 - 2.0f*g*fCos), 1.5f); }
void LightFlareData::prepRender( SceneRenderState *state, LightFlareState *flareState ) { PROFILE_SCOPE( LightFlareData_prepRender ); const LightInfo *lightInfo = flareState->lightInfo; if ( mIsZero( flareState->fullBrightness ) || mIsZero( lightInfo->getBrightness() ) ) return; // Figure out the element count to render. U32 elementCount = mElementCount; const bool isReflectPass = state->isReflectPass(); if ( isReflectPass ) { // Then we don't render anything this pass. if ( !mRenderReflectPass ) return; // Find the zero distance elements which make // up the corona of the light flare. elementCount = 0.0f; for ( U32 i=0; i < mElementCount; i++ ) if ( mIsZero( mElementDist[i] ) ) elementCount++; } // Better have something to render. if ( elementCount == 0 ) return; U32 visDelta = U32_MAX; F32 occlusionFade = 1.0f; Point3F lightPosSS; bool lightVisible = _testVisibility( state, flareState, &visDelta, &occlusionFade, &lightPosSS ); // We can only skip rendering if the light is not // visible, and it has elapsed the fade out time. if ( mIsZero( occlusionFade ) || !lightVisible && visDelta > FadeOutTime ) return; const RectI &viewport = GFX->getViewport(); Point3F oneOverViewportExtent( 1.0f / (F32)viewport.extent.x, 1.0f / (F32)viewport.extent.y, 0.0f ); // Really convert it to screen space. lightPosSS.x -= viewport.point.x; lightPosSS.y -= viewport.point.y; lightPosSS *= oneOverViewportExtent; lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One; lightPosSS.y = -lightPosSS.y; lightPosSS.z = 0.0f; // Take any projection offset into account so that the point where the flare's // elements converge is at the 'eye' point rather than the center of the viewport. const Point2F& projOffset = state->getCameraFrustum().getProjectionOffset(); Point3F flareVec( -lightPosSS + Point3F(projOffset.x, projOffset.y, 0.0f) ); const F32 flareLength = flareVec.len(); if ( flareLength > 0.0f ) flareVec *= 1.0f / flareLength; // Setup the flare quad points. Point3F rotatedBasePoints[4]; dMemcpy(rotatedBasePoints, sBasePoints, sizeof( sBasePoints )); // Rotate the flare quad. F32 rot = mAcos( -1.0f * flareVec.x ); rot *= flareVec.y > 0.0f ? -1.0f : 1.0f; MathUtils::vectorRotateZAxis( rot, rotatedBasePoints, 4 ); // Here we calculate a the light source's influence on // the effect's size and brightness. // Scale based on the current light brightness compared to its normal output. F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness; const Point3F &camPos = state->getCameraPosition(); const Point3F &lightPos = flareState->lightMat.getPosition(); const bool isVectorLight = lightInfo->getType() == LightInfo::Vector; // Scale based on world space distance from camera to light source. F32 distToCamera = ( camPos - lightPos ).len(); F32 lightSourceWSDistanceScale = isVectorLight && distToCamera > 0.0f ? 1.0f : getMin( 10.0f / distToCamera, 10.0f ); // Scale based on screen space distance from screen position of light source to the screen center. F32 lightSourceSSDistanceScale = getMax( ( 1.5f - flareLength ) / 1.5f, 0.0f ); // Scale based on recent visibility changes, fading in or out. F32 fadeInOutScale = 1.0f; if ( lightVisible && visDelta < FadeInTime && flareState->occlusion > 0.0f ) fadeInOutScale = (F32)visDelta / (F32)FadeInTime; else if ( !lightVisible && visDelta < FadeOutTime ) fadeInOutScale = 1.0f - (F32)visDelta / (F32)FadeOutTime; // This combined scale influences the size of all elements this effect renders. // Note we also add in a scale that is user specified in the Light. F32 lightSourceIntensityScale = lightSourceBrightnessScale * lightSourceWSDistanceScale * lightSourceSSDistanceScale * fadeInOutScale * flareState->scale * occlusionFade; if ( mIsZero( lightSourceIntensityScale ) ) return; // The baseColor which modulates the color of all elements. // // These are the factors which affect the "alpha" of the flare effect. // Modulate more in as appropriate. ColorF baseColor = ColorF::WHITE * lightSourceBrightnessScale * occlusionFade; // Setup the vertex buffer for the maximum flare elements. const U32 vertCount = 4 * mElementCount; if ( flareState->vertBuffer.isNull() || flareState->vertBuffer->mNumVerts != vertCount ) flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic ); GFXVertexPCT *vert = flareState->vertBuffer.lock(); const Point2F oneOverTexSize( 1.0f / (F32)mFlareTexture.getWidth(), 1.0f / (F32)mFlareTexture.getHeight() ); for ( U32 i = 0; i < mElementCount; i++ ) { // Skip non-zero elements for reflections. if ( isReflectPass && mElementDist[i] > 0.0f ) continue; Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : sBasePoints; ColorF color( baseColor * mElementTint[i] ); if ( mElementUseLightColor[i] ) color *= lightInfo->getColor(); color.clamp(); Point3F pos( lightPosSS + flareVec * mElementDist[i] * flareLength ); const RectF &rect = mElementRect[i]; Point3F size( rect.extent.x, rect.extent.y, 1.0f ); size *= mElementScale[i] * mScale * lightSourceIntensityScale; AssertFatal( size.x >= 0.0f, "LightFlareData::prepRender - Got a negative element size?" ); if ( size.x < 100.0f ) { F32 alphaScale = mPow( size.x / 100.0f, 2 ); color *= alphaScale; } Point2F texCoordMin, texCoordMax; texCoordMin = rect.point * oneOverTexSize; texCoordMax = ( rect.point + rect.extent ) * oneOverTexSize; size.x = getMax( size.x, 1.0f ); size.y = getMax( size.y, 1.0f ); size *= oneOverViewportExtent; vert->color = color; vert->point = ( basePos[0] * size ) + pos; vert->texCoord.set( texCoordMin.x, texCoordMax.y ); vert++; vert->color = color; vert->point = ( basePos[1] * size ) + pos; vert->texCoord.set( texCoordMax.x, texCoordMax.y ); vert++; vert->color = color; vert->point = ( basePos[2] * size ) + pos; vert->texCoord.set( texCoordMax.x, texCoordMin.y ); vert++; vert->color = color; vert->point = ( basePos[3] * size ) + pos; vert->texCoord.set( texCoordMin.x, texCoordMin.y ); vert++; } flareState->vertBuffer.unlock(); RenderPassManager *rpm = state->getRenderPass(); // Create and submit the render instance. ParticleRenderInst *ri = rpm->allocInst<ParticleRenderInst>(); ri->type = RenderPassManager::RIT_Particle; ri->vertBuff = &flareState->vertBuffer; ri->primBuff = &mFlarePrimBuffer; ri->translucentSort = true; ri->sortDistSq = ( lightPos - camPos ).lenSquared(); ri->modelViewProj = &MatrixF::Identity; ri->bbModelViewProj = &MatrixF::Identity; ri->count = elementCount; ri->blendStyle = ParticleRenderInst::BlendGreyscale; ri->diffuseTex = mFlareTexture; ri->softnessDistance = 1.0f; ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff; // Sort by texture too. // NOTE: Offscreen partical code is currently disabled. ri->systemState = PSS_AwaitingHighResDraw; rpm->addInst( ri ); }
void PxSingleActor::_updateContainerForces() { if ( !mWorld->getEnabled() ) return; PROFILE_SCOPE( PxSingleActor_updateContainerForces ); // Update container drag and buoyancy properties ContainerQueryInfo info; info.box = getWorldBox(); info.mass = getMass(); // Find and retreive physics info from intersecting WaterObject(s) mContainer->findObjects( getWorldBox(), WaterObjectType|PhysicalZoneObjectType, findRouter, &info ); // Calculate buoyancy and drag F32 angDrag = mBuildAngDrag; F32 linDrag = mBuildLinDrag; F32 buoyancy = 0.0f; if ( true ) //info.waterCoverage >= 0.1f) { F32 waterDragScale = info.waterViscosity * mDataBlock->waterDragScale; F32 powCoverage = mPow( info.waterCoverage, 0.25f ); if ( info.waterCoverage > 0.0f ) { //angDrag = mBuildAngDrag * waterDragScale; //linDrag = mBuildLinDrag * waterDragScale; angDrag = mLerp( mBuildAngDrag, mBuildAngDrag * waterDragScale, powCoverage ); linDrag = mLerp( mBuildLinDrag, mBuildLinDrag * waterDragScale, powCoverage ); } buoyancy = ( info.waterDensity / mDataBlock->buoyancyDensity ) * mPow( info.waterCoverage, 2.0f ); } // Apply drag (dampening) mActor->setLinearDamping( linDrag ); mActor->setAngularDamping( angDrag ); // Apply buoyancy force if ( buoyancy != 0 ) { // A little hackery to prevent oscillation // Based on this blog post (http://reinot.blogspot.com/2005/11/oh-yes-they-float-georgie-they-all.html) // JCF: DISABLED NxVec3 gravity; mWorld->getScene()->getGravity(gravity); //NxVec3 velocity = mActor->getLinearVelocity(); NxVec3 buoyancyForce = buoyancy * -gravity * TickSec; //F32 currHeight = getPosition().z; //const F32 C = 2.0f; //const F32 M = 0.1f; //if ( currHeight + velocity.z * TickSec * C > info.waterHeight ) // buoyancyForce *= M; mActor->addForceAtPos( buoyancyForce, mActor->getCMassGlobalPosition(), NX_IMPULSE ); } // Apply physical zone forces if ( info.appliedForce.len() > 0.001f ) mActor->addForceAtPos( pxCast<NxVec3>(info.appliedForce), mActor->getCMassGlobalPosition(), NX_IMPULSE ); }
void pow(wint p){ mPow(res,mat,p); memcpy(mat,res,n*size*sizeof(tmp[0][0])); }
void LightFlareData::prepRender( SceneState *state, LightFlareState *flareState ) { PROFILE_SCOPE( LightFlareData_prepRender ); // No elements then nothing to render. if ( mElementCount == 0 ) return; // We need these all over the place later. const Point3F &camPos = state->getCameraPosition(); const RectI &viewport = GFX->getViewport(); const Point3F &lightPos = flareState->lightMat.getPosition(); LightInfo *lightInfo = flareState->lightInfo; bool isVectorLight = lightInfo->getType() == LightInfo::Vector; // Perform visibility testing on the light... // Project the light position from world to screen space, we need this // position later, and it tells us if it is actually onscreen. Point3F lightPosSS; bool onscreen = MathUtils::mProjectWorldToScreen( lightPos, &lightPosSS, viewport, GFX->getWorldMatrix(), gClientSceneGraph->getNonClipProjection() ); U32 visDelta = U32_MAX; U32 fadeOutTime = 20; U32 fadeInTime = 125; // Fade factor based on amount of occlusion. F32 occlusionFade = 1.0f; bool lightVisible = true; if ( !state->isReflectPass() ) { // It is onscreen, so raycast as a simple occlusion test. U32 losMask = STATIC_COLLISION_MASK | ShapeBaseObjectType | StaticTSObjectType | ItemObjectType | PlayerObjectType; GameConnection *conn = GameConnection::getConnectionToServer(); if ( !conn ) return; bool needsRaycast = true; // NOTE: if hardware does not support HOQ it will return NULL // and we will retry every time but there is not currently a good place // for one-shot initialization of LightFlareState if ( flareState->occlusionQuery == NULL ) flareState->occlusionQuery = GFX->createOcclusionQuery(); if ( flareState->fullPixelQuery == NULL ) flareState->fullPixelQuery = GFX->createOcclusionQuery(); if ( flareState->occlusionQuery && ( ( isVectorLight && flareState->worldRadius > 0.0f ) || ( !isVectorLight && mOcclusionRadius > 0.0f ) ) ) { // Always treat light as onscreen if using HOQ // it will be faded out if offscreen anyway. onscreen = true; U32 pixels = -1; GFXOcclusionQuery::OcclusionQueryStatus status = flareState->occlusionQuery->getStatus( true, &pixels ); String str = flareState->occlusionQuery->statusToString( status ); Con::setVariable( "$Flare::OcclusionStatus", str.c_str() ); Con::setIntVariable( "$Flare::OcclusionVal", pixels ); if ( status == GFXOcclusionQuery::Occluded ) occlusionFade = 0.0f; if ( status != GFXOcclusionQuery::Unset ) needsRaycast = false; RenderPassManager *pass = state->getRenderPass(); OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>(); Point3F scale( Point3F::One ); if ( isVectorLight && flareState->worldRadius > 0.0f ) scale *= flareState->worldRadius; else scale *= mOcclusionRadius; ri->type = RenderPassManager::RIT_Occluder; ri->query = flareState->occlusionQuery; ri->query2 = flareState->fullPixelQuery; ri->position = lightPos; ri->scale = scale; ri->orientation = pass->allocUniqueXform( lightInfo->getTransform() ); ri->isSphere = true; state->getRenderPass()->addInst( ri ); if ( status == GFXOcclusionQuery::NotOccluded ) { U32 fullPixels; flareState->fullPixelQuery->getStatus( true, &fullPixels ); occlusionFade = (F32)pixels / (F32)fullPixels; // Approximation of the full pixel count rather than doing // two queries, but it is not very accurate. /* F32 dist = ( camPos - lightPos ).len(); F32 radius = scale.x; radius = ( radius / dist ) * state->getWorldToScreenScale().y; occlusionFade = (F32)pixels / (4.0f * radius * radius); occlusionFade = mClampF( occlusionFade, 0.0f, 1.0f ); */ } } Con::setFloatVariable( "$Flare::OcclusionFade", occlusionFade ); if ( needsRaycast ) { // Use a raycast to determine occlusion. bool fps = conn->isFirstPerson(); GameBase *control = conn->getControlObject(); if ( control && fps ) control->disableCollision(); RayInfo rayInfo; if ( gClientContainer.castRayRendered( camPos, lightPos, losMask, &rayInfo ) ) occlusionFade = 0.0f; if ( control && fps ) control->enableCollision(); } lightVisible = onscreen && occlusionFade > 0.0f; // To perform a fade in/out when we gain or lose visibility // we must update/store the visibility state and time. U32 currentTime = Sim::getCurrentTime(); if ( lightVisible != flareState->visible ) { flareState->visible = lightVisible; flareState->visChangedTime = currentTime; } // Save this in the state so that we have it during the reflect pass. flareState->occlusion = occlusionFade; visDelta = currentTime - flareState->visChangedTime; } else // state->isReflectPass() { occlusionFade = flareState->occlusion; lightVisible = flareState->visible; visDelta = Sim::getCurrentTime() - flareState->visChangedTime; } // We can only skip rendering if the light is not visible, and it // has elapsed the fadeOutTime. if ( !lightVisible && visDelta > fadeOutTime ) return; // In a reflection we only render the elements with zero distance. U32 elementCount = mElementCount; if ( state->isReflectPass() ) { elementCount = 0; for ( ; elementCount < mElementCount; elementCount++ ) { if ( mElementDist[elementCount] > 0.0f ) break; } } if ( elementCount == 0 ) return; // A bunch of preparatory math before generating verts... const Point2I &vpExtent = viewport.extent; Point3F viewportExtent( vpExtent.x, vpExtent.y, 1.0f ); Point2I halfViewportExtentI( viewport.extent / 2 ); Point3F halfViewportExtentF( (F32)halfViewportExtentI.x * 0.5f, (F32)halfViewportExtentI.y, 0.0f ); Point3F screenCenter( 0,0,0 ); Point3F oneOverViewportExtent( 1.0f / viewportExtent.x, 1.0f / viewportExtent.y, 1.0f ); lightPosSS.y -= viewport.point.y; lightPosSS *= oneOverViewportExtent; lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One; lightPosSS.y = -lightPosSS.y; lightPosSS.z = 0.0f; Point3F flareVec( screenCenter - lightPosSS ); F32 flareLength = flareVec.len(); flareVec.normalizeSafe(); Point3F basePoints[4]; basePoints[0] = Point3F( -0.5, 0.5, 0.0 ); basePoints[1] = Point3F( -0.5, -0.5, 0.0 ); basePoints[2] = Point3F( 0.5, -0.5, 0.0 ); basePoints[3] = Point3F( 0.5, 0.5, 0.0 ); Point3F rotatedBasePoints[4]; rotatedBasePoints[0] = basePoints[0]; rotatedBasePoints[1] = basePoints[1]; rotatedBasePoints[2] = basePoints[2]; rotatedBasePoints[3] = basePoints[3]; Point3F fvec( -1, 0, 0 ); F32 rot = mAcos( mDot( fvec, flareVec ) ); Point3F rvec( 0, -1, 0 ); rot *= mDot( rvec, flareVec ) > 0.0f ? 1.0f : -1.0f; vectorRotateZAxis( rotatedBasePoints[0], rot ); vectorRotateZAxis( rotatedBasePoints[1], rot ); vectorRotateZAxis( rotatedBasePoints[2], rot ); vectorRotateZAxis( rotatedBasePoints[3], rot ); // Here we calculate a the light source's influence on the effect's size // and brightness... // Scale based on the current light brightness compared to its normal output. F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness; // Scale based on world space distance from camera to light source. F32 lightSourceWSDistanceScale = ( isVectorLight ) ? 1.0f : getMin( 10.0f / ( lightPos - camPos ).len(), 1.5f ); // Scale based on screen space distance from screen position of light source to the screen center. F32 lightSourceSSDistanceScale = ( 1.5f - ( lightPosSS - screenCenter ).len() ) / 1.5f; // Scale based on recent visibility changes, fading in or out. F32 fadeInOutScale = 1.0f; if ( lightVisible && visDelta < fadeInTime && flareState->occlusion ) fadeInOutScale = (F32)visDelta / (F32)fadeInTime; else if ( !lightVisible && visDelta < fadeOutTime ) fadeInOutScale = 1.0f - (F32)visDelta / (F32)fadeOutTime; // This combined scale influences the size of all elements this effect renders. // Note we also add in a scale that is user specified in the Light. F32 lightSourceIntensityScale = lightSourceBrightnessScale * lightSourceWSDistanceScale * lightSourceSSDistanceScale * fadeInOutScale * flareState->scale * occlusionFade; // The baseColor which modulates the color of all elements. ColorF baseColor; if ( flareState->fullBrightness == 0.0f ) baseColor = ColorF::BLACK; else // These are the factors which affect the "alpha" of the flare effect. // Modulate more in as appropriate. baseColor = ColorF::WHITE * lightSourceBrightnessScale * occlusionFade; // Fill in the vertex buffer... const U32 vertCount = 4 * elementCount; if ( flareState->vertBuffer.isNull() || flareState->vertBuffer->mNumVerts != vertCount ) flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic ); GFXVertexPCT *pVert = flareState->vertBuffer.lock(); const Point2I &widthHeightI = mFlareTexture.getWidthHeight(); Point2F oneOverTexSize( 1.0f / (F32)widthHeightI.x, 1.0f / (F32)widthHeightI.y ); for ( U32 i = 0; i < elementCount; i++ ) { Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : basePoints; ColorF elementColor( baseColor * mElementTint[i] ); if ( mElementUseLightColor[i] ) elementColor *= lightInfo->getColor(); Point3F elementPos; elementPos = lightPosSS + flareVec * mElementDist[i] * flareLength; elementPos.z = 0.0f; F32 maxDist = 1.5f; F32 elementDist = mSqrt( ( elementPos.x * elementPos.x ) + ( elementPos.y * elementPos.y ) ); F32 distanceScale = ( maxDist - elementDist ) / maxDist; distanceScale = 1.0f; const RectF &elementRect = mElementRect[i]; Point3F elementSize( elementRect.extent.x, elementRect.extent.y, 1.0f ); elementSize *= mElementScale[i] * distanceScale * mScale * lightSourceIntensityScale; if ( elementSize.x < 100.0f ) { F32 alphaScale = mPow( elementSize.x / 100.0f, 2 ); elementColor *= alphaScale; } elementColor.clamp(); Point2F texCoordMin, texCoordMax; texCoordMin = elementRect.point * oneOverTexSize; texCoordMax = ( elementRect.point + elementRect.extent ) * oneOverTexSize; pVert->color = elementColor; pVert->point = ( basePos[0] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMin.x, texCoordMax.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[1] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMax.x, texCoordMax.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[2] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMax.x, texCoordMin.y ); pVert++; pVert->color = elementColor; pVert->point = ( basePos[3] * elementSize * oneOverViewportExtent ) + elementPos; pVert->texCoord.set( texCoordMin.x, texCoordMin.y ); pVert++; } flareState->vertBuffer.unlock(); // Create and submit the render instance... RenderPassManager *renderManager = state->getRenderPass(); ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>(); ri->vertBuff = &flareState->vertBuffer; ri->primBuff = &mFlarePrimBuffer; ri->translucentSort = true; ri->type = RenderPassManager::RIT_Particle; ri->sortDistSq = ( lightPos - camPos ).lenSquared(); ri->modelViewProj = &MatrixF::Identity; ri->bbModelViewProj = ri->modelViewProj; ri->count = elementCount; // Only draw the light flare in high-res mode, never off-screen mode ri->systemState = ParticleRenderInst::AwaitingHighResDraw; ri->blendStyle = ParticleRenderInst::BlendGreyscale; ri->diffuseTex = &*(mFlareTexture); ri->softnessDistance = 1.0f; // Sort by texture too. ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff; renderManager->addInst( ri ); }