void VPostProcessTranslucencies::Execute() { INSERT_PERF_MARKER_SCOPE("VPostProcessTranslucencies"); VisRenderContext_cl *pContext = VisRenderContext_cl::GetCurrentContext(); IVisVisibilityCollector_cl *pVisCollector = pContext->GetVisibilityCollector(); VASSERT(pVisCollector != NULL); const VisEntityCollection_cl *pVisibleForeGroundEntities = pVisCollector->GetVisibleForeGroundEntities(); m_VisibilityObjectCollector.HandleVisibleVisibilityObjects(); #ifndef _VISION_MOBILE RenderingOptimizationHelpers_cl::SetShaderPreference(96); #endif // Get a pointer to the collection of visible mesh buffer objects const VisMeshBufferObjectCollection_cl *pVisibleMeshBuffer = &m_VisibilityObjectCollector.GetMeshBufferObjectCollection(); // Get a pointer to the collection of visible particle groups const VisParticleGroupCollection_cl *pVisibleParticleGroups = &m_VisibilityObjectCollector.GetParticleGroupCollection(); // Mask out entities which are "always in foreground" MaskOutForegroundEntities(*pVisibleForeGroundEntities); if (pVisCollector->GetInterleavedTranslucencySorter() == NULL) { // --- Traditional transparency sorting (default) const VisStaticGeometryInstanceCollection_cl *pVisibleTransparentGeoInstances = pVisCollector->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass); const VisEntityCollection_cl *pVisibleEntities = pVisCollector->GetVisibleEntitiesForPass(VPT_TransparentPass); VisionRenderLoop_cl::RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_TRANSPARENT_PASS_GEOMETRY, true); // render transparent pass surface shaders on translucent static geometry instances Vision::RenderLoopHelper.RenderStaticGeometrySurfaceShaders(*pVisibleTransparentGeoInstances, VPT_TransparentPass); VisionRenderLoop_cl::RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_TRANSPARENT_PASS_ENTITIES, true); // Render transparent pass shaders on entities DrawEntitiesShaders(*pVisibleEntities, VPT_TransparentPass); VisionRenderLoop_cl::RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_POST_TRANSPARENT_PASS_GEOMETRY, true); VisionRenderLoop_cl::RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_DECALS, true); RenderParticles(pVisibleMeshBuffer, pVisibleParticleGroups); } else { // --- Interleaved transparency sorting pVisCollector->GetInterleavedTranslucencySorter()->OnRender(pVisCollector, true); } // Render visible foreground entities (see DrawForegroundEntities) DrawTransparentForegroundEntities(*pVisibleForeGroundEntities); // Coronas and flares will be still rendered after the other interleaved sorted objects were rendered (lensflare and coronas don't must be always rendered "on top") VisionRenderLoop_cl::RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_CORONAS_AND_FLARES, true); }
void VMobileForwardRenderLoop::OnDoRenderLoop(void *pUserData) { INSERT_PERF_MARKER_SCOPE("VMobileForwardRenderLoop::OnDoRenderLoop"); m_iFrameCounter++; // just for arbitrary custom purposes #ifdef WIN32 // vForge specific: if (Vision::RenderLoopHelper.GetReplacementRenderLoop()) { // render with this render-loop instead Vision::RenderLoopHelper.GetReplacementRenderLoop()->OnDoRenderLoop(pUserData); return; } #endif m_pShaderProvider = Vision::GetApplication()->GetShaderProvider(); VASSERT(m_pShaderProvider); m_pShaderProvider->ResetCache(); VisRenderContext_cl *pContext = VisRenderContext_cl::GetCurrentContext(); IVisVisibilityCollector_cl *pVisCollector = pContext->GetVisibilityCollector(); if (pVisCollector==NULL) return; const int iRenderFlags = pContext->GetRenderFlags(); m_pCameraFrustum = pVisCollector->GetBaseFrustum(); const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesPrimaryOpaquePass = pVisCollector->GetVisibleStaticGeometryInstancesForPass(VPT_PrimaryOpaquePass); const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesSecondaryOpaquePass = pVisCollector->GetVisibleStaticGeometryInstancesForPass(VPT_SecondaryOpaquePass); const VisStaticGeometryInstanceCollection_cl *pVisibleGeoInstancesTransparentPass = pVisCollector->GetVisibleStaticGeometryInstancesForPass(VPT_TransparentPass); const VisEntityCollection_cl *pVisibleEntitiesPrimaryOpaquePass = pVisCollector->GetVisibleEntitiesForPass(VPT_PrimaryOpaquePass); const VisEntityCollection_cl *pVisibleEntitiesSecondaryOpaquePass = pVisCollector->GetVisibleEntitiesForPass(VPT_SecondaryOpaquePass); const VisEntityCollection_cl *pVisibleEntitiesTransparentPass = pVisCollector->GetVisibleEntitiesForPass(VPT_TransparentPass); const VisEntityCollection_cl *pVisibleForeGroundEntities = pVisCollector->GetVisibleForeGroundEntities(); HandleVisibleVisibilityObjects(); // Clear the screen if ((iRenderFlags&VIS_RENDERCONTEXT_FLAG_NO_CLEARSCREEN)==0) { 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); } m_bHasRenderHookCallbacks = m_bTriggerCallbacks && Vision::Callbacks.OnRenderHook.HasCallbacks(); // Get a pointer to the collection of visible mesh buffer objects const VisMeshBufferObjectCollection_cl *pVisibleMeshBuffer = &m_VisibilityObjectCollector.GetMeshBufferObjectCollection(); // Get a pointer to the collection of visible particle groups const VisParticleGroupCollection_cl *pVisibleParticleGroups = &m_VisibilityObjectCollector.GetParticleGroupCollection(); // Determine which lights have to rendered in the current frame DetermineRelevantLights(); // Render all mesh buffer objects with the render order flag "VRH_PRE_RENDERING". RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_RENDERING, m_bTriggerCallbacks); // Render all mesh buffer objects with the render order flag "VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY". RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_PRIMARY_OPAQUE_PASS_GEOMETRY, m_bTriggerCallbacks); // Reset tags VisStaticGeometryInstance_cl::ResetTags(); VisBaseEntity_cl::ResetTags(); // Clear temporary collections for geometry that is lit by base pass light, but rendered in additive lighting pass m_AdditiveLitGeoInstanceCollection.Clear(); m_AdditiveLitEntityCollection.Clear(); // Prepare the initial lighting pass (one light collapsed with base lighting contribution) bool bUsesLightClippingVolume = false; IVShadowMapComponent *pShadowMap = PrepareLightingPass(m_pBasePassLight, true, bUsesLightClippingVolume); // Render lit geometry before actual base pass, whereby the geometry which has been rendered here will be tagged, in order // to avoid re-rendering later on. We first render static meshes lit base the base pass light, then static meshes not lit by the base pass light, // and then entities (with/without base pass light, respectively). { RenderLitGeometry(m_pBasePassLight, pShadowMap, true, bUsesLightClippingVolume, false, true); // Render all primary opaque pass surface shaders on opaque world geometry Vision::RenderLoopHelper.RenderStaticGeometrySurfaceShaders(*pVisibleGeoInstancesPrimaryOpaquePass, VPT_PrimaryOpaquePass, VTF_IGNORE_TAGGED_ENTRIES); // Render all mesh buffer objects with the render order flag "VRH_PRE_PRIMARY_OPAQUE_PASS_ENTITIES". RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_PRIMARY_OPAQUE_PASS_ENTITIES, m_bTriggerCallbacks); RenderLitGeometry(m_pBasePassLight, pShadowMap, true, bUsesLightClippingVolume, true, false); // Render all primary opaque pass shaders on entities (see "DrawEntitiesShaders") DrawEntitiesShaders(*pVisibleEntitiesPrimaryOpaquePass, VPT_PrimaryOpaquePass, VTF_IGNORE_TAGGED_ENTRIES); } // Finalize the initial pass FinalizeLightingPass(m_pBasePassLight, bUsesLightClippingVolume); RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_SECONDARY_OPAQUE_PASS_GEOMETRY, m_bTriggerCallbacks); // Render static geometry instances for secondary opaque pass Vision::RenderLoopHelper.RenderStaticGeometrySurfaceShaders(*pVisibleGeoInstancesSecondaryOpaquePass, VPT_SecondaryOpaquePass, VTF_IGNORE_TAGGED_ENTRIES); RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_SECONDARY_OPAQUE_PASS_ENTITIES, m_bTriggerCallbacks); // Render entities for secondary opaque pass DrawEntitiesShaders(*pVisibleEntitiesSecondaryOpaquePass, VPT_SecondaryOpaquePass, VTF_IGNORE_TAGGED_ENTRIES); // Start the hardware occlusion query. Note that this function always has to be called in render loops. // Also, the position of this call in the OnDoRenderLoop is important: The zBuffer contents at this stage of rendering will // act as occluders in the hardware occlusion queries. Vision::RenderLoopHelper.PerformHardwareOcclusionQuery(); // Render sky Vision::RenderLoopHelper.RenderSky(); // Render all mesh buffer objects with the render order flag "VRH_PRE_OCCLUSION_TESTS". RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_OCCLUSION_TESTS, m_bTriggerCallbacks); Vision::RenderLoopHelper.PerformHardwarePixelCounterQuery(); // Render all mesh buffer objects with the render order flag "VRH_POST_OCCLUSION_TESTS". RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_POST_OCCLUSION_TESTS, m_bTriggerCallbacks); // Draw dynamic light DrawDynamicLight(); // Render all mesh buffer objects with the render order flag "VRH_PRE_TRANSPARENT_PASS_GEOMETRY". RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_TRANSPARENT_PASS_GEOMETRY, m_bTriggerCallbacks); // Render transparent pass surface shaders on translucent lit world primitives Vision::RenderLoopHelper.RenderStaticGeometrySurfaceShaders(*pVisibleGeoInstancesTransparentPass, VPT_TransparentPass, VTF_IGNORE_TAGGED_ENTRIES); RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PRE_TRANSPARENT_PASS_ENTITIES, m_bTriggerCallbacks); // Render transparent pass shaders on entities DrawEntitiesShaders(*pVisibleEntitiesTransparentPass, VPT_TransparentPass, VTF_IGNORE_TAGGED_ENTRIES); // Render all mesh buffer objects with the render order flag "VRH_POST_TRANSPARENT_PASS_GEOMETRY". RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_POST_TRANSPARENT_PASS_GEOMETRY, m_bTriggerCallbacks); // Render all mesh buffer objects and particle systems with the render order flag "VRH_DECALS". RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_DECALS, m_bTriggerCallbacks); // Render all mesh buffer objects and particle systems with the render order flag "VRH_PARTICLES". RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_PARTICLES, m_bTriggerCallbacks); // Render all mesh buffer objects with the render order flag "VRH_ADDITIVE_PARTICLES" RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_ADDITIVE_PARTICLES, m_bTriggerCallbacks); RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_TRANSLUCENT_VOLUMES, m_bTriggerCallbacks); // Render visible foreground entities (see DrawForegroundEntities) DrawForegroundEntities(*pVisibleForeGroundEntities); // Render all mesh buffer objects with the render order flag "VRH_CORONAS_AND_FLARES" RenderHook(*pVisibleMeshBuffer, pVisibleParticleGroups, VRH_CORONAS_AND_FLARES, m_bTriggerCallbacks); m_pShaderProvider = NULL; }
void VCoronaManager::UpdateCoronas(int iCoronaUpdateFlags) { #ifdef SUPPORTS_CORONAS VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext(); if ((iCoronaUpdateFlags & VCUF_USE_OC_CONTEXT) > 0) { // 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 == NULL) return; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER) == 0) return; if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_RENDER_CORONAS) == 0) return; // Get bitmask for this context. unsigned int iRenderFilterMask = pContext->GetRenderFilterMask(); // get the collection of visible lights. IVisVisibilityCollector_cl* pVisCollector = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector(); if (pVisCollector == NULL) return; VISION_PROFILE_FUNCTION(PROFILING_CORONA_UPDATE); // Get multi-sampling mode unsigned int iTexelsPerPixel = 1; VTextureObject* pDepthTex = pContext->GetDepthStencilTarget(); if(pDepthTex == NULL) { // If no depth stencil target is available, we might work without a renderer node and we're in the main context if(Vision::Renderer.GetCurrentRendererNode() == NULL && pContext == VisRenderContext_cl::GetMainRenderContext()) { // In this case get the multi-sampling type from the video config as it's used to set the actual backbuffer settings // where the main context will render to iTexelsPerPixel = hkvMath::Max(1, 1 << ((int)Vision::Video.GetCurrentConfig()->m_eMultiSample)); } } else if (pDepthTex->GetTextureType() == VTextureLoader::Texture2D) { iTexelsPerPixel = hkvMath::Max(1u, ((VisRenderableTexture_cl*)pDepthTex)->GetConfig()->m_iMultiSampling); } const VisLightSrcCollection_cl* pVisibleLights = pVisCollector->GetVisibleLights(); int iCandidates = 0; if (pVisibleLights != NULL) iCandidates = pVisibleLights->GetNumEntries(); // Ensure size of coronas 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); // Add visible lights with a lens flare component to the candidate list for this frame if ((iCoronaUpdateFlags & VCUF_ADD) > 0) { for (int iCandidate = 0; iCandidate < iCandidates; ++iCandidate) { VisLightSource_cl* pLight = pVisibleLights->GetEntry(iCandidate); if (pLight) { VCoronaComponent *pComponent = pLight->Components().GetComponentOfBaseType<VCoronaComponent>(); if (pComponent != NULL && pComponent->IsEnabled() && !state.IsBitSet(pComponent->m_iIndex)) { // The component is not in m_Candidates yet, so we check whether it is a valid candidate bool bIsLightOnScreen = pComponent->IsValidCandidate(pContext); if (bIsLightOnScreen) { state.SetBit(pComponent->m_iIndex); pContext->SetPixelCounterResult(pComponent->m_CoronaPixelCounter.GetNumber(), 0); state.m_Candidates.Append(pComponent); } } } } } // Forces the retrieval all pending queries. pContext->FetchPixelCounterTestResults( (iCoronaUpdateFlags & VCUF_FORCE_FETCH) > 0 ); // Retrieve Queries and update status of lens flares if ((iCoronaUpdateFlags & VCUF_UPDATE) > 0) { for (int i=0; i < state.m_Candidates.GetSize(); ++i) { VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i); VCoronaComponent* pCorona = coronaCandidate.m_pCorona; if (!pCorona || !pCorona->IsEnabled()) continue; if (pCorona->GetOwner()) { // Retrieve occlusion results of the last query unsigned int iElementIndex = pCorona->m_CoronaPixelCounter.GetNumber(); bool bRes = !pContext->IsPixelCounterQueryInProgress(iElementIndex); // Reschedule query if the old on could be retrieved or if a teleport forces us to re-query everything. if (bRes | ((iCoronaUpdateFlags & VCUF_FORCE_SCHEDULE) > 0) ) pContext->SchedulePixelCounterTest(iElementIndex); unsigned int iDrawnPixels = pContext->GetPixelCounterResult(iElementIndex) / iTexelsPerPixel; float fVisibility = (float)iDrawnPixels / ((int)pCorona->QueryRadius * (int)pCorona->QueryRadius * 4); // ATI fix for random insanely high return values. if (iDrawnPixels > ((unsigned int)pCorona->QueryRadius * 2 + 1) * ((unsigned int)pCorona->QueryRadius * 2 + 1)) { fVisibility = coronaCandidate.m_fLastVisibilityQuery; } if ((iCoronaUpdateFlags & VCUF_FORCE_FETCH) > 0) { // Force lens flare visibility to the current query value. coronaCandidate.m_fCurrentVisibility = fVisibility; coronaCandidate.m_fLastVisibilityQuery = fVisibility; pCorona->UpdateVisibility(coronaCandidate.m_fLastVisibilityQuery, coronaCandidate.m_fCurrentVisibility); } else if (!m_bTeleportedLastFrame) { coronaCandidate.m_fLastVisibilityQuery = fVisibility; pCorona->UpdateVisibility(coronaCandidate.m_fLastVisibilityQuery, coronaCandidate.m_fCurrentVisibility); } else { // if we were teleported, the last frame's query results must be invalidated coronaCandidate.m_fCurrentVisibility = 0.0f; coronaCandidate.m_fLastVisibilityQuery = 0.0f; } } } } // Removes coronas that are outside the frustum and no longer visible. if ((iCoronaUpdateFlags & VCUF_REMOVE) > 0) { for (int i=0; i < state.m_Candidates.GetSize();) { VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i); VCoronaComponent* pCorona = coronaCandidate.m_pCorona; unsigned int iElementIndex = pCorona->m_CoronaPixelCounter.GetNumber(); // If the visibility reached zero and the corona is no longer potentially visible it is removed from the list if (!pCorona->IsEnabled() || !pCorona->GetOwner() || (pCorona->GetVisibleBitmask() & iRenderFilterMask) == 0 || (((VisLightSource_cl*)pCorona->GetOwner())->GetVisibleBitmask() & iRenderFilterMask) == 0 || ( coronaCandidate.m_fCurrentVisibility == 0.0f && !pCorona->IsValidCandidate(pContext) ) ) { state.RemoveBit(pCorona->m_iIndex); state.m_Candidates.SetAt(i, state.m_Candidates.GetAt(state.m_Candidates.GetSize()-1) ); state.m_Candidates.RemoveAt(state.m_Candidates.GetSize() -1); // Reset cache to zero, so we don't see the lens flare once it enters the frustum again. pContext->SetPixelCounterResult(iElementIndex, 0); } else { ++i; } } } #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); }