| 1615 | } |
| 1616 | |
| 1617 | void ShadowsPass::RenderShadowMask(RenderContextBatch& renderContextBatch, RenderLightData& light, GPUTextureView* shadowMask) |
| 1618 | { |
| 1619 | ASSERT(light.HasShadow); |
| 1620 | PROFILE_GPU_CPU("Shadow"); |
| 1621 | GPUContext* context = GPUDevice::Instance->GetMainContext(); |
| 1622 | RenderContext& renderContext = renderContextBatch.GetMainContext(); |
| 1623 | const ShadowsCustomBuffer& shadows = *renderContext.Buffers->FindCustomBuffer<ShadowsCustomBuffer>(TEXT("Shadows"), false); |
| 1624 | ASSERT(shadows.LastFrameUsed == Engine::FrameCount); |
| 1625 | auto& view = renderContext.View; |
| 1626 | auto shader = _shader->GetShader(); |
| 1627 | const bool isLocalLight = light.IsPointLight || light.IsSpotLight; |
| 1628 | int32 shadowQuality = shadows.MaxShadowsQuality; |
| 1629 | if (isLocalLight) |
| 1630 | { |
| 1631 | // Reduce shadows quality for smaller lights |
| 1632 | if (light.ScreenSize < 0.25f) |
| 1633 | shadowQuality--; |
| 1634 | if (light.ScreenSize < 0.1f) |
| 1635 | shadowQuality--; |
| 1636 | shadowQuality = Math::Max(shadowQuality, 0); |
| 1637 | } |
| 1638 | |
| 1639 | // Setup shader data |
| 1640 | Data sperLight; |
| 1641 | GBufferPass::SetInputs(view, sperLight.GBuffer); |
| 1642 | if (light.IsDirectionalLight) |
| 1643 | ((RenderDirectionalLightData&)light).SetShaderData(sperLight.Light, true); |
| 1644 | else if (light.IsPointLight) |
| 1645 | ((RenderPointLightData&)light).SetShaderData(sperLight.Light, true); |
| 1646 | else if (light.IsSpotLight) |
| 1647 | ((RenderSpotLightData&)light).SetShaderData(sperLight.Light, true); |
| 1648 | Matrix::Transpose(view.ViewProjection(), sperLight.ViewProjectionMatrix); |
| 1649 | sperLight.TemporalTime = renderContext.List->Setup.UseTemporalAAJitter ? RenderTools::ComputeTemporalTime() : 0.0f; |
| 1650 | sperLight.ContactShadowsDistance = light.ShadowsDistance; |
| 1651 | sperLight.ContactShadowsLength = EnumHasAnyFlags(view.Flags, ViewFlags::ContactShadows) ? light.ContactShadowsLength : 0.0f; |
| 1652 | bool isViewInside; |
| 1653 | if (isLocalLight) |
| 1654 | { |
| 1655 | // Calculate world view projection matrix for the light sphere |
| 1656 | Matrix world, wvp; |
| 1657 | RenderTools::ComputeSphereModelDrawMatrix(renderContext.View, light.Position, ((RenderLocalLightData&)light).Radius, world, isViewInside); |
| 1658 | Matrix::Multiply(world, view.ViewProjection(), wvp); |
| 1659 | Matrix::Transpose(wvp, sperLight.WVP); |
| 1660 | } |
| 1661 | |
| 1662 | // Render shadow in screen space |
| 1663 | GPUConstantBuffer* cb0 = shader->GetCB(0); |
| 1664 | context->UpdateCB(cb0, &sperLight); |
| 1665 | context->BindCB(0, cb0); |
| 1666 | context->BindSR(5, shadows.ShadowsBufferView); |
| 1667 | context->BindSR(6, shadows.ShadowMapAtlas); |
| 1668 | const int32 permutationIndex = shadowQuality + (sperLight.ContactShadowsLength > ZeroTolerance ? 4 : 0); |
| 1669 | GPUTexture* depthBuffer = renderContext.Buffers->DepthBuffer; |
| 1670 | const bool depthBufferReadOnly = EnumHasAnyFlags(depthBuffer->Flags(), GPUTextureFlags::ReadOnlyDepthView); |
| 1671 | context->SetRenderTarget(depthBufferReadOnly ? depthBuffer->ViewReadOnlyDepth() : nullptr, shadowMask); |
| 1672 | if (_depthBounds) |
| 1673 | { |
| 1674 | Float2 minMaxDepth; |
no test coverage detected