diff --git a/Editor/CameraComponentWindow.cpp b/Editor/CameraComponentWindow.cpp index 0ccefadf9..56302982c 100644 --- a/Editor/CameraComponentWindow.cpp +++ b/Editor/CameraComponentWindow.cpp @@ -14,13 +14,16 @@ void CameraPreview::RenderPreview() { renderpath.camera = camera; scale_local.y = scale_local.x * renderpath.camera->height / renderpath.camera->width; - renderpath.setSceneUpdateEnabled(false); // we just view our scene with this that's updated by the main rernderpath - renderpath.setOcclusionCullingEnabled(false); // occlusion culling only works for one camera - renderpath.PreUpdate(); - renderpath.Update(0); - renderpath.PostUpdate(); - renderpath.PreRender(); - renderpath.Render(); + if (!camera->render_to_texture.rendertarget_render.IsValid()) + { + renderpath.setSceneUpdateEnabled(false); // we just view our scene with this that's updated by the main rernderpath + renderpath.setOcclusionCullingEnabled(false); // occlusion culling only works for one camera + renderpath.PreUpdate(); + renderpath.Update(0); + renderpath.PostUpdate(); + renderpath.PreRender(); + renderpath.Render(); + } } else { @@ -56,9 +59,17 @@ void CameraPreview::Render(const wi::Canvas& canvas, wi::graphics::CommandList c params.corners_rounding[3].radius = 8; params.color = wi::Color::White(); params.blendFlag = wi::enums::BLENDMODE_OPAQUE; - wi::image::Draw(renderpath.GetLastPostprocessRT(), params, cmd); + if (renderpath.camera->render_to_texture.rendertarget_render.IsValid()) + { + wi::image::Draw(&renderpath.camera->render_to_texture.rendertarget_render, params, cmd); + wi::font::Draw("Camera preview (raw render):", wi::font::Params(params.pos.x + 2, params.pos.y + 2), cmd); + } + else + { + wi::image::Draw(renderpath.GetLastPostprocessRT(), params, cmd); + wi::font::Draw("Camera preview (editor only):", wi::font::Params(params.pos.x + 2, params.pos.y + 2), cmd); + } - wi::font::Draw("Camera preview:", wi::font::Params(params.pos.x + 2, params.pos.y + 2), cmd); } } @@ -213,6 +224,91 @@ void CameraComponentWindow::Create(EditorComponent* _editor) }); AddWidget(&apertureShapeYSlider); + renderButton.Create("RenderToTexture"); + renderButton.SetTooltip("If Render To Texture is enabled for a camera, the camera renders the scene into its own textures\n which can be reused for other things such as materials."); + renderButton.OnClick([=](wi::gui::EventArgs args) { + wi::scene::Scene& scene = editor->GetCurrentScene(); + bool disable = true; + const CameraComponent* cam = scene.cameras.GetComponent(entity); + if (cam != nullptr) + { + disable = cam->render_to_texture.resolution.x > 0 || cam->render_to_texture.resolution.y > 0; + } + if (disable) + { + renderButton.SetText("Enable Render To Texture"); + renderEnabled = false; + } + else + { + renderButton.SetText("Disable Render To Texture"); + renderEnabled = true; + } + for (auto& x : editor->translator.selected) + { + CameraComponent* camera = scene.cameras.GetComponent(x.entity); + if (camera == nullptr) + continue; + if (disable) + { + camera->render_to_texture.resolution = {}; + } + else + { + camera->render_to_texture.resolution = XMUINT2(256, 256); + } + camera->SetDirty(); + } + }); + AddWidget(&renderButton); + + resolutionXSlider.Create(128, 2048, 256, 2048 - 128, "Render Width: "); + resolutionXSlider.SetTooltip("Set the render resolution Width"); + resolutionXSlider.OnSlide([=](wi::gui::EventArgs args) { + wi::scene::Scene& scene = editor->GetCurrentScene(); + for (auto& x : editor->translator.selected) + { + CameraComponent* camera = scene.cameras.GetComponent(x.entity); + if (camera == nullptr) + continue; + camera->render_to_texture.resolution.x = (uint32_t)args.iValue; + camera->SetDirty(); + } + }); + AddWidget(&resolutionXSlider); + + resolutionYSlider.Create(128, 2048, 256, 2048 - 128, "Render Height: "); + resolutionYSlider.SetTooltip("Set the render resolution Height"); + resolutionYSlider.OnSlide([=](wi::gui::EventArgs args) { + wi::scene::Scene& scene = editor->GetCurrentScene(); + for (auto& x : editor->translator.selected) + { + CameraComponent* camera = scene.cameras.GetComponent(x.entity); + if (camera == nullptr) + continue; + camera->render_to_texture.resolution.y = (uint32_t)args.iValue; + camera->SetDirty(); + } + }); + AddWidget(&resolutionYSlider); + + samplecountSlider.Create(1, 8, 1, 7, "Sample count: "); + samplecountSlider.SetTooltip("Set the render resolution sample count (MSAA)"); + samplecountSlider.OnSlide([=](wi::gui::EventArgs args) { + wi::scene::Scene& scene = editor->GetCurrentScene(); + uint32_t samplecount = wi::math::GetNextPowerOfTwo((uint32_t)args.iValue); + samplecountSlider.SetValue((int)samplecount); + for (auto& x : editor->translator.selected) + { + CameraComponent* camera = scene.cameras.GetComponent(x.entity); + if (camera == nullptr) + continue; + camera->render_to_texture.sample_count = samplecount; + camera->SetDirty(); + } + }); + AddWidget(&samplecountSlider); + AddWidget(&preview); @@ -241,6 +337,11 @@ void CameraComponentWindow::SetEntity(Entity entity) apertureSizeSlider.SetValue(camera->aperture_size); apertureShapeXSlider.SetValue(camera->aperture_shape.x); apertureShapeYSlider.SetValue(camera->aperture_shape.y); + renderEnabled = camera->render_to_texture.resolution.x > 0 || camera->render_to_texture.resolution.y > 0; + renderButton.SetText(renderEnabled ? "Disable Render To Texture" : "Enable Render To Texture"); + resolutionXSlider.SetValue((int)camera->render_to_texture.resolution.x); + resolutionYSlider.SetValue((int)camera->render_to_texture.resolution.y); + samplecountSlider.SetValue((int)camera->render_to_texture.sample_count); preview.entity = entity; preview.renderpath.scene = &scene; @@ -300,6 +401,29 @@ void CameraComponentWindow::ResizeLayout() add(apertureSizeSlider); add(apertureShapeXSlider); add(apertureShapeYSlider); + + y += jump; + + add_fullwidth(renderButton); + if (renderEnabled) + { + resolutionXSlider.SetVisible(true); + resolutionYSlider.SetVisible(true); + samplecountSlider.SetVisible(true); + + add(resolutionXSlider); + add(resolutionYSlider); + add(samplecountSlider); + } + else + { + resolutionXSlider.SetVisible(false); + resolutionYSlider.SetVisible(false); + samplecountSlider.SetVisible(false); + } + + y += jump; + add_fullwidth(preview); } diff --git a/Editor/CameraComponentWindow.h b/Editor/CameraComponentWindow.h index 791f4adea..b46c98302 100644 --- a/Editor/CameraComponentWindow.h +++ b/Editor/CameraComponentWindow.h @@ -29,6 +29,12 @@ public: wi::gui::Slider apertureShapeXSlider; wi::gui::Slider apertureShapeYSlider; + wi::gui::Button renderButton; + bool renderEnabled = false; + wi::gui::Slider resolutionXSlider; + wi::gui::Slider resolutionYSlider; + wi::gui::Slider samplecountSlider; + CameraPreview preview; void ResizeLayout() override; diff --git a/Editor/MaterialWindow.cpp b/Editor/MaterialWindow.cpp index 567adf7c3..1745be353 100644 --- a/Editor/MaterialWindow.cpp +++ b/Editor/MaterialWindow.cpp @@ -355,6 +355,27 @@ void MaterialWindow::Create(EditorComponent* _editor) AddWidget(&shadingRateComboBox); + cameraComboBox.Create("Camera source: "); + cameraComboBox.SetTooltip("Select a camera to use as texture"); + cameraComboBox.OnSelect([&](wi::gui::EventArgs args) { + wi::scene::Scene& scene = editor->GetCurrentScene(); + for (auto& x : editor->translator.selected) + { + MaterialComponent* material = get_material(scene, x); + if (material == nullptr) + continue; + material->cameraSource = (Entity)args.userdata; + } + + CameraComponent* camera = scene.cameras.GetComponent((Entity)args.userdata); + if (camera != nullptr) + { + camera->render_to_texture.resolution = XMUINT2(256, 256); + } + }); + AddWidget(&cameraComboBox); + + // Sliders: @@ -1254,6 +1275,19 @@ void MaterialWindow::SetEntity(Entity entity) } shadingRateComboBox.SetSelectedWithoutCallback((int)material->shadingRate); + cameraComboBox.ClearItems(); + cameraComboBox.AddItem("INVALID_ENTITY", (uint64_t)INVALID_ENTITY); + for (size_t i = 0; i < scene.cameras.GetCount(); ++i) + { + Entity cameraEntity = scene.cameras.GetEntity(i); + const NameComponent* name = scene.names.GetComponent(cameraEntity); + if (name != nullptr) + { + cameraComboBox.AddItem(name->name, (uint64_t)cameraEntity); + } + } + cameraComboBox.SetSelectedByUserdataWithoutCallback((uint64_t)material->cameraSource); + colorComboBox.SetEnabled(true); colorPicker.SetEnabled(true); @@ -1400,6 +1434,7 @@ void MaterialWindow::ResizeLayout() add(shaderTypeComboBox); add(blendModeComboBox); add(shadingRateComboBox); + add(cameraComboBox); add(alphaRefSlider); add(normalMapSlider); add(roughnessSlider); diff --git a/Editor/MaterialWindow.h b/Editor/MaterialWindow.h index 6ecf8b2a7..cef5846bf 100644 --- a/Editor/MaterialWindow.h +++ b/Editor/MaterialWindow.h @@ -28,6 +28,7 @@ public: wi::gui::ComboBox shaderTypeComboBox; wi::gui::ComboBox blendModeComboBox; wi::gui::ComboBox shadingRateComboBox; + wi::gui::ComboBox cameraComboBox; wi::gui::Slider normalMapSlider; wi::gui::Slider roughnessSlider; wi::gui::Slider reflectanceSlider; diff --git a/WickedEngine/wiGraphicsDevice_DX12.cpp b/WickedEngine/wiGraphicsDevice_DX12.cpp index 9d5f9f436..72cdfa7fb 100644 --- a/WickedEngine/wiGraphicsDevice_DX12.cpp +++ b/WickedEngine/wiGraphicsDevice_DX12.cpp @@ -42,6 +42,10 @@ namespace dx12_internal static constexpr int BINDLESS_RESOURCE_CAPACITY = 500000; static constexpr int BINDLESS_SAMPLER_CAPACITY = 256; +#ifdef PLATFORM_XBOX +// No renderpass API on xbox yet +#define DISABLE_RENDERPASS +#endif // PLATFORM_XBOX #ifdef PLATFORM_WINDOWS_DESKTOP // On Windows PC we load DLLs manually because graphics device can be chosen at runtime: @@ -5921,7 +5925,7 @@ std::mutex queue_locker; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; commandlist.renderpass_barriers_end.push_back(barrier); -#ifdef PLATFORM_XBOX +#ifdef DISABLE_RENDERPASS commandlist.GetGraphicsCommandList()->OMSetRenderTargets( 1, &internal_state->backbufferRTV[internal_state->GetBufferIndex()], @@ -5944,7 +5948,7 @@ std::mutex queue_locker; RTV.BeginningAccess.Clear.ClearValue.Color[3] = swapchain->desc.clear_color[3]; RTV.EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE; commandlist.GetGraphicsCommandListLatest()->BeginRenderPass(1, &RTV, nullptr, D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES); -#endif // PLATFORM_XBOX +#endif // DISABLE_RENDERPASS commandlist.renderpass_info = RenderPassInfo::from(swapchain->desc); } @@ -6249,7 +6253,7 @@ std::mutex queue_locker; commandlist.GetGraphicsCommandListLatest()->RSSetShadingRateImage(commandlist.shading_rate_image); } -#ifdef PLATFORM_XBOX +#ifdef DISABLE_RENDERPASS D3D12_CPU_DESCRIPTOR_HANDLE rt_descriptors[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {}; for (uint32_t i = 0; i < rt_count; ++i) @@ -6318,7 +6322,7 @@ std::mutex queue_locker; DSV.cpuDescriptor.ptr == 0 ? nullptr : &DSV, FLAGS ); -#endif // PLATFORM_XBOX +#endif // DISABLE_RENDERPASS commandlist.renderpass_info = RenderPassInfo::from(images, image_count); } @@ -6326,7 +6330,7 @@ std::mutex queue_locker; { CommandList_DX12& commandlist = GetCommandList(cmd); -#ifdef PLATFORM_XBOX +#ifdef DISABLE_RENDERPASS // Batch up resolve SRC barriers since XBOX cannot do it with RenderPass: commandlist.resolve_src_barriers.clear(); for (uint32_t rt = 0; rt < commandlist.renderpass_info.rt_count; ++rt) @@ -6353,7 +6357,10 @@ std::mutex queue_locker; barrier.Transition.Subresource = resolve.SrcSubresource; } } - commandlist.GetGraphicsCommandList()->ResourceBarrier((UINT)commandlist.resolve_src_barriers.size(), commandlist.resolve_src_barriers.data()); + if (!commandlist.resolve_src_barriers.empty()) + { + commandlist.GetGraphicsCommandList()->ResourceBarrier((UINT)commandlist.resolve_src_barriers.size(), commandlist.resolve_src_barriers.data()); + } // Perform all resolves: for (uint32_t rt = 0; rt < commandlist.renderpass_info.rt_count; ++rt) @@ -6383,9 +6390,18 @@ std::mutex queue_locker; } } + if (!commandlist.resolve_src_barriers.empty()) + { + for (auto& barrier : commandlist.resolve_src_barriers) + { + std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter); + } + commandlist.GetGraphicsCommandList()->ResourceBarrier((UINT)commandlist.resolve_src_barriers.size(), commandlist.resolve_src_barriers.data()); + } + #else commandlist.GetGraphicsCommandListLatest()->EndRenderPass(); -#endif // PLATFORM_XBOX +#endif // DISABLE_RENDERPASS if (commandlist.shading_rate_image != nullptr) { diff --git a/WickedEngine/wiRenderPath3D.cpp b/WickedEngine/wiRenderPath3D.cpp index 9ed7f56bd..0f68c766a 100644 --- a/WickedEngine/wiRenderPath3D.cpp +++ b/WickedEngine/wiRenderPath3D.cpp @@ -7,6 +7,8 @@ using namespace wi::graphics; using namespace wi::enums; +using namespace wi::scene; +using namespace wi::ecs; namespace wi { @@ -412,6 +414,91 @@ namespace wi wi::renderer::UpdateVisibility(visibility_reflection); } + // Render-to-texture camera components: + for (uint32_t i = 0; i < scene->cameras.GetCount(); ++i) + { + wi::scene::CameraComponent& camera = scene->cameras[i]; + if (camera.render_to_texture.resolution.x == 0 || camera.render_to_texture.resolution.y == 0) + { + camera.render_to_texture = {}; + continue; + } + if (!camera.render_to_texture.rendertarget_render.IsValid() || + camera.render_to_texture.rendertarget_render.desc.width != camera.render_to_texture.resolution.x || + camera.render_to_texture.rendertarget_render.desc.height != camera.render_to_texture.resolution.y || + camera.render_to_texture.rendertarget_MSAA.desc.sample_count != camera.render_to_texture.sample_count + ) + { + TextureDesc desc; + desc.width = camera.render_to_texture.resolution.x; + desc.height = camera.render_to_texture.resolution.y; + desc.format = wi::renderer::format_rendertarget_main; + desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE; + bool success = device->CreateTexture(&desc, nullptr, &camera.render_to_texture.rendertarget_render); + assert(success); + device->SetName(&camera.render_to_texture.rendertarget_render, "CameraComponent::RenderToTexture::rendertarget_render"); + success = device->CreateTexture(&desc, nullptr, &camera.render_to_texture.rendertarget_display); + assert(success); + device->SetName(&camera.render_to_texture.rendertarget_display, "CameraComponent::RenderToTexture::rendertarget_display"); + + if (camera.render_to_texture.sample_count > 1) + { + desc.sample_count = camera.render_to_texture.sample_count; + desc.layout = ResourceState::RENDERTARGET; + desc.bind_flags = BindFlag::RENDER_TARGET; + success = device->CreateTexture(&desc, nullptr, &camera.render_to_texture.rendertarget_MSAA); + assert(success); + device->SetName(&camera.render_to_texture.rendertarget_MSAA, "CameraComponent::RenderToTexture::rendertarget_MSAA"); + } + else + { + camera.render_to_texture.rendertarget_MSAA = {}; + } + + desc.format = wi::renderer::format_depthbuffer_main; + desc.bind_flags = BindFlag::DEPTH_STENCIL | BindFlag::SHADER_RESOURCE; + desc.layout = ResourceState::SHADER_RESOURCE; + success = device->CreateTexture(&desc, nullptr, &camera.render_to_texture.depthstencil); + assert(success); + device->SetName(&camera.render_to_texture.depthstencil, "CameraComponent::RenderToTexture::depthstencil"); + + if (camera.render_to_texture.sample_count > 1) + { + desc.sample_count = 1; + desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS; + desc.layout = ResourceState::SHADER_RESOURCE; + desc.format = Format::R32_FLOAT; + success = device->CreateTexture(&desc, nullptr, &camera.render_to_texture.depthstencil_resolved); + assert(success); + device->SetName(&camera.render_to_texture.depthstencil_resolved, "CameraComponent::RenderToTexture::depthstencil_resolved"); + } + else + { + camera.render_to_texture.depthstencil_resolved = {}; + } + + wi::renderer::TiledLightResources tiledres; + wi::renderer::CreateTiledLightResources(tiledres, camera.render_to_texture.resolution); + camera.render_to_texture.tileCount = tiledres.tileCount; + camera.render_to_texture.entityTiles = tiledres.entityTiles; + } + if (getSceneUpdateEnabled()) + { + std::swap(camera.render_to_texture.rendertarget_render, camera.render_to_texture.rendertarget_display); + } + camera.width = (float)camera.render_to_texture.resolution.x; + camera.height = (float)camera.render_to_texture.resolution.y; + if (camera.render_to_texture.depthstencil_resolved.IsValid()) + { + camera.texture_depth_index = device->GetDescriptorIndex(&camera.render_to_texture.depthstencil_resolved, SubresourceType::SRV); + } + else + { + camera.texture_depth_index = device->GetDescriptorIndex(&camera.render_to_texture.depthstencil, SubresourceType::SRV); + } + camera.buffer_entitytiles_index = device->GetDescriptorIndex(&camera.render_to_texture.entityTiles, SubresourceType::SRV); + } + XMUINT2 internalResolution = GetInternalResolution(); wi::renderer::UpdatePerFrameData( @@ -1770,6 +1857,8 @@ namespace wi } }); + RenderCameraComponents(); + cmd = device->BeginCommandList(); wi::jobsystem::Execute(ctx, [this, cmd](wi::jobsystem::JobArgs args) { RenderPostprocessChain(cmd); @@ -2549,6 +2638,114 @@ namespace wi } } + void RenderPath3D::RenderCameraComponents() const + { + GraphicsDevice* device = GetDevice(); + + // Render-to-texture camera components: + for (uint32_t i = 0; i < scene->cameras.GetCount() && getSceneUpdateEnabled(); ++i) + { + const wi::scene::CameraComponent& camera = scene->cameras[i]; + if (camera.render_to_texture.resolution.x == 0 || camera.render_to_texture.resolution.y == 0) + continue; + if (!camera.render_to_texture.rendertarget_render.IsValid()) + continue; + if (!camera.render_to_texture.depthstencil.IsValid()) + continue; + + // Note: this runs on the main thread to reduce memory usage with some shared resources + wi::renderer::Visibility& visibility = visibility_subcam_shared; + visibility.layerMask = getLayerMask(); + visibility.scene = scene; + visibility.camera = &camera; + visibility.flags = wi::renderer::Visibility::ALLOW_OBJECTS; + visibility.flags |= wi::renderer::Visibility::ALLOW_LIGHTS; + visibility.flags |= wi::renderer::Visibility::ALLOW_DECALS; + visibility.flags |= wi::renderer::Visibility::ALLOW_ENVPROBES; + visibility.flags |= wi::renderer::Visibility::ALLOW_HAIRS; + wi::renderer::UpdateVisibility(visibility); + + // Note: I start a new commandlist for each camera, + // because there is some crash in DX12 with multiple MSAA resolves in the same renderpass with no info + CommandList cmd = device->BeginCommandList(); + + ScopedGPUProfiling("Camera Entity", cmd); + device->EventBegin("Camera Entity", cmd); + wi::renderer::BindCommonResources(cmd); + wi::renderer::BindCameraCB( + camera, + camera, + camera, + cmd + ); + Rect scissor; + scissor.right = (int32_t)camera.render_to_texture.depthstencil.desc.width; + scissor.bottom = (int32_t)camera.render_to_texture.depthstencil.desc.height; + device->BindScissorRects(1, &scissor, cmd); + Viewport vp; + vp.width = (float)camera.render_to_texture.depthstencil.desc.width; + vp.height = (float)camera.render_to_texture.depthstencil.desc.height; + device->BindViewports(1, &vp, cmd); + // prepass: + { + RenderPassImage rp[] = { + RenderPassImage::DepthStencil(&camera.render_to_texture.depthstencil, RenderPassImage::LoadOp::CLEAR, RenderPassImage::StoreOp::STORE, camera.render_to_texture.depthstencil.desc.layout, ResourceState::DEPTHSTENCIL, ResourceState::SHADER_RESOURCE), + }; + device->RenderPassBegin(rp, arraysize(rp), cmd); + wi::renderer::DrawScene( + visibility, + RENDERPASS_PREPASS_DEPTHONLY, + cmd, + wi::renderer::DRAWSCENE_OPAQUE | + wi::renderer::DRAWSCENE_IMPOSTOR | + wi::renderer::DRAWSCENE_HAIRPARTICLE + ); + device->RenderPassEnd(cmd); + } + if (camera.render_to_texture.depthstencil_resolved.IsValid()) + { + wi::renderer::ResolveMSAADepthBuffer(camera.render_to_texture.depthstencil_resolved, camera.render_to_texture.depthstencil, cmd); + } + wi::renderer::TiledLightResources tiledres; + tiledres.tileCount = camera.render_to_texture.tileCount; + tiledres.entityTiles = camera.render_to_texture.entityTiles; + wi::renderer::ComputeTiledLightCulling(tiledres, visibility, {}, cmd); + // color pass: + { + RenderPassImage rp[3]; + uint32_t rp_count = 0; + if (camera.render_to_texture.rendertarget_MSAA.IsValid()) + { + rp[rp_count++] = RenderPassImage::RenderTarget(&camera.render_to_texture.rendertarget_MSAA, RenderPassImage::LoadOp::CLEAR, RenderPassImage::StoreOp::DONTCARE, ResourceState::RENDERTARGET, ResourceState::RENDERTARGET); + rp[rp_count++] = RenderPassImage::Resolve(&camera.render_to_texture.rendertarget_render); + } + else + { + rp[rp_count++] = RenderPassImage::RenderTarget(&camera.render_to_texture.rendertarget_render, RenderPassImage::LoadOp::CLEAR); + } + rp[rp_count++] = RenderPassImage::DepthStencil(&camera.render_to_texture.depthstencil, RenderPassImage::LoadOp::LOAD, RenderPassImage::StoreOp::DONTCARE, ResourceState::SHADER_RESOURCE, ResourceState::DEPTHSTENCIL, camera.render_to_texture.depthstencil.desc.layout); + device->RenderPassBegin(rp, rp_count, cmd); + wi::renderer::DrawScene( + visibility, + RENDERPASS_MAIN, + cmd, + wi::renderer::DRAWSCENE_OPAQUE | + wi::renderer::DRAWSCENE_IMPOSTOR | + wi::renderer::DRAWSCENE_HAIRPARTICLE + ); + wi::renderer::DrawScene( + visibility, + RENDERPASS_MAIN, + cmd, + wi::renderer::DRAWSCENE_TRANSPARENT + ); + wi::renderer::DrawSky(*scene, cmd); + device->RenderPassEnd(cmd); + } + device->EventEnd(cmd); + } + } + void RenderPath3D::setAO(AO value) { ao = value; diff --git a/WickedEngine/wiRenderPath3D.h b/WickedEngine/wiRenderPath3D.h index de69a6b75..0afe2e331 100644 --- a/WickedEngine/wiRenderPath3D.h +++ b/WickedEngine/wiRenderPath3D.h @@ -87,6 +87,8 @@ namespace wi mutable bool first_frame = true; mutable bool prerender_happened = false; + void RenderCameraComponents() const; + public: wi::graphics::Texture rtMain; wi::graphics::Texture rtMain_render; // can be MSAA @@ -184,6 +186,7 @@ namespace wi wi::scene::Scene* scene = &wi::scene::GetScene(); wi::renderer::Visibility visibility_main; wi::renderer::Visibility visibility_reflection; + mutable wi::renderer::Visibility visibility_subcam_shared; FrameCB frameCB = {}; diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index a6c23b002..a506b8459 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -11,6 +11,7 @@ #include "shaders/ShaderInterop_Renderer.h" #include "shaders/ShaderInterop_SurfelGI.h" #include "wiVector.h" +#include "wiSpinLock.h" #include #include diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 307ed0dc8..1407ca19e 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -4080,6 +4080,18 @@ namespace wi::scene material.WriteShaderTextureSlot(materialArrayMapped + args.jobIndex, EMISSIVEMAP, descriptor); } + if (material.cameraSource != INVALID_ENTITY) + { + const CameraComponent* camera = cameras.GetComponent(material.cameraSource); + if (camera != nullptr && camera->render_to_texture.rendertarget_render.IsValid()) + { + // Camera attachment will overwrite texture slots on shader side: + int descriptor = GetDevice()->GetDescriptorIndex(&camera->render_to_texture.rendertarget_render, SubresourceType::SRV); + material.WriteShaderTextureSlot(materialArrayMapped + args.jobIndex, BASECOLORMAP, descriptor); + material.WriteShaderTextureSlot(materialArrayMapped + args.jobIndex, EMISSIVEMAP, descriptor); + } + } + if (textureStreamingFeedbackMapped != nullptr) { const uint32_t request_packed = textureStreamingFeedbackMapped[args.jobIndex]; diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index b3e8641a0..1364f28c1 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -32,7 +32,7 @@ namespace wi::scene wi::ecs::ComponentManager& layers = componentLibrary.Register("wi::scene::Scene::layers"); wi::ecs::ComponentManager& transforms = componentLibrary.Register("wi::scene::Scene::transforms"); wi::ecs::ComponentManager& hierarchy = componentLibrary.Register("wi::scene::Scene::hierarchy"); - wi::ecs::ComponentManager& materials = componentLibrary.Register("wi::scene::Scene::materials", 9); // version = 9 + wi::ecs::ComponentManager& materials = componentLibrary.Register("wi::scene::Scene::materials", 10); // version = 10 wi::ecs::ComponentManager& meshes = componentLibrary.Register("wi::scene::Scene::meshes", 4); // version = 4 wi::ecs::ComponentManager& impostors = componentLibrary.Register("wi::scene::Scene::impostors"); wi::ecs::ComponentManager& objects = componentLibrary.Register("wi::scene::Scene::objects", 4); // version = 4 @@ -40,7 +40,7 @@ namespace wi::scene wi::ecs::ComponentManager& softbodies = componentLibrary.Register("wi::scene::Scene::softbodies", 3); // version = 3 wi::ecs::ComponentManager& armatures = componentLibrary.Register("wi::scene::Scene::armatures"); wi::ecs::ComponentManager& lights = componentLibrary.Register("wi::scene::Scene::lights", 3); // version = 3 - wi::ecs::ComponentManager& cameras = componentLibrary.Register("wi::scene::Scene::cameras", 1); // version = 1 + wi::ecs::ComponentManager& cameras = componentLibrary.Register("wi::scene::Scene::cameras", 2); // version = 2 wi::ecs::ComponentManager& probes = componentLibrary.Register("wi::scene::Scene::probes", 1); // version = 1 wi::ecs::ComponentManager& forces = componentLibrary.Register("wi::scene::Scene::forces", 1); // version = 1 wi::ecs::ComponentManager& decals = componentLibrary.Register("wi::scene::Scene::decals", 1); // version = 1 diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index e33bab7ea..c1c5c600b 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -257,6 +257,8 @@ namespace wi::scene int customShaderID = -1; uint4 userdata = uint4(0, 0, 0, 0); // can be accessed by custom shader + wi::ecs::Entity cameraSource = wi::ecs::INVALID_ENTITY; // take texture from camera render + // Non-serialized attributes: uint32_t layerMask = ~0u; int sampler_descriptor = -1; // optional @@ -1322,6 +1324,19 @@ namespace wi::scene int texture_reprojected_depth_index = -1; uint shadercamera_options = SHADERCAMERA_OPTION_NONE; + struct RenderToTexture + { + XMUINT2 resolution = XMUINT2(0, 0); + uint32_t sample_count = 1; + wi::graphics::Texture rendertarget_MSAA; + wi::graphics::Texture rendertarget_render; + wi::graphics::Texture rendertarget_display; + wi::graphics::Texture depthstencil; + wi::graphics::Texture depthstencil_resolved; + XMUINT2 tileCount = {}; + wi::graphics::GPUBuffer entityTiles; + } render_to_texture; + void CreateOrtho(float newWidth, float newHeight, float newNear, float newFar, float newVerticalSize = 1); void CreatePerspective(float newWidth, float newHeight, float newNear, float newFar, float newFOV = XM_PI / 3.0f); void UpdateCamera(); diff --git a/WickedEngine/wiScene_Decl.h b/WickedEngine/wiScene_Decl.h index 09ec07da1..ac658857b 100644 --- a/WickedEngine/wiScene_Decl.h +++ b/WickedEngine/wiScene_Decl.h @@ -24,5 +24,6 @@ namespace wi::scene struct SoundComponent; struct InverseKinematicsComponent; struct SpringComponent; + struct ColliderComponent; struct Scene; } diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index 4b0d9fec6..a09a2e79c 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -262,6 +262,10 @@ namespace wi::scene archive >> interiorMappingOffset; archive >> interiorMappingRotation; } + if (seri.GetVersion() >= 10) + { + SerializeEntity(archive, cameraSource, seri); + } for (auto& x : textures) { @@ -433,6 +437,10 @@ namespace wi::scene archive << interiorMappingOffset; archive << interiorMappingRotation; } + if (seri.GetVersion() >= 10) + { + SerializeEntity(archive, cameraSource, seri); + } } } void MeshComponent::Serialize(wi::Archive& archive, EntitySerializer& seri) @@ -1201,6 +1209,12 @@ namespace wi::scene archive >> ortho_vertical_size; } + if (seri.GetVersion() >= 2) + { + archive >> render_to_texture.resolution; + archive >> render_to_texture.sample_count; + } + SetDirty(); } else @@ -1223,6 +1237,12 @@ namespace wi::scene { archive << ortho_vertical_size; } + + if (seri.GetVersion() >= 2) + { + archive << render_to_texture.resolution; + archive << render_to_texture.sample_count; + } } } void EnvironmentProbeComponent::Serialize(wi::Archive& archive, EntitySerializer& seri) diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index a54e92cda..e424722fb 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 721; + const int revision = 722; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);