void VTerrainVisibilityInfo::Set(IVisVisibilityCollector_cl *pCollector,const VTerrainConfig &config) { hkvVec3 vCamPos(hkvNoInitialization), vCamDir(hkvNoInitialization); pCollector->GetSourceObject()->GetPosition(vCamPos); vCamDir = pCollector->GetSourceObject()->GetDirection(); VisRenderContext_cl *pLODContext = pCollector->GetLODReferenceRenderContext(); VASSERT(pLODContext!=NULL && pLODContext->GetCamera()!=NULL); pLODContext->GetCamera()->GetPosition(m_vCamLODPos); m_vCamPos.FromRenderSpace(config,(const hkvVec3& )vCamPos); m_vCamVisPos = vCamPos; m_CameraPlane.setFromPointAndNormal(vCamPos,vCamDir); VASSERT(m_vCamPos.IsValid(config)); // compute the rest float fNear,fFar; pCollector->GetClipPlanes(fNear,fFar); m_fMaxViewDistance = fFar; m_fLODDistanceInvScale = pLODContext->GetLODDistanceScaling() * VTerrainSectorManager::g_fDecorationDistanceInvScaling; if (m_fLODDistanceInvScale>0.f) m_fLODDistanceScale = 1.f/m_fLODDistanceInvScale; else m_fLODDistanceScale = 0.f; // overestimate config.GetViewDistanceBox(m_CamBBox, m_vCamVisPos, fFar); m_VisibleRangeBox.FromRenderSpace(config,m_CamBBox); m_iContextFilterMask = pCollector->GetFilterBitmask(); // reset min/max m_iVisibleSectorRange[0] = m_iVisibleSectorRange[1] = 32000; m_iVisibleSectorRange[2] = m_iVisibleSectorRange[3] = -32000; // reset some of the values: m_iVisibleDecorationCount = 0; m_iEstimatedDecorationCount = 0; static bool bEnableOpt = true; // shadowmap related: if (bEnableOpt && pCollector->GetTypeId()==V_RUNTIME_CLASS(VShadowmapVisibilityCollector)) { m_pSMGenerator = ((VShadowmapVisibilityCollector *)pCollector)->m_pSMGenerator; float fShadowExtrusionFactor = m_pSMGenerator->GetShadowMapComponent()->GetShadowBoxExtrudeMultiplier(); m_vShadowExtrusion = m_pSMGenerator->GetDirection(); if (m_vShadowExtrusion.z<-0.01f) // normalize height m_vShadowExtrusion.z *= (-1.f/m_vShadowExtrusion.z); m_vShadowExtrusion *= fShadowExtrusionFactor; m_bCastDynamicShadows = (m_pSMGenerator->GetShadowMapComponent()->GetGeometryTypes()&SHADOW_CASTER_TERRAIN)>0; } else m_pSMGenerator = NULL; }
int VMobileForwardRenderLoop::GetLightInfluenceArea(VisLightSource_cl *pLight) { VASSERT(pLight != NULL); VisRenderContext_cl *pContext = VisRenderContext_cl::GetCurrentContext(); int iScreenWidth,iScreenHeight; pContext->GetSize(iScreenWidth, iScreenHeight); if (pLight->GetType() == VIS_LIGHT_DIRECTED) { // directional lights influence the whole screen return (iScreenWidth*iScreenHeight); } hkvMat4 projMatrix = pContext->GetViewProperties()->getProjectionMatrix(hkvClipSpaceYRange::MinusOneToOne); hkvMat4 viewMatrix = pContext->GetCamera()->GetWorldToCameraTransformation(); // get position/ radius of bounding sphere hkvVec3 vPosition; float fRadius = 0.0f; if (pLight->GetType() == VIS_LIGHT_POINT) { vPosition = pLight->GetPosition(); fRadius = pLight->GetRadius(); } else if (pLight->GetType() == VIS_LIGHT_SPOTLIGHT) { hkvAlignedBBox bBox; pLight->GetBoundingBox(bBox); vPosition = bBox.getBoundingSphere().m_vCenter; fRadius = bBox.getBoundingSphere().m_fRadius; } else VASSERT_MSG(false, "Unsupported light type"); // get corners of bounding rectangle in view space hkvVec4 vPositionVS = viewMatrix*vPosition.getAsVec4(1.0f); hkvVec4 vCorners[4]; vCorners[0] = vPositionVS+hkvVec4(-fRadius, -fRadius, 0.0f, 0.0f); vCorners[1] = vPositionVS+hkvVec4(fRadius, -fRadius, 0.0f, 0.0f); vCorners[2] = vPositionVS+hkvVec4(fRadius, fRadius, 0.0f, 0.0f); vCorners[3] = vPositionVS+hkvVec4(-fRadius, fRadius, 0.0f, 0.0f); // get corners of bounding rectangle in normalized device coordinates for (int i=0;i<4;i++) { vCorners[i] = projMatrix*vCorners[i]; vCorners[i] /= vCorners[i].w; } // clip corners of bounding rectangle hkvVec2 vMin(vCorners[0].x, vCorners[0].y); vMin.clampTo(hkvVec2(-1.0f, -1.0f), hkvVec2(1.0f, 1.0f)); hkvVec2 vMax(vCorners[2].x, vCorners[2].y); vMax.clampTo(hkvVec2(-1.0f, -1.0f), hkvVec2(1.0f, 1.0f)); // calculate influence area int iWidth = (int)((vMax.x-vMin.x)*0.5f*iScreenWidth); int iHeight = (int)((vMax.y-vMin.y)*0.5f*iScreenHeight); return (iWidth*iHeight); }
void VMobileForwardRenderLoop::DetermineRelevantLights() { m_DynamicLightCollection.Clear(); m_pBasePassLight = NULL; m_iBasePassLightPriority = 0; // Get all visible light sources IVisVisibilityCollector_cl *pVisColl = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector(); if (pVisColl == NULL) return; const VisLightSrcCollection_cl *pLightSourceCollection = pVisColl->GetVisibleLights(); if (pLightSourceCollection == NULL) return; unsigned int iNumLights = pLightSourceCollection->GetNumEntries(); if (iNumLights == 0) return; VisRenderContext_cl *pContext = VisRenderContext_cl::GetCurrentContext(); const hkvVec3 &vCamPos = pContext->GetCamera()->GetPosition(); for (unsigned i=0;i<iNumLights;i++) { VisLightSource_cl *pLight = pLightSourceCollection->GetEntry(i); // We are only interested in dynamic lights or static lights with attached shadow map component if ((!pLight->IsDynamic() && !GetCompatibleShadowMapComponent(pLight)) || pLight->GetRadius()<=HKVMATH_LARGE_EPSILON) continue; const float fFade = pLight->GetMultiplier()*pLight->GetFadeWeight(vCamPos); if (fFade <= HKVMATH_LARGE_EPSILON) continue; // See which geometry types have to cast shadows int iReceiverFlags = GetLightReceiverFlags(pLight); // If nothing receives light from this light source, we can proceed to the next light. if (!iReceiverFlags) continue; // Find light with highest priority. This light will be rendered in the base pass, in contrast to all // additional lights that are rendered additively after the base pass. The search ignores lights with // attached light clipping volume, since light clipping volumes can't be rendered before the base pass. if (!pLight->HasClipVolumeComponent()) { // get the light with highest priority (largest influence area in screen space combined with weighting factor) int iLightPriority = GetLightPriority(pLight); if (iLightPriority > m_iBasePassLightPriority) { m_pBasePassLight = pLight; m_iBasePassLightPriority = iLightPriority; } } if (pLight->IsDynamic()) m_DynamicLightCollection.AppendEntry(pLight); } }
void VLensFlareComponent::UpdateVisibility (float& fLastVisibilityQuery, float& fCurrentVisibility) { // Make sure we are actually attached to an object if (GetOwner()) { // Get Camera VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext(); const hkvVec3 vCameraPos = pContext->GetCamera()->GetPosition(); // Get Light VisLightSource_cl* pLight = (VisLightSource_cl*)GetOwner(); hkvVec3 vPos; pLight->GetVirtualPosition( vPos, pContext ); hkvVec3 vDist = vCameraPos - vPos; float fDist = vDist.getLength(); float fFactor = 1.0f; // Distance FadeOut if (FadeOutEnd != 0 && FadeOutStart < FadeOutEnd) { if (fDist > FadeOutEnd) { fFactor = 0.0f; } else if (fDist > FadeOutStart) { fFactor = 1.0f - (fDist - FadeOutStart) / (FadeOutEnd - FadeOutStart); } } // Apply distance fade out fLastVisibilityQuery *= fFactor; // PreGlow/AfterGlow if (fLastVisibilityQuery > fCurrentVisibility) { float fSpeed = Vision::GetTimer()->GetTimeDifference() / ((PreGlowMS + 1) * 0.001f); fCurrentVisibility = hkvMath::Min(fCurrentVisibility + fSpeed, fLastVisibilityQuery); } else if (fLastVisibilityQuery < fCurrentVisibility) { float fSpeed = Vision::GetTimer()->GetTimeDifference() / ((AfterGlowMS + 1) * 0.001f); fCurrentVisibility = hkvMath::Max(fCurrentVisibility - fSpeed, fLastVisibilityQuery); } fCurrentVisibility = hkvMath::clamp(fCurrentVisibility, 0.0f, 1.0f); } }
bool VOcclusionQueryObjectPixelCounterLensFlare::Render(VOcclusionQuery &query, const hkvAlignedBBox &safeBox) { if (m_pLensFlare != NULL && m_pLensFlare->GetOwner() != NULL) { SetState(VISQUERY_RENDERSTATE_BILLBOARD); VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext(); VisLightSource_cl* pLight = (VisLightSource_cl*)m_pLensFlare->GetOwner(); hkvVec3 vPos(hkvNoInitialization); pLight->GetVirtualPosition(vPos, pContext); hkvVec3 vCameraDir = pContext->GetCamera()->GetPosition() - vPos; vCameraDir /= hkvMath::Max(vCameraDir.getLength(), HKVMATH_LARGE_EPSILON); vPos += vCameraDir * m_pLensFlare->GetDepthBias(); query.DoHardwareOcclusionTest_Billboard(&vPos.x, m_pLensFlare->GetCheckBlockSize()); return true; } return false; }
/// update all internal data ////////////////////////////////////////////////////////////////////////// bool CScaler::UpdateInternalsAndGetVisibility() { VisRenderContext_cl* pCtx = Vision::Contexts.GetCurrentContext(); const VisMatrix4x4_cl& mtxProjection = pCtx->GetProjectionMatrix(); VisContextCamera_cl* pContextCam = pCtx->GetCamera(); pContextCam->GetWorldMatrix( m_mtxViewProjection ); // it`s View mtx and not all cells are filled?!?, fix below // ogl View to dx View mtx crap float* pGlmatrix = m_mtxViewProjection.GetFloatPtr(); pGlmatrix[ 2 ] = -pGlmatrix[ 2 ]; pGlmatrix[ 6 ] = -pGlmatrix[ 6 ]; pGlmatrix[ 10 ] = -pGlmatrix[ 10 ]; pGlmatrix[ 14 ] = -pGlmatrix[ 14 ]; pGlmatrix[ 15 ] = 1.f; //this must be here, GetWorldMatrix DOES NOT fill all cells !!! // multiply is now DX style (ogl is projection*view*world) m_mtxViewProjection *= mtxProjection; // get transpose mtx of ViewProjection m_mtxViewProjectionT = m_mtxViewProjection; m_mtxViewProjectionT.Transpose(); // gen VPInverse mtx (if sended to shader, must be transposed) m_mtxViewProjectionInv = m_mtxViewProjection; m_mtxViewProjectionInv.InvertEx(); // calculate -far & far plane vectors (homogeneous space) m_NearPlane.v1.SetXYZW( -1, 1, 0, 1 ); m_NearPlane.v2.SetXYZW( 1, 1, 0, 1 ); m_NearPlane.v3.SetXYZW( 1, -1, 0, 1 ); m_NearPlane.v4.SetXYZW( -1, -1, 0, 1 ); m_FarPlane.v1.SetXYZW( -1, 1, 1, 1 ); m_FarPlane.v2.SetXYZW( 1, 1, 1, 1 ); m_FarPlane.v3.SetXYZW( 1, -1, 1, 1 ); m_FarPlane.v4.SetXYZW( -1, -1, 1, 1 ); // w are all ones so Vision may be used m_NearPlane.v1 *= m_mtxViewProjectionInv; m_NearPlane.v2 *= m_mtxViewProjectionInv; m_NearPlane.v3 *= m_mtxViewProjectionInv; m_NearPlane.v4 *= m_mtxViewProjectionInv; m_FarPlane.v1 *= m_mtxViewProjectionInv; m_FarPlane.v2 *= m_mtxViewProjectionInv; m_FarPlane.v3 *= m_mtxViewProjectionInv; m_FarPlane.v4 *= m_mtxViewProjectionInv; _GetWorldPos( m_NearPlane, m_WorldNearPlane ); _GetWorldPos( m_FarPlane, m_WorldFarPlane ); GetIntersectionsAndPointsBeetween(); // will fill m_aIntesections & counter // skip if can`t generate proper matrix ( volume is outside of frustum ) if( m_iInterectionsCount >= 4 ) // valid { // get clip space coords to calculate XY span for( int i=0; i<m_iInterectionsCount; i++ ) { //m_aIntersections[ i ].w = 1.f; // Vision use w as 1 so don`t set m_aIntersections[ i ].z = 0.f; // TODO: should be water level m_aIntersections[ i ] *= m_mtxViewProjectionT; // use transposed mtx m_aIntersections[ i ].x /= m_aIntersections[ i ].w; m_aIntersections[ i ].y /= m_aIntersections[ i ].w; //m_aIntersections[ i ].z /= m_aIntersections[ i ].w; // we dont need Z } float fXMin = FLT_MAX; float fXMax = -FLT_MAX; float fYMin = FLT_MAX; float fYMax = -FLT_MAX; for( int i=0; i<m_iInterectionsCount; i++ ) { if( m_aIntersections[ i ].x > fXMax ) fXMax = m_aIntersections[ i ].x; if ( m_aIntersections[ i ].x < fXMin ) fXMin = m_aIntersections[ i ].x; if( m_aIntersections[ i ].y > fYMax ) fYMax = m_aIntersections[ i ].y; if ( m_aIntersections[ i ].y < fYMin ) fYMin = m_aIntersections[ i ].y; } // build scaling matrix. it prevents h-space verts in shader to run out of range /* normal way VisMatrix4x4_cl mtxScale; mtxScale.Identity(); mtxScale[ 0 ] = fXMax - fXMin; mtxScale[ 5 ] = fYMax - fYMin; mtxScale[ 12 ] = fXMin; mtxScale[ 13 ] = fYMin; mtxScale.Transpose(); */ // faster way m_mtxScale[ 0 ] = fXMax - fXMin; m_mtxScale[ 5 ] = fYMax - fYMin; m_mtxScale[ 3 ] = fXMin; m_mtxScale[ 7 ] = fYMin; m_mtxViewProjectionInv *= m_mtxScale; m_NearPlane.v1.SetXYZW( 0, 1, 0, 1 ); m_NearPlane.v2.SetXYZW( 1, 1, 0, 1 ); m_NearPlane.v3.SetXYZW( 1, 0, 0, 1 ); m_NearPlane.v4.SetXYZW( 0, 0, 0, 1 ); m_FarPlane.v1.SetXYZW( 0, 1, 1, 1 ); m_FarPlane.v2.SetXYZW( 1, 1, 1, 1 ); m_FarPlane.v3.SetXYZW( 1, 0, 1, 1 ); m_FarPlane.v4.SetXYZW( 0, 0, 1, 1 ); m_NearPlane.v1 *= m_mtxViewProjectionInv; m_NearPlane.v2 *= m_mtxViewProjectionInv; m_NearPlane.v3 *= m_mtxViewProjectionInv; m_NearPlane.v4 *= m_mtxViewProjectionInv; m_FarPlane.v1 *= m_mtxViewProjectionInv; m_FarPlane.v2 *= m_mtxViewProjectionInv; m_FarPlane.v3 *= m_mtxViewProjectionInv; m_FarPlane.v4 *= m_mtxViewProjectionInv; return true; }else { // do not render return false; } }
// TODO: This doesn't handle opaque fullbright surfaces correctly yet, and translucent fullbright surfaces are simply ignored. void MirrorRenderLoop_cl::OnDoRenderLoop(void *pUserData) { INSERT_PERF_MARKER_SCOPE("MirrorRenderLoop_cl::OnDoRenderLoop"); #if defined (WIN32) || defined (_VISION_XENON) || defined (_VISION_PS3) || defined(_VISION_PSP2) || defined(_VISION_WIIU) if (Vision::Editor.GetIgnoreAdvancedEffects()) { // force a black reflection because it won't work with orthographic views Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, V_RGBA_BLACK); return; } #endif VisRenderContext_cl *pContext = Vision::Contexts.GetCurrentContext(); const int iRenderFlags = pContext->GetRenderFlags(); const float fFarClipDist = m_pMirror->GetActualFarClipDistance(); const VFogParameters &fog = Vision::World.GetFogParameters(); VColorRef clearColor = (fog.depthMode != VFogParameters::Off) ? fog.iDepthColor : Vision::Renderer.GetDefaultClearColor(); Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, clearColor); // set the oblique clipping plane... pContext->SetCustomProjectionMatrix (m_pMirror->GetObliqueClippingProjection().getPointer ()); const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesPrimaryOpaquePass; const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesSecondaryOpaquePass; const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesTransparentPass; const VisEntityCollection_cl *pVisEntities; // === Visibility Determination === IVisVisibilityCollector_cl *pVisColl = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector(); if (pVisColl == NULL) return; const VisVisibilityObjectCollection_cl *pVisObjectCollection = pVisColl->GetVisibleVisObjects(); hkvAlignedBBox box; int iVoCount = m_pMirror->GetVisibilityObjectCount(); int iFrustumCount = 0; bool bUseCommonFrustum = false; // === Determine Scissor Rect === hkvVec2 vMinScreenSpace, vMaxScreenSpace; const hkvAlignedBBox &worldSpaceBox = m_pMirror->GetBoundingBox(); hkvVec3 vCorners[8]; worldSpaceBox.getCorners (vCorners); VRectanglef scissorRect; bool bUseScissorRect = true; for (int i=0; i<8; i++) { float x2d, y2d; BOOL bInFrontOfCamera = pContext->Project2D(vCorners[i], x2d, y2d); if (bInFrontOfCamera) { scissorRect.Add(hkvVec2(x2d, y2d)); } else { bUseScissorRect = false; break; } } if (bUseScissorRect) Vision::RenderLoopHelper.SetScissorRect(&scissorRect); for (int iVo = 0; iVo < iVoCount; iVo++) { VisVisibilityObject_cl *pVisObj = m_pMirror->GetVisibilityObject(iVo); if (pVisObj != NULL && pVisObj->WasVisibleInAnyLastFrame()) { if (iFrustumCount <= MAX_SEPARATE_FRUSTA) { const hkvAlignedBBox &voBox = pVisObj->GetWorldSpaceBoundingBox(); box.expandToInclude(voBox); if (m_Frustum[iFrustumCount].Set(pContext->GetCamera()->GetPosition(), voBox, true, fFarClipDist)) { iFrustumCount++; } else { bUseCommonFrustum = true; } } else { const hkvAlignedBBox &voBox = pVisObj->GetWorldSpaceBoundingBox(); box.expandToInclude(voBox); bUseCommonFrustum = true; } } } if (bUseCommonFrustum) { iFrustumCount = 1; if (!m_Frustum[0].Set(pContext->GetCamera()->GetPosition(), box, true, fFarClipDist)) iFrustumCount = 0; } if (iFrustumCount>0) { for (int i=0; i<iFrustumCount; i++) { m_visiblePrimaryOpaquePassGeoInstances.Clear(); m_visibleSecondaryOpaquePassGeoInstances.Clear(); m_visibleTransparentOpaquePassGeoInstances.Clear(); m_visEntities.Clear(); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visiblePrimaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visibleSecondaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass)->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visibleTransparentOpaquePassGeoInstances); pVisColl->GetVisibleEntities()->DetermineEntriesTouchingFrustum(m_Frustum[i], m_visEntities); if (iFrustumCount == 1) break; m_visiblePrimaryOpaquePassGeoInstances.TagEntries(); m_visibleSecondaryOpaquePassGeoInstances.TagEntries(); m_visibleTransparentOpaquePassGeoInstances.TagEntries(); m_visEntities.TagEntries(); } if (iFrustumCount > 1) { m_visiblePrimaryOpaquePassGeoInstances.Clear(); m_visibleSecondaryOpaquePassGeoInstances.Clear(); m_visibleTransparentOpaquePassGeoInstances.Clear(); m_visEntities.Clear(); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass)->GetTaggedEntries(m_visiblePrimaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass)->GetTaggedEntries(m_visibleSecondaryOpaquePassGeoInstances); pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass)->GetTaggedEntries(m_visibleTransparentOpaquePassGeoInstances); pVisColl->GetVisibleEntities()->GetTaggedEntries(m_visEntities); } pVisibleGeoInstancesPrimaryOpaquePass = &m_visiblePrimaryOpaquePassGeoInstances; pVisibleGeoInstancesSecondaryOpaquePass = &m_visibleSecondaryOpaquePassGeoInstances; pVisibleGeoInstancesTransparentPass = &m_visibleTransparentOpaquePassGeoInstances; pVisEntities = &m_visEntities; } else { pVisibleGeoInstancesPrimaryOpaquePass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass); pVisibleGeoInstancesSecondaryOpaquePass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass); pVisibleGeoInstancesTransparentPass = pVisColl->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass); pVisEntities = pVisColl->GetVisibleEntities(); } // === End Visibility Determination === if (m_pMirror->GetExecuteRenderHooks()) { VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY); Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data); } // Render opaque static geometry VASSERT(m_spDefaultLightMapping->m_Shaders.Count()==1); TRIGGER_MIRROR_HOOK(VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY) VisMirror_cl::VReflectionShaderSets_e shaderMode = m_pMirror->m_eReflectionShaderMode; DrawStaticGeometry(*pVisibleGeoInstancesPrimaryOpaquePass, VPT_PrimaryOpaquePass); DrawStaticGeometry(*pVisibleGeoInstancesSecondaryOpaquePass, VPT_SecondaryOpaquePass); // Render entities const VisEntityCollection_cl *pEntities = pVisEntities; int iCount = pEntities->GetNumEntries(); VASSERT(m_spDefaultLightGrid->m_Shaders.Count()==1); //VCompiledShaderPass *pLightgridShader = m_spDefaultLightGrid->m_Shaders.GetAt(0); int i; //bool bUseSimpleShader = shaderMode==VisMirror_cl::AlwaysSimple; Vision::RenderLoopHelper.BeginEntityRendering(); for (i=0;i<iCount;i++) { VisBaseEntity_cl *pEnt = pEntities->GetEntry(i); // Vision::RenderLoopHelper.TrackLightGridInfo(pEnt); // important: need to be done in RenderEntityWithSurfaceShaderList //if (bUseSimpleShader) //{ // Vision::RenderLoopHelper.RenderEntityWithShaders(pEnt,1,&pLightgridShader); //} //else { VisDrawCallInfo_t surfaceShaderList[RLP_MAX_ENTITY_SURFACES]; VDynamicMesh *pMesh = pEnt->GetMesh(); VisSurface_cl **ppSurfaces = pEnt->GetSurfaceArray(); int iNumSubmeshes = pMesh->GetSubmeshCount(); for (int j=0; j<iNumSubmeshes; j++) { VisDrawCallInfo_t &info(surfaceShaderList[j]); VBaseSubmesh* pSubmesh = pMesh->GetSubmesh(j); VisSurface_cl* pSurface = ppSurfaces[pSubmesh->m_iMaterialIndex]; info.Set(pSubmesh, pSurface, GetMirrorShader (pSurface, shaderMode)); } Vision::RenderLoopHelper.RenderEntityWithSurfaceShaderList(pEnt, iNumSubmeshes, surfaceShaderList); } } Vision::RenderLoopHelper.EndEntityRendering(); // Render Sky if (VSky::IsVisible()) { // The sky has to be rendered without oblique clipping pContext->SetCustomProjectionMatrix(NULL); Vision::RenderLoopHelper.RenderSky(); // set the oblique clipping plane after sky... pContext->SetCustomProjectionMatrix (m_pMirror->GetObliqueClippingProjection().getPointer ()); } if (m_pMirror->GetExecuteRenderHooks()) { VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_PRE_OCCLUSION_TESTS); Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data); } // Render Coronas / Lens Flares VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook,VRH_CORONAS_AND_FLARES); Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data); TRIGGER_MIRROR_HOOK(VRH_PRE_OCCLUSION_TESTS) if (iRenderFlags&VIS_RENDERCONTEXT_FLAG_USE_OCCLUSIONQUERY) Vision::RenderLoopHelper.PerformHardwareOcclusionQuery(); if (iRenderFlags&VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER) Vision::RenderLoopHelper.PerformHardwarePixelCounterQuery(); DrawDynamicLight(); TRIGGER_MIRROR_HOOK(VRH_DECALS) TRIGGER_MIRROR_HOOK(VRH_CORONAS_AND_FLARES) TRIGGER_MIRROR_HOOK(VRH_PRE_TRANSPARENT_PASS_GEOMETRY) DrawStaticGeometry(*pVisibleGeoInstancesTransparentPass, VPT_TransparentPass); TRIGGER_MIRROR_HOOK(VRH_POST_TRANSPARENT_PASS_GEOMETRY) if (bUseScissorRect) Vision::RenderLoopHelper.SetScissorRect(NULL); }
// renders visible wallmarks of specified pass type (pre or post, which is relevant in deferred context) void VWallmarkManager::RenderProjectedWallmarks(VPassType_e ePassType) { INSERT_PERF_MARKER_SCOPE("Wallmark Rendering (VWallmarkManager::RenderProjectedWallmarks)"); const int iWallmarkCount = m_AllProjectedWallmarks.Count(); IVisVisibilityCollector_cl *pVisCollector = Vision::Contexts.GetCurrentContext()->GetVisibilityCollector(); if (!pVisCollector || !iWallmarkCount) return; const VisStaticGeometryInstanceCollection_cl *pGeoInstances = pVisCollector->GetVisibleStaticGeometryInstances(); VisStaticGeometryInstance_cl::ResetTags(); pGeoInstances->TagEntries(); VisStaticGeometryInstanceCollection_cl &targetGiCollection = m_TempGeoInstanceCollection; VisRenderContext_cl *pContext = Vision::Contexts.GetCurrentContext(); VisRenderContext_cl *pLODContext = pContext->GetLODReferenceContext(); hkvVec3 vLODPos = pLODContext ? pLODContext->GetCamera()->GetPosition() : pContext->GetCamera()->GetPosition(); unsigned int iContextFilter = pContext->GetRenderFilterMask(); const VisFrustum_cl *pFrustum = pVisCollector->GetBaseFrustum(); int i; for (i=0;i<iWallmarkCount;i++) { VProjectedWallmark *pProjWallmark = m_AllProjectedWallmarks.GetAt(i); if ((pProjWallmark->GetVisibleBitmask() & iContextFilter)==0 || (ePassType & pProjWallmark->m_ePassType) == 0) continue; pProjWallmark->PrepareForRendering(); const VisStaticGeometryInstanceCollection_cl &wmGiList = pProjWallmark->GetStaticGeometryCollection(); #ifdef HK_DEBUG const int iNum = wmGiList.GetNumEntries(); for (int j=0;j<iNum;j++) { VisStaticGeometryInstance_cl *pInst = wmGiList.GetEntry(j); VASSERT_MSG(pInst && (pInst->GetGeometryType()==STATIC_GEOMETRY_TYPE_MESHINSTANCE || pInst->GetGeometryType()==STATIC_GEOMETRY_TYPE_TERRAIN), "The wallmark conains invalid primitive references") } #endif // clip against its bounding box (primitive visibility might overestimate visible parts) const hkvAlignedBBox &bbox = pProjWallmark->GetBoundingBox(); if (pProjWallmark->m_fFarClipDistance>0.f && pProjWallmark->m_fFarClipDistance<bbox.getDistanceTo(vLODPos)) continue; if (pFrustum && !pFrustum->Overlaps(bbox)) continue; const int iGeomFilter = pProjWallmark->GetGeometryTypeFilterMask(); if (iGeomFilter&PROJECTOR_AFFECTS_STATICMESHES) { // standard geometry targetGiCollection.Clear(); wmGiList.GetTaggedEntriesOfType(targetGiCollection,STATIC_GEOMETRY_TYPE_MESHINSTANCE); if (targetGiCollection.GetNumEntries()) { // render the static geometry instances using lightmapped or non-lightmapped shader VProjectorShaderPass *pShader = GetWallmarkShader(pProjWallmark,STATIC_GEOMETRY_TYPE_MESHINSTANCE); Vision::RenderLoopHelper.RenderStaticGeometryWithShader(targetGiCollection, *pShader); } } if (iGeomFilter&PROJECTOR_AFFECTS_TERRAIN) { // terrain geometry (different shader) targetGiCollection.Clear(); wmGiList.GetTaggedEntriesOfType(targetGiCollection,STATIC_GEOMETRY_TYPE_TERRAIN); if (targetGiCollection.GetNumEntries()>0) { // render the static geometry instances using lightmapped or non-lightmapped shader VProjectorShaderPass *pShader = GetWallmarkShader(pProjWallmark,STATIC_GEOMETRY_TYPE_TERRAIN); if (pShader) Vision::RenderLoopHelper.RenderStaticGeometryWithShader(targetGiCollection, *pShader); } } // entities if (iGeomFilter&PROJECTOR_AFFECTS_ENTITIES) { const VisEntityCollection_cl *pVisibleEntities = pVisCollector->GetVisibleEntities(); const unsigned int iInfluenceMask = pProjWallmark->GetInfluenceBitmask(); m_TempEntityCollection.Clear(); const int iEntCount = pVisibleEntities->GetNumEntries(); for (int j=0;j<iEntCount;j++) { VisBaseEntity_cl *pEntity = pVisibleEntities->GetEntry(j); if (pEntity==NULL || (pEntity->GetVisibleBitmask()&iInfluenceMask)==0) continue; const hkvAlignedBBox &entityBox(*pEntity->GetCurrentVisBoundingBoxPtr()); if (!entityBox.overlaps(bbox)) continue; m_TempEntityCollection.AppendEntry(pEntity); } if (m_TempEntityCollection.GetNumEntries()>0) { VProjectorShaderPass *pShader = GetWallmarkShader(pProjWallmark,STATIC_GEOMETRY_TYPE_MESHINSTANCE); // we can use this shader - VS skinning is used implicitly Vision::RenderLoopHelper.RenderEntitiesWithShader(m_TempEntityCollection, *pShader); } } } }
void VMobileForwardRenderLoop::RenderLitGeometry(VisLightSource_cl *pLight, IVShadowMapComponent *pShadowMapComponent, bool bBasePass, bool bUsesLightClippingVolume, bool bEntities, bool bStaticGeometry) { if (!pLight) return; // Some local variables for storing surfaces, shaders, surface shaders, and the like. VCompiledTechnique *pTechnique = NULL; VisDrawCallInfo_t SurfaceShaderList[RLP_MAX_ENTITY_SURFACESHADERS]; VisRenderContext_cl *pContext = VisRenderContext_cl::GetCurrentContext(); const hkvVec3 &vCamPos = pContext->GetCamera()->GetPosition(); const float fFade = pLight->GetFadeWeight(vCamPos); VisStaticGeometryInstanceCollection_cl *pLitGeoInstanceCollection = NULL; VisEntityCollection_cl *pLitEntityCollection = NULL; if (bBasePass || pLight != m_pBasePassLight) { if (bStaticGeometry) { pLitGeoInstanceCollection = &s_LitGeoInstanceCollection; pLitGeoInstanceCollection->Clear(); } if (bEntities) { pLitEntityCollection = &s_LitEntityCollection; pLitEntityCollection->Clear(); } Vision::RenderLoopHelper.GetVisibleGeometryInLightsourceRange(pLitGeoInstanceCollection, pLitEntityCollection, NULL, *pLight); } else { if (bStaticGeometry) pLitGeoInstanceCollection = &m_AdditiveLitGeoInstanceCollection; if (bEntities) pLitEntityCollection = &m_AdditiveLitEntityCollection; } #ifdef SUPPORTS_SHADOW_MAPS VShadowMapGenSpotDir *pShadowMapGenDir = NULL; if (pShadowMapComponent) { VShadowMapGenerator *pShadowMapGen = pShadowMapComponent->GetShadowMapGenerator(); if (pShadowMapGen->GetProjectionType()==SHADOW_PROJECTION_ORTHOGRAPHIC) pShadowMapGenDir = static_cast<VShadowMapGenSpotDir*>(pShadowMapGen); } #endif // Set the stencil render state for reading light clipping volume information if(bUsesLightClippingVolume) { const VLightClippingVolumeComponent* pLightClippingComponent = pLight->Components().GetComponentOfBaseType<VLightClippingVolumeComponent>(); VASSERT(pLightClippingComponent != NULL && V_ARRAY_SIZE(m_lightClippingStencilStatesRead)==2); VisRenderStates_cl::SetDepthStencilState(m_lightClippingStencilStatesRead[pLightClippingComponent->GetClipHandedness()]); } else VisRenderStates_cl::SetDepthStencilState(m_dynLightDefaultState); // For all illuminated entities: Render a dynamic lighting pass now. if (pLight->GetLightInfluenceBitMaskEntity() != 0 && bEntities) { int iNumLitEntities = pLitEntityCollection->GetNumEntries(); Vision::RenderLoopHelper.BeginEntityRendering(); for (int j=0; j<iNumLitEntities; j++) { VisBaseEntity_cl *pEntity = pLitEntityCollection->GetEntry(j); if (!(pEntity->GetLightInfluenceBitMask() & pLight->GetLightInfluenceBitMaskEntity())) continue; VDynamicMesh *pMesh = pEntity->GetMesh(); VisSurface_cl **ppSurfaces = pEntity->GetSurfaceArray(); // Get list of all the surfaces in the model int iNumSubmeshes = pMesh->GetSubmeshCount(); int iNumSurfaceShaders = 0; // For all the surfaces... for (int k=0; k<iNumSubmeshes; k++) { VDynamicSubmesh *pSubmesh = pMesh->GetSubmesh(k); VisSurface_cl *pSurface = ppSurfaces[pSubmesh->m_iMaterialIndex]; // Full-bright surfaces can't be rendered in the compound base pass, since such surfaces are not illuminated. Since tagging // of already rendered geometry happens per entity instance, in case an entity contains full-bright surfaces, all surfaces // of this entity have to be rendered in the normal rendering pipeline. const VisLightingMethod_e eLightingMethod = pSurface->GetLightingMode(); if (bBasePass) { // Since entities can contain several surfaces with different lighting methods (full-bright, dynamic only, etc.), entities // with full-bright surfaces have to be also added to the additive lit entity collection, in order to ensure rendering of // dynamic only surfaces. if (eLightingMethod==VIS_LIGHTING_FULLBRIGHT) { iNumSurfaceShaders = 0; m_AdditiveLitEntityCollection.AppendEntry(pEntity); break; } } else { if (eLightingMethod == VIS_LIGHTING_FULLBRIGHT) continue; } // If not all surfaces have a primary opaque pass type in the base pass, then render corresponding entity // in the additive lighting pass. if (bBasePass && pSurface->GetResolvedPassType()!=VPT_PrimaryOpaquePass) { iNumSurfaceShaders = 0; m_AdditiveLitEntityCollection.AppendEntry(pEntity); break; } // Check whether entity is in current shadow volume for orthographic shadows. In that case the entity is rendered // without shadows since it is not in the relevant shadow volume. IVShadowMapComponent *pTmpShadowMapComponent = pShadowMapComponent; #ifdef SUPPORTS_SHADOW_MAPS if (pShadowMapGenDir) { if (!pShadowMapGenDir->IsEntityInsideOrthoShadowVolume(pEntity)) pTmpShadowMapComponent = NULL; } #endif pTechnique = GetLightShader(pLight, bBasePass, pSurface, fFade, pTmpShadowMapComponent); if (!pTechnique || !pTechnique->GetShaderCount()) // do not light this surface { // If base-pass lighting technique could not be retrieved, render lit entity in the additive pass. if (bBasePass && pLight->IsDynamic()) m_AdditiveLitEntityCollection.AppendEntry(pEntity); iNumSurfaceShaders = 0; break; } // Generate a list of surface shader from the combined surface/shader information VisDrawCallInfo_t &info(SurfaceShaderList[iNumSurfaceShaders++]); info.Set(pSubmesh, pSurface, pTechnique->m_Shaders.GetAt(0)); } // Finally, render the entity with a surface shader list. if (iNumSurfaceShaders>0) { Vision::RenderLoopHelper.RenderEntityWithSurfaceShaderList(pEntity, iNumSurfaceShaders, SurfaceShaderList); if (bBasePass) pEntity->Tag(); } } Vision::RenderLoopHelper.EndEntityRendering(); } // For all illuminated world primitives: Render a dynamic lighting pass now. if (pLight->GetLightInfluenceBitMaskWorld() != 0 && bStaticGeometry) { VisSurface_cl *pSurface; VisSurface_cl *pLastSurface = NULL; VCompiledTechnique *pLastTechnique = NULL; // We start collecting illuminated mesh instances. Whenever a relevant property changes, we set the // shader information, render all collected world instances, and start collecting from scratch. int iNumLitGeoInstances = pLitGeoInstanceCollection->GetNumEntries(); pLastSurface = NULL; s_RenderGeoInstanceCollection.Clear(); pLastTechnique = NULL; for (int j=0; j<iNumLitGeoInstances; j++) { VisStaticGeometryInstance_cl *pGI = pLitGeoInstanceCollection->GetEntry(j); pSurface = pGI->GetSurface(); VASSERT(pSurface); if (pSurface->IsFullbright()) continue; // If surface does not have a primary opaque pass type in the base pass, then render corresponding static // mesh instance in the additive lighting pass. if (bBasePass && pSurface->GetResolvedPassType()!=VPT_PrimaryOpaquePass) { m_AdditiveLitGeoInstanceCollection.AppendEntry(pGI); continue; } // Check whether mesh is in current shadow volume for orthographic shadows. In that case the mesh is rendered // without shadows since it is not in the relevant shadow volume. IVShadowMapComponent *pTmpShadowMapComponent = pShadowMapComponent; #ifdef SUPPORTS_SHADOW_MAPS if (pShadowMapGenDir) { if (!pShadowMapGenDir->IsMeshInsideOrthoShadowVolume(pGI)) pTmpShadowMapComponent = NULL; } #endif if (pLastSurface!=pSurface) { pTechnique = GetLightShader(pLight, bBasePass, pSurface, fFade, pTmpShadowMapComponent); pLastSurface = pSurface; } if (pTechnique == NULL || !pTechnique->GetShaderCount()) { // If base-pass lighting technique could not be retrieved, render lit mesh in the additive pass. if (bBasePass && pLight->IsDynamic()) m_AdditiveLitGeoInstanceCollection.AppendEntry(pGI); continue; } // If the state information is different from the previous one, we have to render the world primitives we // have collected so far if (pLastTechnique!=pTechnique) { if (s_RenderGeoInstanceCollection.GetNumEntries()!=0) { VASSERT(pLastTechnique != NULL); Vision::RenderLoopHelper.RenderStaticGeometryWithShader(s_RenderGeoInstanceCollection, *pLastTechnique->m_Shaders.GetAt(0)); if (bBasePass) s_RenderGeoInstanceCollection.TagEntries(); s_RenderGeoInstanceCollection.Clear(); } // Update the stored state information pLastTechnique = pTechnique; } // Naturally, we have to append the primitive to our collection (otherwise it won't be collected =) ). s_RenderGeoInstanceCollection.AppendEntry(pGI); } // If there's still something left in the collection, render it as well. if (s_RenderGeoInstanceCollection.GetNumEntries()!=0) { if (pLastTechnique && pLastTechnique->GetShaderCount()>0) { Vision::RenderLoopHelper.RenderStaticGeometryWithShader(s_RenderGeoInstanceCollection, *pLastTechnique->m_Shaders.GetAt(0)); if (bBasePass) s_RenderGeoInstanceCollection.TagEntries(); } s_RenderGeoInstanceCollection.Clear(); } } // Restore default render state VisRenderStates_cl::SetDepthStencilState(*VisRenderStates_cl::GetDepthStencilDefaultState()); }
void VCoronaManager::RenderCorona (VCoronaCandidate& coronaCandidate, VTextureObject*& pTexture) { #ifdef SUPPORTS_CORONAS VCoronaComponent *pCorona = coronaCandidate.m_pCorona; VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext(); VisLightSource_cl* pLight = (VisLightSource_cl*)pCorona->GetOwner(); hkvVec3 vLightPos(hkvNoInitialization); pLight->GetVirtualPosition(vLightPos, pContext); hkvVec3 vEyePos(hkvNoInitialization); pContext->GetCamera()->GetPosition(vEyePos); hkvVec3 vDir = pContext->GetCamera()->GetDirection(); // Corona texture VTextureObject *pTex = pCorona->GetCoronaTexture(); if (pTex == NULL) return; if (pTexture != pTex) { pTexture = pTex; Vision::RenderLoopHelper.BindMeshTexture(pTexture,0); } // Get light color VColorRef color = pLight->GetColor(); hkvVec3 vDist = vLightPos - vEyePos; float fEyeDist = vDir.dot(vDist); //determine if camera is in light cone if the light is directional float fDirectionalDampening = 1.0f; if ( pLight->GetType() == VIS_LIGHT_SPOTLIGHT && pCorona->GetOnlyVisibleInSpotLight() ) { fDirectionalDampening = 0.0f; float fConeAngle = pLight->GetProjectionAngle(); float fConeLength = pLight->GetRadius(); hkvVec3 fConeDirection = pLight->GetDirection(); fConeDirection.normalize(); hkvVec3 vLightEyeDist = vEyePos - vLightPos; //#2 check if the camera is inside the angle of the cone float cosinusAngle = (vLightEyeDist/vLightEyeDist.getLength()).dot(fConeDirection); float fDegree = hkvMath::acosDeg(cosinusAngle); float normRadius = fDegree / (fConeAngle/2.0f); if (normRadius < 1.0f) { //hardcoded falloff. For better performance, we avoid sampling the projection texture here. const float fEpsilon = 64.0f/256.0f; const float fQuadFactor = 1.0f/fEpsilon - 1.0f; fDirectionalDampening = 1.0f / (1.0f + fQuadFactor*normRadius*normRadius); // scale the function so that the value is exactly 0.0 at the edge and 1.0 in the center fDirectionalDampening = (fDirectionalDampening - fEpsilon) / (1.0f - fEpsilon); } } // Fog params float fFogDampening = 1.0f; if (pLight->GetType() != VIS_LIGHT_DIRECTED && Vision::World.IsLinearDepthFogEnabled()) { const VFogParameters &fog = Vision::World.GetFogParameters(); float fFogStart = fog.fDepthStart; float fFogEnd = fog.fDepthEnd; float fFogFactor = (fFogEnd > fFogStart) ? ((fEyeDist - fFogStart) / (fFogEnd - fFogStart)) : 0.f; fFogDampening = 1.0f - hkvMath::clamp(fFogFactor, 0.0f, 1.0f); } // Get corona rotation float fRotation = 0.0f; hkvVec4 vRotation(1.0f, 0.0f, 0.0f, 1.0f); if (pCorona->CoronaFlags & VIS_CORONASCALE_ROTATING) { fRotation = hkvMath::mod (fEyeDist * 0.5f, 360.f); vRotation.x = hkvMath::cosDeg (fRotation); vRotation.y = -hkvMath::sinDeg (fRotation); vRotation.z = -vRotation.y; vRotation.w = vRotation.x; } // Texture dimensions int iSizeX, iSizeY, depth; pTex->GetTextureDimensions(iSizeX, iSizeY, depth); hkvVec4 vScale(0.0f, 0.0f, 0.0f, 0.0f); int iMainWidth, iMainHeight, iWidth, iHeight; pContext->GetSize(iWidth, iHeight); VisRenderContext_cl::GetMainRenderContext()->GetSize(iMainWidth, iMainHeight); // Preserve texture aspect ratio int iTexHeight = pTex->GetTextureHeight(); int iTexWidth = pTex->GetTextureWidth(); // Perspective scaling // This scaling ensures roughly the same size on 720p as the old implementation. vScale.z = iTexWidth * pCorona->CoronaScaling * 0.25f; vScale.w = iTexHeight * pCorona->CoronaScaling * 0.25f; // Screen-space scaling // This scaling ensures roughly the same size on 720p as the old implementation. const float fScaleFactor = pCorona->CoronaScaling * iMainHeight / 11.0f; vScale.x = ((float)iTexWidth / 128.0f) * fScaleFactor * (float(iWidth) / float(iMainWidth)); vScale.y = ((float)iTexHeight / 128.0f) * fScaleFactor * (float(iHeight) / float(iMainHeight)); vScale.x *= 2.0f / iWidth; vScale.y *= 2.0f / iHeight; // Scale by visibility if (pCorona->CoronaFlags & VIS_CORONASCALE_VISIBLEAREA) { vScale.x *= coronaCandidate.m_fCurrentVisibility; vScale.y *= coronaCandidate.m_fCurrentVisibility; vScale.z *= coronaCandidate.m_fCurrentVisibility; vScale.w *= coronaCandidate.m_fCurrentVisibility; } VCompiledShaderPass* pShader = m_spCoronaTechnique->GetShader(0); VShaderConstantBuffer *pVertexConstBuffer = pShader->GetConstantBuffer(VSS_VertexShader); // xyz = worldspace position, w = 1.0 if VIS_CORONASCALE_DISTANCE is true, otherwise zero. pVertexConstBuffer->SetSingleParameterF("coronaPosition", vLightPos.x, vLightPos.y, vLightPos.z, (pCorona->CoronaFlags & VIS_CORONASCALE_DISTANCE) ? 1.0f : 0.0f); // xyz = light color, w = corona visibility. pVertexConstBuffer->SetSingleParameterF("coronaColor", color.r/255.0f, color.g/255.0f, color.b/255.0f, coronaCandidate.m_fCurrentVisibility * fFogDampening * fDirectionalDampening); // xyzw = 2x2 rotation matrix. float2x2 is not supported in shader model 2, so a float4 is used and multiplication is done manually in the shader. pVertexConstBuffer->SetSingleParameterF("coronaRotation", vRotation.x, vRotation.y, vRotation.z, vRotation.w); // xy = screen-space scaling. zw = view-space scaling. pVertexConstBuffer->SetSingleParameterF("coronaScale", vScale.x, vScale.y, vScale.z, vScale.w); Vision::RenderLoopHelper.RenderMeshes(pShader, VisMeshBuffer_cl::MB_PRIMTYPE_TRILIST, 0, 2, 6); #endif }
void VCoronaManager::RenderAllVisibleCoronas() { #ifdef SUPPORTS_CORONAS VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext(); // Determine relevant render context and visibility collector IVisVisibilityCollector_cl *pVisCollector = pContext->GetVisibilityCollector(); if (!pVisCollector) return; VisRenderContext_cl *pOQContext = pVisCollector->GetOcclusionQueryRenderContext(); if (pOQContext != NULL) pContext = pOQContext; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER) == 0) return; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_RENDER_CORONAS) == 0) return; INSERT_PERF_MARKER_SCOPE("VCoronaManager::RenderAllVisibleCoronas"); VISION_PROFILE_FUNCTION(PROFILING_CORONA_RENDER); // Force for the queries to finish so they are available in this frame. if (m_bTeleportedLastFrame && m_bForceQueryOnTeleport) { UpdateCoronas(VCUF_UPDATE | VCUF_FORCE_FETCH | VCUF_USE_OC_CONTEXT); } // Ensure size of corona state structure. int iContextIndex = pContext->GetNumber(); if (iContextIndex + 1 > m_State.GetSize()) m_State.SetSize(iContextIndex + 1, -1); VCoronaRenderContextState& state = m_State[iContextIndex]; int iCapacity = m_Instances.GetCapacity(); state.EnsureSize(iCapacity); const int iCoronasToRender = state.m_Candidates.GetSize(); // Sort candidates by texture? VTextureObject* pTexture = NULL; // Render all corona components Vision::RenderLoopHelper.BeginMeshRendering(); Vision::RenderLoopHelper.AddMeshStreams(m_spBillboardMesh,VERTEX_STREAM_POSITION); for (int i=0; i < iCoronasToRender; ++i) { VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i); if (coronaCandidate.m_fCurrentVisibility > 0.0f) { RenderCorona (coronaCandidate, pTexture); } } Vision::RenderLoopHelper.EndMeshRendering(); m_bTeleportedLastFrame = (pContext->GetCamera()->GetLastTeleported() >= pContext->GetLastRenderedFrame()); #endif }
void VFakeSpecularGenerator::OnDoRenderLoop(void *pUserData) { VFrustumMeshHelper::UpdateMeshBuffer(m_spMeshBuffer, Vision::Contexts.GetCurrentContext(), VFrustumMeshHelper::IN_WORLD_SPACE); Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_All, VColorRef(0, 0, 0, 0)); VisRenderContext_cl* pContext = Vision::Contexts.GetCurrentContext(); const VisLightSrcCollection_cl* pLights = pContext->GetVisibilityCollector()->GetVisibleLights(); Vision::RenderLoopHelper.BeginMeshRendering(); Vision::RenderLoopHelper.ResetMeshStreams(); Vision::RenderLoopHelper.AddMeshStreams(m_spMeshBuffer, m_spShader->GetStreamMask () | VERTEX_STREAM_INDEXBUFFER); for(unsigned int iLightIndex = 0; iLightIndex < pLights->GetNumEntries(); iLightIndex++) { VisLightSource_cl* pLight = pLights->GetEntry(iLightIndex); if((pLight->GetVisibleBitmask() & pContext->GetRenderFilterMask()) == 0) continue; if(!pLight->GetUseSpecular()) continue; hkvVec4 vDirection; hkvVec3 vLightPositionRel = pLight->GetPosition() - pContext->GetCamera()->GetPosition(); hkvVec3 vLightDirection = pLight->GetDirection(); float fAttenuation = 1; switch(pLight->GetType()) { case VIS_LIGHT_DIRECTED: vDirection = vLightDirection.getAsVec4(1.0f); break; case VIS_LIGHT_SPOTLIGHT: { vDirection = vLightDirection.getAsVec4(1.0f); float fAngle = vLightPositionRel.getAngleBetween(-vLightDirection); float fConeAngle = pLight->GetProjectionAngle(); fAttenuation = hkvMath::clamp((fConeAngle - fAngle) / fConeAngle, 0.0f, 1.0f); float fDistance = vLightPositionRel.getLength(); float fRadius = pLight->GetRadius(); fAttenuation *= hkvMath::clamp((fRadius - fDistance) / fRadius, 0.0f, 1.0f); } break; case VIS_LIGHT_POINT: vDirection = (-vLightPositionRel).getNormalized().getAsVec4(1.0f); float fDistance = vLightPositionRel.getLength(); float fRadius = pLight->GetRadius(); fAttenuation = hkvMath::clamp((fRadius - fDistance) / fRadius, 0.0f, 1.0f); break; } hkvVec4 vColor = pLight->GetColor().getAsVec4() * pLight->GetMultiplier() * fAttenuation; hkvVec4 vParams(m_fSpecularPower, 0, 0, 0); m_spShader->GetConstantBuffer(VSS_PixelShader)->SetSingleParameterF("fLightDirection", vDirection.data); m_spShader->GetConstantBuffer(VSS_PixelShader)->SetSingleParameterF("fLightColor", vColor.data); m_spShader->GetConstantBuffer(VSS_PixelShader)->SetSingleParameterF("fParams", vParams.data); Vision::RenderLoopHelper.RenderMeshes(m_spShader, VisMeshBuffer_cl::MB_PRIMTYPE_INDEXED_TRILIST, 0, 2, 6); } Vision::RenderLoopHelper.EndMeshRendering(); // Trigger pre-screenmask render hook to make the attached cubemap handle flip and blur the cubemap target VisRenderHookDataObject_cl data(&Vision::Callbacks.OnRenderHook, VRH_PRE_SCREENMASKS); Vision::Callbacks.OnRenderHook.TriggerCallbacks(&data); }