WIP
This commit is contained in:
parent
4a10c1f8fe
commit
e990a320cc
|
|
@ -159,7 +159,7 @@ int main()
|
|||
skyboxPipelineInfo.depthBuffer = true;
|
||||
skyboxPipelineInfo.depthCompare = Nz::RendererComparison::Equal;
|
||||
skyboxPipelineInfo.faceCulling = true;
|
||||
skyboxPipelineInfo.cullingSide = Nz::FaceSide::Front;
|
||||
skyboxPipelineInfo.faceCulling = Nz::FaceCulling::Front;
|
||||
skyboxPipelineInfo.pipelineLayout = skyboxPipelineLayout;
|
||||
skyboxPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, shaderDir / "skybox.nzsl", states));
|
||||
skyboxPipelineInfo.vertexBuffers.push_back({
|
||||
|
|
@ -558,7 +558,7 @@ int main()
|
|||
});
|
||||
lightingPipelineInfo.depthBuffer = false;
|
||||
lightingPipelineInfo.faceCulling = true;
|
||||
lightingPipelineInfo.cullingSide = Nz::FaceSide::Front;
|
||||
lightingPipelineInfo.faceCulling = Nz::FaceCulling::Front;
|
||||
lightingPipelineInfo.stencilTest = true;
|
||||
lightingPipelineInfo.stencilBack.compare = Nz::RendererComparison::NotEqual;
|
||||
lightingPipelineInfo.stencilBack.fail = Nz::StencilOperation::Zero;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ int main()
|
|||
if (std::getchar() == 'y')
|
||||
rendererConfig.preferredAPI = Nz::RenderAPI::Vulkan;
|
||||
else
|
||||
rendererConfig.preferredAPI = Nz::RenderAPI::Vulkan;
|
||||
rendererConfig.preferredAPI = Nz::RenderAPI::OpenGL;
|
||||
|
||||
Nz::Modules<Nz::Graphics> nazara(rendererConfig);
|
||||
|
||||
|
|
|
|||
|
|
@ -196,11 +196,11 @@ int main()
|
|||
|
||||
std::shared_ptr<Nz::RenderPipelineLayout> basePipelineLayout = device->InstantiateRenderPipelineLayout(pipelineLayoutInfo);
|
||||
|
||||
auto& textureBinding = pipelineLayoutInfo.bindings.emplace_back();
|
||||
textureBinding.setIndex = 1;
|
||||
textureBinding.bindingIndex = 0;
|
||||
textureBinding.shaderStageFlags = nzsl::ShaderStageType::Fragment;
|
||||
textureBinding.type = Nz::ShaderBindingType::Texture;
|
||||
auto& pipelineTextureBinding = pipelineLayoutInfo.bindings.emplace_back();
|
||||
pipelineTextureBinding.setIndex = 1;
|
||||
pipelineTextureBinding.bindingIndex = 0;
|
||||
pipelineTextureBinding.shaderStageFlags = nzsl::ShaderStageType::Fragment;
|
||||
pipelineTextureBinding.type = Nz::ShaderBindingType::Texture;
|
||||
|
||||
std::shared_ptr<Nz::RenderPipelineLayout> renderPipelineLayout = device->InstantiateRenderPipelineLayout(std::move(pipelineLayoutInfo));
|
||||
|
||||
|
|
@ -218,11 +218,15 @@ int main()
|
|||
}
|
||||
});
|
||||
|
||||
Nz::ShaderBinding::TextureBinding textureBinding {
|
||||
texture.get(), textureSampler.get()
|
||||
};
|
||||
|
||||
textureShaderBinding->Update({
|
||||
{
|
||||
0,
|
||||
Nz::ShaderBinding::TextureBinding {
|
||||
texture.get(), textureSampler.get()
|
||||
Nz::ShaderBinding::TextureBindings {
|
||||
1, &textureBinding
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -31,7 +31,11 @@ int main()
|
|||
resourceDir = "../.." / resourceDir;
|
||||
|
||||
Nz::Renderer::Config rendererConfig;
|
||||
rendererConfig.preferredAPI = Nz::RenderAPI::OpenGL;
|
||||
std::cout << "Run using Vulkan? (y/n)" << std::endl;
|
||||
if (std::getchar() == 'y')
|
||||
rendererConfig.preferredAPI = Nz::RenderAPI::Vulkan;
|
||||
else
|
||||
rendererConfig.preferredAPI = Nz::RenderAPI::OpenGL;
|
||||
|
||||
Nz::Modules<Nz::Graphics> nazara(rendererConfig);
|
||||
|
||||
|
|
@ -70,7 +74,7 @@ int main()
|
|||
playerRotNode.SetParent(playerNode);
|
||||
|
||||
auto& cameraNode = registry.emplace<Nz::NodeComponent>(playerCamera);
|
||||
cameraNode.SetParent(playerRotNode);
|
||||
//cameraNode.SetParent(playerRotNode);
|
||||
|
||||
auto& cameraComponent = registry.emplace<Nz::CameraComponent>(playerCamera, window.GetRenderTarget());
|
||||
cameraComponent.UpdateZNear(0.2f);
|
||||
|
|
@ -160,10 +164,11 @@ int main()
|
|||
|
||||
entt::handle bobEntity = entt::handle(registry, registry.create());
|
||||
entt::entity bobLight = registry.create();
|
||||
|
||||
{
|
||||
auto& lightNode = registry.emplace<Nz::NodeComponent>(bobLight);
|
||||
lightNode.SetPosition(Nz::Vector3f::Up() * 3.f);
|
||||
lightNode.SetRotation(Nz::EulerAnglesf(-90.f, 0.f, 0.f));
|
||||
lightNode.SetPosition(Nz::Vector3f::Up() * 3.f + Nz::Vector3f::Backward() * 1.f);
|
||||
lightNode.SetRotation(Nz::EulerAnglesf(-70.f, 0.f, 0.f));
|
||||
|
||||
auto spotLight = std::make_shared<Nz::SpotLight>();
|
||||
spotLight->UpdateAmbientFactor(1.f);
|
||||
|
|
@ -228,6 +233,36 @@ int main()
|
|||
registry.emplace<Nz::SharedSkeletonComponent>(smallBobEntity, skeleton);
|
||||
}
|
||||
|
||||
std::shared_ptr<Nz::MaterialInstance> textMat = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate();
|
||||
textMat->UpdatePassStates("ForwardPass", [](Nz::RenderStates& renderStates)
|
||||
{
|
||||
renderStates.depthWrite = false;
|
||||
renderStates.blending = true;
|
||||
renderStates.faceCulling = Nz::FaceCulling::None;
|
||||
renderStates.blend.modeColor = Nz::BlendEquation::Add;
|
||||
renderStates.blend.modeAlpha = Nz::BlendEquation::Add;
|
||||
renderStates.blend.srcColor = Nz::BlendFunc::SrcAlpha;
|
||||
renderStates.blend.dstColor = Nz::BlendFunc::InvSrcAlpha;
|
||||
renderStates.blend.srcAlpha = Nz::BlendFunc::One;
|
||||
renderStates.blend.dstAlpha = Nz::BlendFunc::One;
|
||||
return true;
|
||||
});
|
||||
|
||||
textMat->SetValueProperty("AlphaTest", true);
|
||||
|
||||
std::shared_ptr<Nz::TextSprite> sprite = std::make_shared<Nz::TextSprite>(textMat);
|
||||
sprite->UpdateRenderLayer(1);
|
||||
sprite->Update(Nz::SimpleTextDrawer::Draw("Shadow-mapping !", 72), 0.002f);
|
||||
|
||||
entt::entity textEntity = registry.create();
|
||||
{
|
||||
auto& entityGfx = registry.emplace<Nz::GraphicsComponent>(textEntity);
|
||||
entityGfx.AttachRenderable(sprite, 1);
|
||||
|
||||
auto& entityNode = registry.emplace<Nz::NodeComponent>(textEntity);
|
||||
entityNode.SetPosition(Nz::Vector3f::Up() * 0.5f + Nz::Vector3f::Backward() * 0.66f + Nz::Vector3f::Left() * 0.5f);
|
||||
entityNode.SetRotation(Nz::EulerAnglesf(-45.f, 0.f, 0.f));
|
||||
}
|
||||
|
||||
entt::entity planeEntity = registry.create();
|
||||
Nz::Boxf floorBox;
|
||||
|
|
@ -264,6 +299,20 @@ int main()
|
|||
|
||||
auto& planeBody = registry.emplace<Nz::RigidBody3DComponent>(planeEntity, &physSytem.GetPhysWorld());
|
||||
planeBody.SetGeom(std::make_shared<Nz::BoxCollider3D>(Nz::Vector3f(planeSize.x, 0.5f, planeSize.y), Nz::Vector3f(0.f, -0.25f, 0.f)));
|
||||
|
||||
Nz::Mesh boxMesh;
|
||||
boxMesh.CreateStatic();
|
||||
boxMesh.BuildSubMesh(Nz::Primitive::Box(Nz::Vector3f(0.5f, 0.5f, 0.5f)), meshPrimitiveParams);
|
||||
boxMesh.SetMaterialCount(1);
|
||||
|
||||
std::shared_ptr<Nz::GraphicalMesh> boxMeshGfx = Nz::GraphicalMesh::BuildFromMesh(boxMesh);
|
||||
|
||||
std::shared_ptr<Nz::Model> boxModel = std::make_shared<Nz::Model>(std::move(boxMeshGfx), boxMesh.GetAABB());
|
||||
boxModel->SetMaterial(0, planeMat);
|
||||
|
||||
entt::entity boxEntity = registry.create();
|
||||
registry.emplace<Nz::NodeComponent>(boxEntity).SetPosition(Nz::Vector3f(0.f, 0.25f, -0.5f));
|
||||
registry.emplace<Nz::GraphicsComponent>(boxEntity).AttachRenderable(boxModel, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
window.EnableEventPolling(true);
|
||||
|
|
@ -308,7 +357,9 @@ int main()
|
|||
// Idem, mais pour éviter les problèmes de calcul de la matrice de vue, on restreint les angles
|
||||
camAngles.pitch = Nz::Clamp(camAngles.pitch - event.mouseMove.deltaY * sensitivity, -89.f, 89.f);
|
||||
|
||||
auto& playerRotNode = registry.get<Nz::NodeComponent>(playerRotation);
|
||||
/*auto& playerRotNode = registry.get<Nz::NodeComponent>(playerRotation);
|
||||
playerRotNode.SetRotation(camAngles);*/
|
||||
auto& playerRotNode = registry.get<Nz::NodeComponent>(playerCamera);
|
||||
playerRotNode.SetRotation(camAngles);
|
||||
break;
|
||||
}
|
||||
|
|
@ -322,7 +373,7 @@ int main()
|
|||
{
|
||||
float updateTime = updateClock.Restart() / 1'000'000.f;
|
||||
|
||||
auto& playerBody = registry.get<Nz::RigidBody3DComponent>(playerEntity);
|
||||
/*auto& playerBody = registry.get<Nz::RigidBody3DComponent>(playerEntity);
|
||||
|
||||
float mass = playerBody.GetMass();
|
||||
|
||||
|
|
@ -339,7 +390,25 @@ int main()
|
|||
playerBody.AddForce(Nz::Vector3f::Left() * 25.f * mass, Nz::CoordSys::Local);
|
||||
|
||||
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Right) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::D))
|
||||
playerBody.AddForce(Nz::Vector3f::Right() * 25.f * mass, Nz::CoordSys::Local);
|
||||
playerBody.AddForce(Nz::Vector3f::Right() * 25.f * mass, Nz::CoordSys::Local);*/
|
||||
|
||||
float cameraSpeed = 2.f;
|
||||
|
||||
auto& cameraNode = registry.get<Nz::NodeComponent>(playerCamera);
|
||||
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Space))
|
||||
cameraNode.Move(Nz::Vector3f::Up() * cameraSpeed * updateTime, Nz::CoordSys::Global);
|
||||
|
||||
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Up) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Z))
|
||||
cameraNode.Move(Nz::Vector3f::Forward() * cameraSpeed * updateTime, Nz::CoordSys::Local);
|
||||
|
||||
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Down) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::S))
|
||||
cameraNode.Move(Nz::Vector3f::Backward() * cameraSpeed * updateTime, Nz::CoordSys::Local);
|
||||
|
||||
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Left) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Q))
|
||||
cameraNode.Move(Nz::Vector3f::Left() * cameraSpeed * updateTime, Nz::CoordSys::Local);
|
||||
|
||||
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Right) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::D))
|
||||
cameraNode.Move(Nz::Vector3f::Right() * cameraSpeed * updateTime, Nz::CoordSys::Local);
|
||||
|
||||
if (!paused)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace Nz
|
|||
class NAZARA_GRAPHICS_API DepthPipelinePass : public FramePipelinePass
|
||||
{
|
||||
public:
|
||||
DepthPipelinePass(FramePipeline& owner, ElementRendererRegistry& elementRegistry, AbstractViewer* viewer);
|
||||
DepthPipelinePass(FramePipeline& owner, ElementRendererRegistry& elementRegistry, AbstractViewer* viewer, std::size_t passIndex, std::string passName);
|
||||
DepthPipelinePass(const DepthPipelinePass&) = delete;
|
||||
DepthPipelinePass(DepthPipelinePass&&) = delete;
|
||||
~DepthPipelinePass() = default;
|
||||
|
|
@ -57,8 +57,9 @@ namespace Nz
|
|||
NazaraSlot(MaterialInstance, OnMaterialInstanceShaderBindingInvalidated, onMaterialInstanceShaderBindingInvalidated);
|
||||
};
|
||||
|
||||
std::size_t m_depthPassIndex;
|
||||
std::size_t m_passIndex;
|
||||
std::size_t m_lastVisibilityHash;
|
||||
std::string m_passName;
|
||||
std::vector<std::unique_ptr<ElementRendererData>> m_elementRendererData;
|
||||
std::vector<ElementRenderer::RenderStates> m_renderStates;
|
||||
std::vector<RenderElementOwner> m_renderElements;
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@
|
|||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/Enums.hpp>
|
||||
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
|
||||
#include <Nazara/Graphics/RenderElementPool.hpp>
|
||||
#include <Nazara/Renderer/RenderBufferView.hpp>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
|
@ -43,6 +45,14 @@ namespace Nz
|
|||
|
||||
struct RenderStates
|
||||
{
|
||||
RenderStates()
|
||||
{
|
||||
shadowMaps2D.fill(nullptr);
|
||||
shadowMapsCube.fill(nullptr);
|
||||
}
|
||||
|
||||
std::array<const Texture*, PredefinedLightData::MaxLightCount> shadowMaps2D;
|
||||
std::array<const Texture*, PredefinedLightData::MaxLightCount> shadowMapsCube;
|
||||
RenderBufferView lightData;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ namespace Nz
|
|||
InstanceDataUbo,
|
||||
LightDataUbo,
|
||||
OverlayTexture,
|
||||
Shadowmap2D,
|
||||
ShadowmapCube,
|
||||
SkeletalDataUbo,
|
||||
ViewerDataUbo,
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ namespace Nz
|
|||
std::size_t RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) override;
|
||||
std::size_t RegisterWorldInstance(WorldInstancePtr worldInstance) override;
|
||||
|
||||
const Light* RetrieveLight(std::size_t lightIndex) const override;
|
||||
const Texture* RetrieveLightShadowmap(std::size_t lightIndex) const override;
|
||||
|
||||
void Render(RenderFrame& renderFrame) override;
|
||||
|
||||
void UnregisterLight(std::size_t lightIndex) override;
|
||||
|
|
@ -147,7 +150,7 @@ namespace Nz
|
|||
std::unordered_map<MaterialInstance*, MaterialInstanceData> m_materialInstances;
|
||||
std::vector<ElementRenderer::RenderStates> m_renderStates;
|
||||
std::vector<FramePipelinePass::VisibleRenderable> m_visibleRenderables;
|
||||
std::vector<const Light*> m_visibleLights;
|
||||
std::vector<std::size_t> m_visibleLights;
|
||||
robin_hood::unordered_set<TransferInterface*> m_transferSet;
|
||||
BakedFrameGraph m_bakedFrameGraph;
|
||||
Bitset<UInt64> m_shadowCastingLights;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace Nz
|
|||
inline void InvalidateCommandBuffers();
|
||||
inline void InvalidateElements();
|
||||
|
||||
void Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, const std::vector<const Light*>& visibleLights, std::size_t visibilityHash);
|
||||
void Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, const std::vector<std::size_t>& visibleLights, std::size_t visibilityHash);
|
||||
|
||||
void RegisterMaterialInstance(const MaterialInstance& material);
|
||||
FramePass& RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t colorBufferIndex, std::size_t depthBufferIndex, bool hasDepthPrepass);
|
||||
|
|
@ -76,11 +76,25 @@ namespace Nz
|
|||
UploadPool::Allocation* allocation = nullptr;
|
||||
};
|
||||
|
||||
struct LightPerElementData
|
||||
{
|
||||
RenderBufferView lightUniformBuffer;
|
||||
std::array<const Texture*, MaxLightCountPerDraw> shadowMaps;
|
||||
std::size_t lightCount;
|
||||
};
|
||||
|
||||
struct LightUboPool
|
||||
{
|
||||
std::vector<std::shared_ptr<RenderBuffer>> lightUboBuffers;
|
||||
};
|
||||
|
||||
struct RenderableLight
|
||||
{
|
||||
const Light* light;
|
||||
std::size_t lightIndex;
|
||||
float contributionScore;
|
||||
};
|
||||
|
||||
std::size_t m_forwardPassIndex;
|
||||
std::size_t m_lastVisibilityHash;
|
||||
std::shared_ptr<LightUboPool> m_lightUboPool;
|
||||
|
|
@ -88,10 +102,10 @@ namespace Nz
|
|||
std::vector<ElementRenderer::RenderStates> m_renderStates;
|
||||
std::vector<RenderElementOwner> m_renderElements;
|
||||
std::unordered_map<const MaterialInstance*, MaterialPassEntry> m_materialInstances;
|
||||
std::unordered_map<const RenderElement*, RenderBufferView> m_lightPerRenderElement;
|
||||
std::unordered_map<const RenderElement*, LightPerElementData> m_lightPerRenderElement;
|
||||
std::unordered_map<LightKey, RenderBufferView, LightKeyHasher> m_lightBufferPerLights;
|
||||
std::vector<LightDataUbo> m_lightDataBuffers;
|
||||
std::vector<const Light*> m_renderableLights;
|
||||
std::vector<RenderableLight> m_renderableLights;
|
||||
RenderQueue<const RenderElement*> m_renderQueue;
|
||||
RenderQueueRegistry m_renderQueueRegistry;
|
||||
AbstractViewer* m_viewer;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ namespace Nz
|
|||
virtual std::size_t RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) = 0;
|
||||
virtual std::size_t RegisterWorldInstance(WorldInstancePtr worldInstance) = 0;
|
||||
|
||||
virtual const Light* RetrieveLight(std::size_t lightIndex) const = 0;
|
||||
virtual const Texture* RetrieveLightShadowmap(std::size_t lightIndex) const = 0;
|
||||
|
||||
virtual void Render(RenderFrame& renderFrame) = 0;
|
||||
|
||||
virtual void UnregisterLight(std::size_t lightIndex) = 0;
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ namespace Nz
|
|||
|
||||
struct DefaultTextures
|
||||
{
|
||||
std::array<std::shared_ptr<Texture>, ImageTypeCount> depthTextures;
|
||||
std::array<std::shared_ptr<Texture>, ImageTypeCount> whiteTextures;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ namespace Nz
|
|||
std::size_t parameter2;
|
||||
std::size_t parameter3;
|
||||
std::size_t shadowMappingFlag;
|
||||
std::size_t viewProjMatrix;
|
||||
};
|
||||
|
||||
std::size_t lightsOffset;
|
||||
|
|
|
|||
|
|
@ -55,9 +55,11 @@ namespace Nz
|
|||
|
||||
private:
|
||||
inline void UpdateBoundingVolume();
|
||||
inline void UpdateViewProjMatrix();
|
||||
|
||||
Color m_color;
|
||||
Quaternionf m_rotation;
|
||||
Matrix4f m_viewProjMatrix;
|
||||
RadianAnglef m_innerAngle;
|
||||
RadianAnglef m_outerAngle;
|
||||
Vector3f m_direction;
|
||||
|
|
|
|||
|
|
@ -97,8 +97,6 @@ namespace Nz
|
|||
{
|
||||
m_innerAngle = innerAngle;
|
||||
m_innerAngleCos = m_innerAngle.GetCos();
|
||||
|
||||
UpdateBoundingVolume();
|
||||
}
|
||||
|
||||
inline void SpotLight::UpdateOuterAngle(RadianAnglef outerAngle)
|
||||
|
|
@ -108,6 +106,7 @@ namespace Nz
|
|||
m_outerAngleTan = m_outerAngle.GetTan();
|
||||
|
||||
UpdateBoundingVolume();
|
||||
UpdateViewProjMatrix();
|
||||
}
|
||||
|
||||
inline void SpotLight::UpdatePosition(const Vector3f& position)
|
||||
|
|
@ -115,6 +114,7 @@ namespace Nz
|
|||
m_position = position;
|
||||
|
||||
UpdateBoundingVolume();
|
||||
UpdateViewProjMatrix();
|
||||
}
|
||||
|
||||
inline void SpotLight::UpdateRadius(float radius)
|
||||
|
|
@ -123,6 +123,7 @@ namespace Nz
|
|||
m_invRadius = 1.f / m_radius;
|
||||
|
||||
UpdateBoundingVolume();
|
||||
UpdateViewProjMatrix();
|
||||
}
|
||||
|
||||
inline void SpotLight::UpdateRotation(const Quaternionf& rotation)
|
||||
|
|
@ -131,6 +132,7 @@ namespace Nz
|
|||
m_direction = rotation * Vector3f::Forward();
|
||||
|
||||
UpdateBoundingVolume();
|
||||
UpdateViewProjMatrix();
|
||||
}
|
||||
|
||||
inline void SpotLight::UpdateBoundingVolume()
|
||||
|
|
@ -158,6 +160,19 @@ namespace Nz
|
|||
|
||||
Light::UpdateBoundingVolume(boundingVolume); //< will trigger OnLightDataInvalided
|
||||
}
|
||||
|
||||
inline void SpotLight::UpdateViewProjMatrix()
|
||||
{
|
||||
Matrix4f biasMatrix(0.5f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.5f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.5f, 0.5f, 0.0f, 1.0f);
|
||||
|
||||
Matrix4f projection = Matrix4f::Perspective(m_outerAngle * 2.f, 1.f, 1.f, m_radius);
|
||||
Matrix4f view = Matrix4f::TransformInverse(m_position, m_rotation);
|
||||
|
||||
m_viewProjMatrix = view * projection * biasMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace Nz
|
|||
|
||||
private:
|
||||
std::vector<ShaderBinding::Binding> m_bindingCache;
|
||||
std::vector<ShaderBinding::TextureBinding> m_textureBindingCache;
|
||||
RenderElementPool<RenderSubmesh> m_submeshPool;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Nz
|
|||
{
|
||||
class OpenGLRenderPipelineLayout;
|
||||
|
||||
class NAZARA_OPENGLRENDERER_API OpenGLShaderBinding : public ShaderBinding
|
||||
class NAZARA_OPENGLRENDERER_API OpenGLShaderBinding final : public ShaderBinding
|
||||
{
|
||||
public:
|
||||
inline OpenGLShaderBinding(OpenGLRenderPipelineLayout& owner, std::size_t poolIndex, std::size_t bindingIndex);
|
||||
|
|
@ -38,6 +38,7 @@ namespace Nz
|
|||
OpenGLShaderBinding& operator=(OpenGLShaderBinding&&) = delete;
|
||||
|
||||
private:
|
||||
void HandleTextureBinding(UInt32 bindingIndex, const TextureBinding& textureBinding);
|
||||
void Release() override;
|
||||
|
||||
OpenGLRenderPipelineLayout& m_owner;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace Nz
|
|||
inline GLenum ToOpenGL(BlendEquation blendEquation);
|
||||
inline GLenum ToOpenGL(BlendFunc blendFunc);
|
||||
inline GLenum ToOpenGL(FaceFilling filling);
|
||||
inline GLenum ToOpenGL(FaceSide side);
|
||||
inline GLenum ToOpenGL(FaceCulling side);
|
||||
inline GLenum ToOpenGL(FrontFace face);
|
||||
inline GLenum ToOpenGL(IndexType indexType);
|
||||
inline GLenum ToOpenGL(PrimitiveMode primitiveMode);
|
||||
|
|
|
|||
|
|
@ -92,16 +92,16 @@ namespace Nz
|
|||
return {};
|
||||
}
|
||||
|
||||
inline GLenum ToOpenGL(FaceSide side)
|
||||
inline GLenum ToOpenGL(FaceCulling side)
|
||||
{
|
||||
switch (side)
|
||||
{
|
||||
case FaceSide::None:
|
||||
case FaceCulling::None:
|
||||
break;
|
||||
|
||||
case FaceSide::Back: return GL_BACK;
|
||||
case FaceSide::Front: return GL_FRONT;
|
||||
case FaceSide::FrontAndBack: return GL_FRONT_AND_BACK;
|
||||
case FaceCulling::Back: return GL_BACK;
|
||||
case FaceCulling::Front: return GL_FRONT;
|
||||
case FaceCulling::FrontAndBack: return GL_FRONT_AND_BACK;
|
||||
}
|
||||
|
||||
NazaraError("Unhandled FaceSide 0x" + NumberToString(UnderlyingCast(side), 16));
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERPROC) (GLuint shader, const GLch
|
|||
cb(glLinkProgram, PFNGLLINKPROGRAMPROC) \
|
||||
cb(glMapBufferRange, PFNGLMAPBUFFERRANGEPROC) \
|
||||
cb(glPixelStorei, PFNGLPIXELSTOREIPROC) \
|
||||
cb(glPolygonOffset, PFNGLPOLYGONOFFSETPROC) \
|
||||
cb(glProgramBinary, PFNGLPROGRAMBINARYPROC) \
|
||||
cb(glProgramParameteri, PFNGLPROGRAMPARAMETERIPROC) \
|
||||
cb(glReadPixels, PFNGLREADPIXELSPROC) \
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ namespace Nz
|
|||
{
|
||||
struct Binding
|
||||
{
|
||||
UInt32 setIndex = 0;
|
||||
UInt32 arraySize = 1;
|
||||
UInt32 bindingIndex;
|
||||
UInt32 setIndex = 0;
|
||||
ShaderBindingType type;
|
||||
nzsl::ShaderStageTypeFlags shaderStageFlags;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,13 +20,13 @@ namespace Nz
|
|||
struct RenderStates
|
||||
{
|
||||
ColorComponentMask colorWriteMask = ColorComponentAll;
|
||||
FaceCulling faceCulling = FaceCulling::Back;
|
||||
FaceFilling faceFilling = FaceFilling::Fill;
|
||||
FaceSide cullingSide = FaceSide::Back;
|
||||
FrontFace frontFace = FrontFace::CounterClockwise;
|
||||
RendererComparison depthCompare = RendererComparison::LessOrEqual;
|
||||
PrimitiveMode primitiveMode = PrimitiveMode::TriangleList;
|
||||
|
||||
struct
|
||||
struct
|
||||
{
|
||||
BlendEquation modeAlpha = BlendEquation::Add;
|
||||
BlendEquation modeColor = BlendEquation::Add;
|
||||
|
|
@ -48,13 +48,15 @@ namespace Nz
|
|||
} stencilBack, stencilFront;
|
||||
|
||||
bool blending = false;
|
||||
bool depthBias = false;
|
||||
bool depthBuffer = false;
|
||||
bool depthClamp = false;
|
||||
bool depthWrite = true;
|
||||
bool faceCulling = false;
|
||||
bool scissorTest = false;
|
||||
bool stencilTest = false;
|
||||
|
||||
float depthBiasConstantFactor = 0.f;
|
||||
float depthBiasSlopeFactor = 0.f;
|
||||
float lineWidth = 1.f;
|
||||
float pointSize = 1.f;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ namespace Nz
|
|||
#define NazaraRenderStateFloatMember(field, maxDiff) if (!NumberEquals(lhs.field, rhs.field, maxDiff)) return false
|
||||
|
||||
NazaraRenderStateBoolMember(blending);
|
||||
NazaraRenderStateBoolMember(depthBias);
|
||||
NazaraRenderStateBoolMember(depthBuffer);
|
||||
NazaraRenderStateBoolMember(depthClamp);
|
||||
NazaraRenderStateBoolMember(faceCulling);
|
||||
NazaraRenderStateBoolMember(scissorTest);
|
||||
NazaraRenderStateBoolMember(stencilTest);
|
||||
|
||||
|
|
@ -27,6 +27,7 @@ namespace Nz
|
|||
NazaraRenderStateBoolMember(depthWrite);
|
||||
|
||||
NazaraRenderStateMember(colorWriteMask);
|
||||
NazaraRenderStateMember(faceCulling);
|
||||
NazaraRenderStateMember(faceFilling);
|
||||
|
||||
if (lhs.blending) //< Remember, at this time we know lhs.blending == rhs.blending
|
||||
|
|
@ -42,8 +43,11 @@ namespace Nz
|
|||
if (lhs.depthBuffer)
|
||||
NazaraRenderStateMember(depthCompare);
|
||||
|
||||
if (lhs.faceCulling)
|
||||
NazaraRenderStateMember(cullingSide);
|
||||
if (lhs.depthBias)
|
||||
{
|
||||
NazaraRenderStateMember(depthBiasConstantFactor);
|
||||
NazaraRenderStateMember(depthBiasSlopeFactor);
|
||||
}
|
||||
|
||||
if (lhs.stencilTest)
|
||||
{
|
||||
|
|
@ -95,15 +99,16 @@ namespace std
|
|||
#define NazaraRenderStateUInt32(member) Nz::HashCombine(seed, pipelineInfo.member)
|
||||
|
||||
NazaraRenderStateBool(blending);
|
||||
NazaraRenderStateBool(depthBias);
|
||||
NazaraRenderStateBool(depthBuffer);
|
||||
NazaraRenderStateBool(depthClamp);
|
||||
NazaraRenderStateBool(faceCulling);
|
||||
NazaraRenderStateBool(scissorTest);
|
||||
NazaraRenderStateBool(stencilTest);
|
||||
|
||||
NazaraRenderStateBoolDep(depthBuffer, depthWrite);
|
||||
|
||||
NazaraRenderStateUInt8(colorWriteMask);
|
||||
NazaraRenderStateEnum(faceCulling);
|
||||
NazaraRenderStateEnum(faceFilling);
|
||||
|
||||
if (pipelineInfo.blending) //< we don't care about blending state if blending isn't enabled
|
||||
|
|
@ -119,8 +124,11 @@ namespace std
|
|||
if (pipelineInfo.depthBuffer)
|
||||
NazaraRenderStateEnum(depthCompare);
|
||||
|
||||
if (pipelineInfo.faceCulling)
|
||||
NazaraRenderStateEnum(cullingSide);
|
||||
if (pipelineInfo.depthBias)
|
||||
{
|
||||
NazaraRenderStateFloat(depthBiasConstantFactor, 0.001f);
|
||||
NazaraRenderStateFloat(depthBiasSlopeFactor, 0.001f);
|
||||
}
|
||||
|
||||
if (pipelineInfo.stencilTest) //< we don't care about stencil state if stencil isn't enabled
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@ namespace Nz
|
|||
const TextureSampler* sampler;
|
||||
};
|
||||
|
||||
struct TextureBindings
|
||||
{
|
||||
UInt32 arraySize;
|
||||
const TextureBinding* textureBindings;
|
||||
};
|
||||
|
||||
struct UniformBufferBinding
|
||||
{
|
||||
RenderBuffer* buffer;
|
||||
|
|
@ -66,7 +72,7 @@ namespace Nz
|
|||
struct Binding
|
||||
{
|
||||
UInt32 bindingIndex;
|
||||
std::variant<StorageBufferBinding, TextureBinding, UniformBufferBinding> content;
|
||||
std::variant<StorageBufferBinding, TextureBinding, TextureBindings, UniformBufferBinding> content;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ namespace Nz
|
|||
SamplerWrap wrapModeU = SamplerWrap::Clamp;
|
||||
SamplerWrap wrapModeV = SamplerWrap::Clamp;
|
||||
SamplerWrap wrapModeW = SamplerWrap::Clamp;
|
||||
bool depthCompare = false;
|
||||
RendererComparison depthComparison = RendererComparison::LessOrEqual;
|
||||
|
||||
inline bool operator==(const TextureSamplerInfo& samplerInfo) const;
|
||||
inline bool operator!=(const TextureSamplerInfo& samplerInfo) const;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,12 @@ namespace Nz
|
|||
if (wrapModeW != samplerInfo.wrapModeW)
|
||||
return false;
|
||||
|
||||
if (depthCompare != samplerInfo.depthCompare)
|
||||
return false;
|
||||
|
||||
if (depthComparison != samplerInfo.depthComparison)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +60,8 @@ struct std::hash<Nz::TextureSamplerInfo>
|
|||
Nz::HashCombine(seed, sampler.wrapModeU);
|
||||
Nz::HashCombine(seed, sampler.wrapModeV);
|
||||
Nz::HashCombine(seed, sampler.wrapModeW);
|
||||
Nz::HashCombine(seed, sampler.depthCompare);
|
||||
Nz::HashCombine(seed, sampler.depthComparison);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ namespace Nz
|
|||
Max = Point
|
||||
};
|
||||
|
||||
enum class FaceSide
|
||||
enum class FaceCulling
|
||||
{
|
||||
None,
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Nz
|
|||
inline VkAttachmentStoreOp ToVulkan(AttachmentStoreOp storeOp);
|
||||
inline VkBufferUsageFlags ToVulkan(BufferType bufferType);
|
||||
inline VkFormat ToVulkan(ComponentType componentType);
|
||||
inline VkCullModeFlagBits ToVulkan(FaceSide faceSide);
|
||||
inline VkCullModeFlagBits ToVulkan(FaceCulling faceSide);
|
||||
inline VkPolygonMode ToVulkan(FaceFilling faceFilling);
|
||||
inline VkFrontFace ToVulkan(FrontFace frontFace);
|
||||
inline VkIndexType ToVulkan(IndexType indexType);
|
||||
|
|
|
|||
|
|
@ -130,14 +130,14 @@ namespace Nz
|
|||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
|
||||
inline VkCullModeFlagBits ToVulkan(FaceSide faceSide)
|
||||
inline VkCullModeFlagBits ToVulkan(FaceCulling faceSide)
|
||||
{
|
||||
switch (faceSide)
|
||||
{
|
||||
case FaceSide::None: return VK_CULL_MODE_NONE;
|
||||
case FaceSide::Back: return VK_CULL_MODE_BACK_BIT;
|
||||
case FaceSide::Front: return VK_CULL_MODE_FRONT_BIT;
|
||||
case FaceSide::FrontAndBack: return VK_CULL_MODE_FRONT_AND_BACK;
|
||||
case FaceCulling::None: return VK_CULL_MODE_NONE;
|
||||
case FaceCulling::Back: return VK_CULL_MODE_BACK_BIT;
|
||||
case FaceCulling::Front: return VK_CULL_MODE_FRONT_BIT;
|
||||
case FaceCulling::FrontAndBack: return VK_CULL_MODE_FRONT_AND_BACK;
|
||||
}
|
||||
|
||||
NazaraError("Unhandled FaceSide 0x" + NumberToString(UnderlyingCast(faceSide), 16));
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ SOFTWARE.
|
|||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
constexpr unsigned int AssimpFlags = aiProcess_CalcTangentSpace | aiProcess_FixInfacingNormals | aiProcess_FlipWindingOrder
|
||||
constexpr unsigned int AssimpFlags = aiProcess_CalcTangentSpace | aiProcess_FixInfacingNormals
|
||||
| aiProcess_FlipUVs | aiProcess_GenSmoothNormals | aiProcess_GenUVCoords
|
||||
| aiProcess_JoinIdenticalVertices | aiProcess_RemoveComponent | aiProcess_SortByPType
|
||||
| aiProcess_TransformUVCoords | aiProcess_Triangulate;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
|
||||
#include <Nazara/Graphics/FrameGraph.hpp>
|
||||
#include <Nazara/Graphics/FramePipeline.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
||||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Renderer/RenderFrame.hpp>
|
||||
|
|
@ -16,15 +15,16 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
DepthPipelinePass::DepthPipelinePass(FramePipeline& owner, ElementRendererRegistry& elementRegistry, AbstractViewer* viewer) :
|
||||
DepthPipelinePass::DepthPipelinePass(FramePipeline& owner, ElementRendererRegistry& elementRegistry, AbstractViewer* viewer, std::size_t passIndex, std::string passName) :
|
||||
m_passIndex(passIndex),
|
||||
m_lastVisibilityHash(0),
|
||||
m_passName(std::move(passName)),
|
||||
m_viewer(viewer),
|
||||
m_elementRegistry(elementRegistry),
|
||||
m_pipeline(owner),
|
||||
m_rebuildCommandBuffer(false),
|
||||
m_rebuildElements(false)
|
||||
{
|
||||
m_depthPassIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex("DepthPass");
|
||||
}
|
||||
|
||||
void DepthPipelinePass::Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, std::size_t visibilityHash)
|
||||
|
|
@ -42,7 +42,7 @@ namespace Nz
|
|||
renderableData.worldInstance
|
||||
};
|
||||
|
||||
renderableData.instancedRenderable->BuildElement(m_elementRegistry, elementData, m_depthPassIndex, m_renderElements);
|
||||
renderableData.instancedRenderable->BuildElement(m_elementRegistry, elementData, m_passIndex, m_renderElements);
|
||||
}
|
||||
|
||||
m_renderQueueRegistry.Clear();
|
||||
|
|
@ -105,7 +105,7 @@ namespace Nz
|
|||
|
||||
void DepthPipelinePass::RegisterMaterialInstance(const MaterialInstance& materialInstance)
|
||||
{
|
||||
if (!materialInstance.HasPass(m_depthPassIndex))
|
||||
if (!materialInstance.HasPass(m_passIndex))
|
||||
return;
|
||||
|
||||
auto it = m_materialInstances.find(&materialInstance);
|
||||
|
|
@ -114,7 +114,7 @@ namespace Nz
|
|||
auto& matPassEntry = m_materialInstances[&materialInstance];
|
||||
matPassEntry.onMaterialInstancePipelineInvalidated.Connect(materialInstance.OnMaterialInstancePipelineInvalidated, [=](const MaterialInstance*, std::size_t passIndex)
|
||||
{
|
||||
if (passIndex != m_depthPassIndex)
|
||||
if (passIndex != m_passIndex)
|
||||
return;
|
||||
|
||||
m_rebuildElements = true;
|
||||
|
|
@ -131,7 +131,7 @@ namespace Nz
|
|||
|
||||
FramePass& DepthPipelinePass::RegisterToFrameGraph(FrameGraph& frameGraph, std::size_t depthBufferIndex)
|
||||
{
|
||||
FramePass& depthPrepass = frameGraph.AddPass("Depth pre-pass");
|
||||
FramePass& depthPrepass = frameGraph.AddPass(m_passName);
|
||||
depthPrepass.SetDepthStencilOutput(depthBufferIndex);
|
||||
depthPrepass.SetDepthStencilClear(1.f, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -177,11 +177,13 @@ namespace Nz
|
|||
|
||||
std::size_t ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder)
|
||||
{
|
||||
std::size_t depthPassIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex("DepthPass");
|
||||
|
||||
std::size_t viewerIndex;
|
||||
auto& viewerData = *m_viewerPool.Allocate(viewerIndex);
|
||||
viewerData.renderOrder = renderOrder;
|
||||
viewerData.debugDrawPass = std::make_unique<DebugDrawPipelinePass>(*this, viewerInstance);
|
||||
viewerData.depthPrepass = std::make_unique<DepthPipelinePass>(*this, m_elementRegistry, viewerInstance);
|
||||
viewerData.depthPrepass = std::make_unique<DepthPipelinePass>(*this, m_elementRegistry, viewerInstance, depthPassIndex, "Depth pre-pass");
|
||||
viewerData.forwardPass = std::make_unique<ForwardPipelinePass>(*this, m_elementRegistry, viewerInstance);
|
||||
viewerData.viewer = viewerInstance;
|
||||
viewerData.onTransferRequired.Connect(viewerInstance->GetViewerInstance().OnTransferRequired, [this](TransferInterface* transferInterface)
|
||||
|
|
@ -211,6 +213,20 @@ namespace Nz
|
|||
return worldInstanceIndex;
|
||||
}
|
||||
|
||||
const Light* ForwardFramePipeline::RetrieveLight(std::size_t lightIndex) const
|
||||
{
|
||||
return m_lightPool.RetrieveFromIndex(lightIndex)->light.get();
|
||||
}
|
||||
|
||||
const Texture* ForwardFramePipeline::RetrieveLightShadowmap(std::size_t lightIndex) const
|
||||
{
|
||||
if (!m_shadowCastingLights.UnboundedTest(lightIndex))
|
||||
return nullptr;
|
||||
|
||||
std::size_t shadowmapIndex = m_lightPool.RetrieveFromIndex(lightIndex)->shadowMapAttachmentIndex;
|
||||
return m_bakedFrameGraph.GetAttachmentTexture(shadowmapIndex).get();
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::Render(RenderFrame& renderFrame)
|
||||
{
|
||||
m_currentRenderFrame = &renderFrame;
|
||||
|
|
@ -355,13 +371,17 @@ namespace Nz
|
|||
|
||||
m_visibleLights.clear();
|
||||
for (const LightData& lightData : m_lightPool)
|
||||
for (auto it = m_lightPool.begin(); it != m_lightPool.end(); ++it)
|
||||
{
|
||||
const LightData& lightData = *it;
|
||||
std::size_t lightIndex = it.GetIndex();
|
||||
|
||||
const BoundingVolumef& boundingVolume = lightData.light->GetBoundingVolume();
|
||||
|
||||
// TODO: Use more precise tests for point lights (frustum/sphere is cheap)
|
||||
if (renderMask & lightData.renderMask && frustum.Contains(boundingVolume))
|
||||
{
|
||||
m_visibleLights.push_back(lightData.light.get());
|
||||
m_visibleLights.push_back(lightIndex);
|
||||
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(lightData.light.get()));
|
||||
}
|
||||
}
|
||||
|
|
@ -575,7 +595,7 @@ namespace Nz
|
|||
m_transferSet.insert(transferInterface);
|
||||
});
|
||||
|
||||
lightData->camera->UpdateFOV(spotLight.GetOuterAngle());
|
||||
lightData->camera->UpdateFOV(spotLight.GetOuterAngle() * 2.f);
|
||||
lightData->camera->UpdateZFar(spotLight.GetRadius());
|
||||
lightData->camera->UpdateViewport(Recti(0, 0, SafeCast<int>(shadowMapSize), SafeCast<int>(shadowMapSize)));
|
||||
|
||||
|
|
@ -584,13 +604,15 @@ namespace Nz
|
|||
|
||||
if (!lightData->pass)
|
||||
{
|
||||
lightData->pass = std::make_unique<DepthPipelinePass>(*this, m_elementRegistry, lightData->camera.get());
|
||||
std::size_t shadowPassIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex("ShadowPass");
|
||||
|
||||
lightData->pass = std::make_unique<DepthPipelinePass>(*this, m_elementRegistry, lightData->camera.get(), shadowPassIndex, "Spot shadowmap");
|
||||
for (RenderableData& renderable : m_renderablePool)
|
||||
{
|
||||
std::size_t matCount = renderable.renderable->GetMaterialCount();
|
||||
for (std::size_t i = 0; i < matCount; ++i)
|
||||
for (std::size_t j = 0; j < matCount; ++j)
|
||||
{
|
||||
if (MaterialInstance* mat = renderable.renderable->GetMaterial(i).get())
|
||||
if (MaterialInstance* mat = renderable.renderable->GetMaterial(j).get())
|
||||
lightData->pass->RegisterMaterialInstance(*mat);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace Nz
|
|||
m_lightUboPool = std::make_shared<LightUboPool>();
|
||||
}
|
||||
|
||||
void ForwardPipelinePass::Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, const std::vector<const Light*>& visibleLights, std::size_t visibilityHash)
|
||||
void ForwardPipelinePass::Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, const std::vector<std::size_t>& visibleLights, std::size_t visibilityHash)
|
||||
{
|
||||
if (m_lastVisibilityHash != visibilityHash || m_rebuildElements) //< FIXME
|
||||
{
|
||||
|
|
@ -65,17 +65,22 @@ namespace Nz
|
|||
|
||||
// Select lights
|
||||
m_renderableLights.clear();
|
||||
for (const Light* light : visibleLights)
|
||||
for (std::size_t lightIndex : visibleLights)
|
||||
{
|
||||
const Light* light = m_pipeline.RetrieveLight(lightIndex);
|
||||
|
||||
const BoundingVolumef& boundingVolume = light->GetBoundingVolume();
|
||||
if (boundingVolume.Intersect(renderableBoundingVolume.aabb))
|
||||
m_renderableLights.push_back(light);
|
||||
{
|
||||
float contributionScore = light->ComputeContributionScore(renderableBoundingVolume);
|
||||
m_renderableLights.push_back({ light, lightIndex, contributionScore });
|
||||
}
|
||||
}
|
||||
|
||||
// Sort lights
|
||||
std::sort(m_renderableLights.begin(), m_renderableLights.end(), [&](const Light* lhs, const Light* rhs)
|
||||
std::sort(m_renderableLights.begin(), m_renderableLights.end(), [&](const RenderableLight& lhs, const RenderableLight& rhs)
|
||||
{
|
||||
return lhs->ComputeContributionScore(renderableBoundingVolume) < rhs->ComputeContributionScore(renderableBoundingVolume);
|
||||
return lhs.contributionScore < rhs.contributionScore;
|
||||
});
|
||||
|
||||
std::size_t lightCount = std::min(m_renderableLights.size(), MaxLightCountPerDraw);
|
||||
|
|
@ -83,7 +88,7 @@ namespace Nz
|
|||
LightKey lightKey;
|
||||
lightKey.fill(nullptr);
|
||||
for (std::size_t i = 0; i < lightCount; ++i)
|
||||
lightKey[i] = m_renderableLights[i];
|
||||
lightKey[i] = m_renderableLights[i].light;
|
||||
|
||||
RenderBufferView lightUboView;
|
||||
|
||||
|
|
@ -130,7 +135,7 @@ namespace Nz
|
|||
UInt8* lightPtr = static_cast<UInt8*>(lightDataPtr) + lightOffsets.lightsOffset;
|
||||
for (std::size_t i = 0; i < lightCount; ++i)
|
||||
{
|
||||
m_renderableLights[i]->FillLightData(lightPtr);
|
||||
m_renderableLights[i].light->FillLightData(lightPtr);
|
||||
lightPtr += lightOffsets.lightSize;
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +160,15 @@ namespace Nz
|
|||
for (std::size_t i = previousCount; i < m_renderElements.size(); ++i)
|
||||
{
|
||||
const RenderElement* element = m_renderElements[i].GetElement();
|
||||
m_lightPerRenderElement.emplace(element, lightUboView);
|
||||
|
||||
LightPerElementData perElementData;
|
||||
perElementData.lightCount = lightCount;
|
||||
perElementData.lightUniformBuffer = lightUboView;
|
||||
|
||||
for (std::size_t i = 0; i < lightCount; ++i)
|
||||
perElementData.shadowMaps[i] = m_pipeline.RetrieveLightShadowmap(m_renderableLights[i].lightIndex);
|
||||
|
||||
m_lightPerRenderElement.emplace(element, perElementData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,8 +235,25 @@ namespace Nz
|
|||
auto it = lightPerRenderElement.find(elements[i]);
|
||||
assert(it != lightPerRenderElement.end());
|
||||
|
||||
const LightPerElementData& lightData = it->second;
|
||||
|
||||
auto& renderStates = m_renderStates.emplace_back();
|
||||
renderStates.lightData = it->second;
|
||||
renderStates.lightData = lightData.lightUniformBuffer;
|
||||
|
||||
for (std::size_t i = 0; i < lightData.lightCount; ++i)
|
||||
{
|
||||
const Texture* texture = lightData.shadowMaps[i];
|
||||
if (!texture)
|
||||
continue;
|
||||
|
||||
if (texture->GetType() == ImageType::E2D)
|
||||
renderStates.shadowMaps2D[i] = texture;
|
||||
else
|
||||
{
|
||||
assert(texture->GetType() == ImageType::Cubemap);
|
||||
renderStates.shadowMapsCube[i] = texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elementRenderer.Prepare(viewerInstance, *m_elementRendererData[elementType], renderFrame, elementCount, elements, m_renderStates.data());
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ namespace Nz
|
|||
{
|
||||
if (auto it = m_pending.attachmentToTextures.find(depthStencilOutput); it == m_pending.attachmentToTextures.end())
|
||||
{
|
||||
// Special case where multiples attachements point simultaneously to the same texture
|
||||
// Special case where multiples attachments point simultaneously to the same texture
|
||||
m_pending.attachmentToTextures.emplace(depthStencilOutput, textureId);
|
||||
|
||||
auto inputIt = m_pending.attachmentLastUse.find(depthStencilInput);
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ namespace Nz
|
|||
RenderPipelineLayoutInfo layoutInfo;
|
||||
layoutInfo.bindings.assign({
|
||||
{
|
||||
0, 0,
|
||||
1, 0, 0,
|
||||
ShaderBindingType::Texture,
|
||||
nzsl::ShaderStageType::Fragment
|
||||
}
|
||||
|
|
@ -230,7 +230,10 @@ namespace Nz
|
|||
MaterialPass depthPass = forwardPass;
|
||||
depthPass.options[CRC32("DepthPass")] = true;
|
||||
settings.AddPass(depthPassIndex, depthPass);
|
||||
settings.AddPass(shadowPassIndex, depthPass);
|
||||
|
||||
MaterialPass shadowPass = depthPass;
|
||||
shadowPass.states.faceCulling = FaceCulling::Front;
|
||||
settings.AddPass(shadowPassIndex, shadowPass);
|
||||
|
||||
m_defaultMaterials.basicMaterial = std::make_shared<Material>(std::move(settings), "BasicMaterial");
|
||||
}
|
||||
|
|
@ -249,7 +252,10 @@ namespace Nz
|
|||
MaterialPass depthPass = forwardPass;
|
||||
depthPass.options[CRC32("DepthPass")] = true;
|
||||
settings.AddPass(depthPassIndex, depthPass);
|
||||
settings.AddPass(shadowPassIndex, depthPass);
|
||||
|
||||
MaterialPass shadowPass = depthPass;
|
||||
shadowPass.states.faceCulling = FaceCulling::Front;
|
||||
settings.AddPass(shadowPassIndex, shadowPass);
|
||||
|
||||
m_defaultMaterials.pbrMaterial = std::make_shared<Material>(std::move(settings), "PhysicallyBasedMaterial");
|
||||
}
|
||||
|
|
@ -268,7 +274,13 @@ namespace Nz
|
|||
MaterialPass depthPass = forwardPass;
|
||||
depthPass.options[CRC32("DepthPass")] = true;
|
||||
settings.AddPass(depthPassIndex, depthPass);
|
||||
settings.AddPass(shadowPassIndex, depthPass);
|
||||
|
||||
MaterialPass shadowPass = depthPass;
|
||||
shadowPass.states.faceCulling = FaceCulling::Front;
|
||||
shadowPass.states.depthBias = true;
|
||||
shadowPass.states.depthBiasConstantFactor = 0.005f;
|
||||
shadowPass.states.depthBiasSlopeFactor = 0.05f;
|
||||
settings.AddPass(shadowPassIndex, shadowPass);
|
||||
|
||||
m_defaultMaterials.phongMaterial = std::make_shared<Material>(std::move(settings), "PhongMaterial");
|
||||
}
|
||||
|
|
@ -301,6 +313,38 @@ namespace Nz
|
|||
|
||||
void Graphics::BuildDefaultTextures()
|
||||
{
|
||||
// Depth textures (white but with a depth format)
|
||||
{
|
||||
PixelFormat depthFormat = PixelFormat::Undefined;
|
||||
for (PixelFormat depthStencilCandidate : { PixelFormat::Depth16, PixelFormat::Depth24, PixelFormat::Depth32F })
|
||||
{
|
||||
if (m_renderDevice->IsTextureFormatSupported(depthStencilCandidate, TextureUsage::ShaderSampling))
|
||||
{
|
||||
depthFormat = depthStencilCandidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (depthFormat == PixelFormat::Undefined)
|
||||
throw std::runtime_error("couldn't find a sampling-compatible depth pixel format");
|
||||
|
||||
TextureInfo texInfo;
|
||||
texInfo.width = texInfo.height = texInfo.depth = texInfo.mipmapLevel = 1;
|
||||
texInfo.pixelFormat = depthFormat;
|
||||
|
||||
std::array<UInt8, 6> whitePixels = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
for (std::size_t i = 0; i < ImageTypeCount; ++i)
|
||||
{
|
||||
texInfo.type = static_cast<ImageType>(i);
|
||||
if (texInfo.type == ImageType::E3D)
|
||||
continue;
|
||||
|
||||
m_defaultTextures.depthTextures[i] = m_renderDevice->InstantiateTexture(texInfo);
|
||||
m_defaultTextures.depthTextures[i]->Update(whitePixels.data());
|
||||
}
|
||||
}
|
||||
|
||||
// White texture 2D
|
||||
{
|
||||
TextureInfo texInfo;
|
||||
|
|
|
|||
|
|
@ -94,6 +94,12 @@ namespace Nz
|
|||
if (auto it = block->uniformBlocks.find("ViewerData"); it != block->uniformBlocks.end())
|
||||
m_engineShaderBindings[UnderlyingCast(EngineShaderBinding::ViewerDataUbo)] = it->second.bindingIndex;
|
||||
|
||||
if (auto it = block->samplers.find("ShadowMaps2D"); it != block->samplers.end())
|
||||
m_engineShaderBindings[UnderlyingCast(EngineShaderBinding::Shadowmap2D)] = it->second.bindingIndex;
|
||||
|
||||
if (auto it = block->samplers.find("ShadowMapsCube"); it != block->samplers.end())
|
||||
m_engineShaderBindings[UnderlyingCast(EngineShaderBinding::ShadowmapCube)] = it->second.bindingIndex;
|
||||
|
||||
if (auto it = block->uniformBlocks.find("SkeletalData"); it != block->uniformBlocks.end())
|
||||
m_engineShaderBindings[UnderlyingCast(EngineShaderBinding::SkeletalDataUbo)] = it->second.bindingIndex;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ namespace Nz
|
|||
lightData.lightMemberOffsets.parameter2 = lightStruct.AddField(nzsl::StructFieldType::Float4);
|
||||
lightData.lightMemberOffsets.parameter3 = lightStruct.AddField(nzsl::StructFieldType::Float4);
|
||||
lightData.lightMemberOffsets.shadowMappingFlag = lightStruct.AddField(nzsl::StructFieldType::Bool1);
|
||||
lightData.lightMemberOffsets.viewProjMatrix = lightStruct.AddMatrix(nzsl::StructFieldType::Float1, 4, 4, true);
|
||||
|
||||
lightData.lightSize = lightStruct.GetAlignedSize();
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ struct VertOut
|
|||
}
|
||||
|
||||
const vertPos = array[vec2[f32]](
|
||||
vec2[f32](-1.0, 1.0),
|
||||
vec2[f32](-1.0, -3.0),
|
||||
vec2[f32](-1.0, 1.0),
|
||||
vec2[f32]( 3.0, 1.0)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ struct Light
|
|||
parameter1: vec4[f32],
|
||||
parameter2: vec4[f32],
|
||||
parameter3: vec4[f32],
|
||||
hasShadowMapping: u32
|
||||
hasShadowMapping: u32,
|
||||
viewProjMatrix: mat4[f32]
|
||||
}
|
||||
|
||||
[export]
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ const HasTangent = (VertexTangentLoc >= 0);
|
|||
const HasUV = (VertexUvLoc >= 0);
|
||||
const HasNormalMapping = HasNormalTexture && HasNormal && HasTangent && !DepthPass;
|
||||
const HasSkinning = (VertexJointIndicesLoc >= 0 && VertexJointWeightsLoc >= 0);
|
||||
const HasLighting = HasNormal && !DepthPass;
|
||||
|
||||
[layout(std140)]
|
||||
struct MaterialSettings
|
||||
|
|
@ -96,8 +97,8 @@ external
|
|||
[tag("ViewerData")] viewerData: uniform[ViewerData],
|
||||
[tag("SkeletalData")] skeletalData: uniform[SkeletalData],
|
||||
[tag("LightData")] lightData: uniform[LightData],
|
||||
[tag("ShadowMaps2D")] shadowMaps2D: array[sampler2D[f32], MaxLightCount],
|
||||
[tag("ShadowMapsCube")] shadowMapsCube: array[samplerCube[f32], MaxLightCount]
|
||||
[tag("ShadowMaps2D")] shadowMaps2D: array[depth_sampler2D[f32], MaxLightCount],
|
||||
[tag("ShadowMapsCube")] shadowMapsCube: array[depth_sampler_cube[f32], MaxLightCount]
|
||||
}
|
||||
|
||||
struct VertToFrag
|
||||
|
|
@ -107,6 +108,7 @@ struct VertToFrag
|
|||
[location(2), cond(HasColor)] color: vec4[f32],
|
||||
[location(3), cond(HasNormal)] normal: vec3[f32],
|
||||
[location(4), cond(HasNormalMapping)] tangent: vec3[f32],
|
||||
[location(5), cond(HasLighting)] lightProjPos: array[vec4[f32], MaxLightCount],
|
||||
[builtin(position)] position: vec4[f32],
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +141,7 @@ fn main(input: VertToFrag) -> FragOut
|
|||
discard;
|
||||
}
|
||||
|
||||
const if (HasNormal && !DepthPass)
|
||||
const if (HasLighting)
|
||||
{
|
||||
let lightAmbient = vec3[f32](0.0, 0.0, 0.0);
|
||||
let lightDiffuse = vec3[f32](0.0, 0.0, 0.0);
|
||||
|
|
@ -225,17 +227,41 @@ fn main(input: VertToFrag) -> FragOut
|
|||
let attenuationFactor = max(1.0 - dist * lightInvRadius, 0.0);
|
||||
attenuationFactor *= max((curAngle - lightOuterAngle) / innerMinusOuterAngle, 0.0);
|
||||
|
||||
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor.rgb;
|
||||
|
||||
let lambert = max(dot(normal, -lightToPosNorm), 0.0);
|
||||
|
||||
lightDiffuse += attenuationFactor * lambert * light.color.rgb * lightDiffuseFactor;
|
||||
|
||||
let reflection = reflect(lightToPosNorm, normal);
|
||||
let specFactor = max(dot(reflection, eyeVec), 0.0);
|
||||
specFactor = pow(specFactor, settings.Shininess);
|
||||
|
||||
lightSpecular += attenuationFactor * specFactor * light.color.rgb;
|
||||
let shadowFactor = 0.0;
|
||||
if (true) //< TODO: HasShadowMapping
|
||||
{
|
||||
let shadowTexSize = 1.0 / 512.0; //< FIXME
|
||||
|
||||
let offsetArray = array[vec2[f32], 9](
|
||||
vec2[f32](-1.0, -1.0),
|
||||
vec2[f32](-1.0, 0.0),
|
||||
vec2[f32](-1.0, 1.0),
|
||||
vec2[f32](0.0, -1.0),
|
||||
vec2[f32](0.0, 0.0),
|
||||
vec2[f32](0.0, 1.0),
|
||||
vec2[f32](1.0, -1.0),
|
||||
vec2[f32](1.0, 0.0),
|
||||
vec2[f32](1.0, 1.0)
|
||||
);
|
||||
|
||||
for offset in offsetArray
|
||||
{
|
||||
let shadowCoords = input.lightProjPos[i].xyz / input.lightProjPos[i].w;
|
||||
shadowCoords.xy += offset * shadowTexSize;
|
||||
shadowFactor += shadowMaps2D[i].SampleDepthComp(shadowCoords.xy, shadowCoords.z).r;
|
||||
}
|
||||
shadowFactor /= 9.0;
|
||||
}
|
||||
|
||||
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor.rgb;
|
||||
lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * lightDiffuseFactor;
|
||||
lightSpecular += shadowFactor * attenuationFactor * specFactor * light.color.rgb;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,5 +408,11 @@ fn main(input: VertIn) -> VertToFrag
|
|||
const if (HasNormalMapping)
|
||||
output.tangent = rotationMatrix * input.tangent;
|
||||
|
||||
const if (HasLighting)
|
||||
{
|
||||
for i in u32(0) -> lightData.lightCount
|
||||
output.lightProjPos[i] = lightData.lights[i].viewProjMatrix * worldPosition;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,16 +73,14 @@ namespace Nz
|
|||
else
|
||||
throw std::runtime_error("unexpected type " + ToString(varType));
|
||||
|
||||
for (UInt32 i = 0; i < arraySize; ++i)
|
||||
{
|
||||
// TODO: Get more precise shader stage type
|
||||
m_pipelineLayoutInfo.bindings.push_back({
|
||||
bindingSet, // setIndex
|
||||
bindingIndex + i, // bindingIndex
|
||||
bindingType, // type
|
||||
nzsl::ShaderStageType_All // shaderStageFlags
|
||||
});
|
||||
}
|
||||
// TODO: Get more precise shader stage type
|
||||
m_pipelineLayoutInfo.bindings.push_back({
|
||||
arraySize, // arraySize
|
||||
bindingIndex, // bindingIndex
|
||||
bindingSet, // setIndex
|
||||
bindingType, // type
|
||||
nzsl::ShaderStageType_All // shaderStageFlags
|
||||
});
|
||||
|
||||
if (!externalVar.tag.empty() && externalBlock)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ namespace Nz
|
|||
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter2) = Vector4f(m_direction.x, m_direction.y, m_direction.z, 0.f);
|
||||
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter3) = Vector4f(m_innerAngleCos, m_outerAngleCos, 0.f, 0.f);
|
||||
AccessByOffset<UInt8&>(data, lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;
|
||||
AccessByOffset<Matrix4f&>(data, lightOffset.lightMemberOffsets.viewProjMatrix) = m_viewProjMatrix;
|
||||
}
|
||||
|
||||
void SpotLight::UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& /*scale*/)
|
||||
|
|
|
|||
|
|
@ -54,9 +54,16 @@ namespace Nz
|
|||
currentShaderBinding = nullptr;
|
||||
};
|
||||
|
||||
const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
|
||||
const auto& depthTexture2D = Graphics::Instance()->GetDefaultTextures().depthTextures[UnderlyingCast(ImageType::E2D)];
|
||||
const auto& depthTextureCube = Graphics::Instance()->GetDefaultTextures().depthTextures[UnderlyingCast(ImageType::Cubemap)];
|
||||
const auto& whiteTexture2D = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
|
||||
const auto& whiteTextureCube = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::Cubemap)];
|
||||
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
|
||||
|
||||
TextureSamplerInfo samplerInfo;
|
||||
samplerInfo.depthCompare = true;
|
||||
const auto& shadowSampler = graphics->GetSamplerCache().Get(samplerInfo);
|
||||
|
||||
std::size_t oldDrawCallCount = data.drawCalls.size();
|
||||
|
||||
for (std::size_t i = 0; i < elementCount; ++i)
|
||||
|
|
@ -122,6 +129,8 @@ namespace Nz
|
|||
assert(currentMaterialInstance);
|
||||
|
||||
m_bindingCache.clear();
|
||||
m_textureBindingCache.clear();
|
||||
m_textureBindingCache.reserve(renderState.shadowMaps2D.size() + renderState.shadowMapsCube.size());
|
||||
currentMaterialInstance->FillShaderBinding(m_bindingCache);
|
||||
|
||||
const Material& material = *currentMaterialInstance->GetParentMaterial();
|
||||
|
|
@ -150,6 +159,50 @@ namespace Nz
|
|||
};
|
||||
}
|
||||
|
||||
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::Shadowmap2D); bindingIndex != Material::InvalidBindingIndex)
|
||||
{
|
||||
std::size_t textureBindingBaseIndex = m_textureBindingCache.size();
|
||||
|
||||
for (std::size_t j = 0; j < renderState.shadowMaps2D.size(); ++j)
|
||||
{
|
||||
const Texture* texture = renderState.shadowMaps2D[j];
|
||||
if (!texture)
|
||||
texture = depthTexture2D.get();
|
||||
|
||||
auto& textureEntry = m_textureBindingCache.emplace_back();
|
||||
textureEntry.texture = texture;
|
||||
textureEntry.sampler = shadowSampler.get();
|
||||
}
|
||||
|
||||
auto& bindingEntry = m_bindingCache.emplace_back();
|
||||
bindingEntry.bindingIndex = bindingIndex;
|
||||
bindingEntry.content = ShaderBinding::TextureBindings {
|
||||
SafeCast<UInt32>(renderState.shadowMaps2D.size()), &m_textureBindingCache[textureBindingBaseIndex]
|
||||
};
|
||||
}
|
||||
|
||||
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::ShadowmapCube); bindingIndex != Material::InvalidBindingIndex)
|
||||
{
|
||||
std::size_t textureBindingBaseIndex = m_textureBindingCache.size();
|
||||
|
||||
for (std::size_t j = 0; j < renderState.shadowMapsCube.size(); ++j)
|
||||
{
|
||||
const Texture* texture = renderState.shadowMapsCube[j];
|
||||
if (!texture)
|
||||
texture = depthTextureCube.get();
|
||||
|
||||
auto& textureEntry = m_textureBindingCache.emplace_back();
|
||||
textureEntry.texture = texture;
|
||||
textureEntry.sampler = shadowSampler.get();
|
||||
}
|
||||
|
||||
auto& bindingEntry = m_bindingCache.emplace_back();
|
||||
bindingEntry.bindingIndex = bindingIndex;
|
||||
bindingEntry.content = ShaderBinding::TextureBindings {
|
||||
SafeCast<UInt32>(renderState.shadowMaps2D.size()), &m_textureBindingCache[textureBindingBaseIndex]
|
||||
};
|
||||
}
|
||||
|
||||
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::SkeletalDataUbo); bindingIndex != Material::InvalidBindingIndex && currentSkeletonInstance)
|
||||
{
|
||||
const auto& skeletalBuffer = currentSkeletonInstance->GetSkeletalBuffer();
|
||||
|
|
@ -179,7 +232,7 @@ namespace Nz
|
|||
auto& bindingEntry = m_bindingCache.emplace_back();
|
||||
bindingEntry.bindingIndex = bindingIndex;
|
||||
bindingEntry.content = ShaderBinding::TextureBinding{
|
||||
whiteTexture.get(), defaultSampler.get()
|
||||
whiteTexture2D.get(), defaultSampler.get()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,14 @@ namespace Nz
|
|||
unsigned int bindingIndex = 0;
|
||||
for (const auto& binding : m_layoutInfo.bindings)
|
||||
{
|
||||
UInt64 bindingKey = UInt64(binding.setIndex) << 32 | UInt64(binding.bindingIndex);
|
||||
for (UInt32 i = 0; i < binding.arraySize; ++i)
|
||||
{
|
||||
UInt64 bindingKey = UInt64(binding.setIndex) << 32 | UInt64(binding.bindingIndex + i);
|
||||
|
||||
m_bindingMapping[bindingKey] = bindingIndex++;
|
||||
m_maxDescriptorCount = std::max<std::size_t>(m_maxDescriptorCount, binding.bindingIndex + 1);
|
||||
m_bindingMapping[bindingKey] = bindingIndex++;
|
||||
}
|
||||
|
||||
m_maxDescriptorCount = std::max<std::size_t>(m_maxDescriptorCount, binding.bindingIndex + binding.arraySize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,18 @@ namespace Nz
|
|||
{
|
||||
using DescriptorType = std::decay_t<decltype(descriptor)>;
|
||||
|
||||
auto bindingIt = std::find_if(layoutInfo.bindings.begin(), layoutInfo.bindings.end(), [&](const auto& binding) { return binding.setIndex == setIndex && binding.bindingIndex == bindingIndex; });
|
||||
auto bindingIt = std::find_if(layoutInfo.bindings.begin(), layoutInfo.bindings.end(), [&](const auto& binding)
|
||||
{
|
||||
if (binding.setIndex != setIndex)
|
||||
return false;
|
||||
|
||||
assert(binding.arraySize > 0);
|
||||
if (bindingIndex < binding.bindingIndex || bindingIndex >= binding.bindingIndex + binding.arraySize)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (bindingIt == layoutInfo.bindings.end())
|
||||
throw std::runtime_error("invalid binding index");
|
||||
|
||||
|
|
@ -88,26 +99,11 @@ namespace Nz
|
|||
storageDescriptor.buffer = 0;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, TextureBinding>)
|
||||
HandleTextureBinding(binding.bindingIndex, arg);
|
||||
else if constexpr (std::is_same_v<T, TextureBindings>)
|
||||
{
|
||||
auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, binding.bindingIndex);
|
||||
|
||||
if (const OpenGLTexture* glTexture = static_cast<const OpenGLTexture*>(arg.texture))
|
||||
{
|
||||
textureDescriptor.texture = glTexture->GetTexture().GetObjectId();
|
||||
|
||||
if (const OpenGLTextureSampler* glSampler = static_cast<const OpenGLTextureSampler*>(arg.sampler))
|
||||
textureDescriptor.sampler = glSampler->GetSampler(glTexture->GetLevelCount() > 1).GetObjectId();
|
||||
else
|
||||
textureDescriptor.sampler = 0;
|
||||
|
||||
textureDescriptor.textureTarget = OpenGLTexture::ToTextureTarget(glTexture->GetType());
|
||||
}
|
||||
else
|
||||
{
|
||||
textureDescriptor.sampler = 0;
|
||||
textureDescriptor.texture = 0;
|
||||
textureDescriptor.textureTarget = GL::TextureTarget::Target2D;
|
||||
}
|
||||
for (UInt32 i = 0; i < arg.arraySize; ++i)
|
||||
HandleTextureBinding(binding.bindingIndex + i, arg.textureBindings[i]);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, UniformBufferBinding>)
|
||||
{
|
||||
|
|
@ -137,6 +133,29 @@ namespace Nz
|
|||
// No OpenGL object to name
|
||||
}
|
||||
|
||||
void OpenGLShaderBinding::HandleTextureBinding(UInt32 bindingIndex, const TextureBinding& textureBinding)
|
||||
{
|
||||
auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, bindingIndex);
|
||||
|
||||
if (const OpenGLTexture* glTexture = static_cast<const OpenGLTexture*>(textureBinding.texture))
|
||||
{
|
||||
textureDescriptor.texture = glTexture->GetTexture().GetObjectId();
|
||||
|
||||
if (const OpenGLTextureSampler* glSampler = static_cast<const OpenGLTextureSampler*>(textureBinding.sampler))
|
||||
textureDescriptor.sampler = glSampler->GetSampler(glTexture->GetLevelCount() > 1).GetObjectId();
|
||||
else
|
||||
textureDescriptor.sampler = 0;
|
||||
|
||||
textureDescriptor.textureTarget = OpenGLTexture::ToTextureTarget(glTexture->GetType());
|
||||
}
|
||||
else
|
||||
{
|
||||
textureDescriptor.sampler = 0;
|
||||
textureDescriptor.texture = 0;
|
||||
textureDescriptor.textureTarget = GL::TextureTarget::Target2D;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLShaderBinding::Release()
|
||||
{
|
||||
m_owner.Release(*this);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,12 @@ namespace Nz
|
|||
|
||||
if (samplerInfo.anisotropyLevel > 1.f)
|
||||
sampler.SetParameterf(GL_TEXTURE_MAX_ANISOTROPY_EXT, samplerInfo.anisotropyLevel);
|
||||
|
||||
if (samplerInfo.depthCompare)
|
||||
{
|
||||
sampler.SetParameteri(GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||
sampler.SetParameteri(GL_TEXTURE_COMPARE_FUNC, ToOpenGL(samplerInfo.depthComparison));
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLTextureSampler::UpdateDebugName(std::string_view name)
|
||||
|
|
|
|||
|
|
@ -565,8 +565,13 @@ namespace Nz::GL
|
|||
glGetIntegerv(GL_VIEWPORT, res.data());
|
||||
m_state.viewport = { res[0], res[1], res[2], res[3] };
|
||||
|
||||
m_state.renderStates.depthCompare = RendererComparison::Less; //< OpenGL default depth mode is GL_LESS
|
||||
m_state.renderStates.frontFace = FrontFace::CounterClockwise; //< OpenGL default front face is GL_CCW
|
||||
// Set default OpenGL states
|
||||
m_state.renderStates.depthBuffer = false;
|
||||
m_state.renderStates.depthCompare = RendererComparison::Less;
|
||||
m_state.renderStates.faceCulling = FaceCulling::None;
|
||||
m_state.renderStates.frontFace = FrontFace::CounterClockwise;
|
||||
m_state.renderStates.scissorTest = false;
|
||||
m_state.renderStates.stencilTest = false;
|
||||
|
||||
EnableVerticalSync(false);
|
||||
|
||||
|
|
@ -671,6 +676,18 @@ namespace Nz::GL
|
|||
if (!SetCurrentContext(this))
|
||||
throw std::runtime_error("failed to activate context");
|
||||
|
||||
// Depth bias
|
||||
if (renderStates.depthBias)
|
||||
{
|
||||
if (!NumberEquals(m_state.renderStates.depthBiasConstantFactor, renderStates.depthBiasConstantFactor) ||
|
||||
!NumberEquals(m_state.renderStates.depthBiasSlopeFactor, renderStates.depthBiasSlopeFactor))
|
||||
{
|
||||
glPolygonOffset(renderStates.depthBiasConstantFactor, renderStates.depthBiasSlopeFactor);
|
||||
m_state.renderStates.depthBiasConstantFactor = renderStates.depthBiasConstantFactor;
|
||||
m_state.renderStates.depthBiasSlopeFactor = renderStates.depthBiasSlopeFactor;
|
||||
}
|
||||
}
|
||||
|
||||
// Depth compare and depth write
|
||||
if (renderStates.depthBuffer)
|
||||
{
|
||||
|
|
@ -687,14 +704,23 @@ namespace Nz::GL
|
|||
}
|
||||
}
|
||||
|
||||
// Face culling side
|
||||
if (renderStates.faceCulling)
|
||||
// Face culling
|
||||
if (m_state.renderStates.faceCulling != renderStates.faceCulling)
|
||||
{
|
||||
if (m_state.renderStates.cullingSide != renderStates.cullingSide)
|
||||
bool wasEnabled = (m_state.renderStates.faceCulling != FaceCulling::None);
|
||||
bool isEnabled = (renderStates.faceCulling != FaceCulling::None);
|
||||
|
||||
if (isEnabled)
|
||||
{
|
||||
glCullFace(ToOpenGL(renderStates.cullingSide));
|
||||
m_state.renderStates.cullingSide = renderStates.cullingSide;
|
||||
if (!wasEnabled)
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
glCullFace(ToOpenGL(renderStates.faceCulling));
|
||||
}
|
||||
else if (wasEnabled)
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
m_state.renderStates.faceCulling = renderStates.faceCulling;
|
||||
}
|
||||
|
||||
// Front face
|
||||
|
|
@ -811,6 +837,18 @@ namespace Nz::GL
|
|||
m_state.renderStates.colorWriteMask = renderStates.colorWriteMask;
|
||||
}
|
||||
|
||||
// Depth bias
|
||||
if (m_state.renderStates.depthBias != renderStates.depthBias)
|
||||
{
|
||||
// TODO: Handle line and points
|
||||
if (renderStates.depthBias)
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
else
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
m_state.renderStates.depthBias = renderStates.depthBias;
|
||||
}
|
||||
|
||||
// Depth buffer
|
||||
if (m_state.renderStates.depthBuffer != renderStates.depthBuffer)
|
||||
{
|
||||
|
|
@ -835,17 +873,6 @@ namespace Nz::GL
|
|||
m_state.renderStates.depthClamp = renderStates.depthClamp;
|
||||
}
|
||||
|
||||
// Face culling
|
||||
if (m_state.renderStates.faceCulling != renderStates.faceCulling)
|
||||
{
|
||||
if (renderStates.faceCulling)
|
||||
glEnable(GL_CULL_FACE);
|
||||
else
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
m_state.renderStates.faceCulling = renderStates.faceCulling;
|
||||
}
|
||||
|
||||
// Scissor test
|
||||
if (m_state.renderStates.scissorTest != renderStates.scissorTest)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ namespace Nz
|
|||
RenderPipelineLayoutInfo layoutInfo;
|
||||
layoutInfo.bindings.assign({
|
||||
{
|
||||
0, 0,
|
||||
1, 0, 0,
|
||||
ShaderBindingType::UniformBuffer,
|
||||
nzsl::ShaderStageType::Vertex
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,8 +133,8 @@ namespace Nz
|
|||
std::string appName = parameters.GetStringParameter("VkAppInfo_OverrideApplicationName").GetValueOr("Another application made with Nazara Engine");
|
||||
std::string engineName = parameters.GetStringParameter("VkAppInfo_OverrideEngineName").GetValueOr("Nazara Engine - Vulkan Renderer");
|
||||
|
||||
UInt32 appVersion = parameters.GetIntegerParameter("VkAppInfo_OverrideApplicationVersion").GetValueOr(VK_MAKE_API_VERSION(0, 1, 0, 0));
|
||||
UInt32 engineVersion = parameters.GetIntegerParameter("VkAppInfo_OverrideEngineVersion").GetValueOr(VK_MAKE_API_VERSION(0, 1, 0, 0));
|
||||
UInt32 appVersion = SafeCast<UInt32>(parameters.GetIntegerParameter("VkAppInfo_OverrideApplicationVersion").GetValueOr(VK_MAKE_API_VERSION(0, 1, 0, 0)));
|
||||
UInt32 engineVersion = SafeCast<UInt32>(parameters.GetIntegerParameter("VkAppInfo_OverrideEngineVersion").GetValueOr(VK_MAKE_API_VERSION(0, 1, 0, 0)));
|
||||
|
||||
if (auto result = parameters.GetIntegerParameter("VkAppInfo_OverrideAPIVersion"))
|
||||
targetApiVersion = SafeCast<UInt32>(result.GetValue());
|
||||
|
|
@ -160,7 +160,7 @@ namespace Nz
|
|||
targetApiVersion
|
||||
};
|
||||
|
||||
VkInstanceCreateFlags createFlags = parameters.GetIntegerParameter("VkInstanceInfo_OverrideCreateFlags").GetValueOr(0);
|
||||
VkInstanceCreateFlags createFlags = SafeCast<VkInstanceCreateFlags>(parameters.GetIntegerParameter("VkInstanceInfo_OverrideCreateFlags").GetValueOr(0));
|
||||
|
||||
std::vector<const char*> enabledLayers;
|
||||
|
||||
|
|
|
|||
|
|
@ -159,7 +159,10 @@ namespace Nz
|
|||
{
|
||||
VkPipelineRasterizationStateCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
createInfo.cullMode = (pipelineInfo.faceCulling) ? ToVulkan(pipelineInfo.cullingSide) : VK_CULL_MODE_NONE;
|
||||
createInfo.cullMode = ToVulkan(pipelineInfo.faceCulling);
|
||||
createInfo.depthBiasEnable = pipelineInfo.depthBias;
|
||||
createInfo.depthBiasConstantFactor = pipelineInfo.depthBiasConstantFactor;
|
||||
createInfo.depthBiasSlopeFactor = pipelineInfo.depthBiasSlopeFactor;
|
||||
createInfo.depthClampEnable = pipelineInfo.depthClamp;
|
||||
createInfo.frontFace = ToVulkan(pipelineInfo.frontFace);
|
||||
createInfo.lineWidth = pipelineInfo.lineWidth;
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ namespace Nz
|
|||
|
||||
VkDescriptorSetLayoutBinding& layoutBinding = descriptorSetLayoutInfo.bindings.emplace_back();
|
||||
layoutBinding.binding = bindingInfo.bindingIndex;
|
||||
layoutBinding.descriptorCount = 1U;
|
||||
layoutBinding.descriptorCount = bindingInfo.arraySize;
|
||||
layoutBinding.descriptorType = ToVulkan(bindingInfo.type);
|
||||
layoutBinding.pImmutableSamplers = nullptr;
|
||||
layoutBinding.stageFlags = ToVulkan(bindingInfo.shaderStageFlags);
|
||||
|
|
|
|||
|
|
@ -15,8 +15,34 @@ namespace Nz
|
|||
{
|
||||
void VulkanShaderBinding::Update(const Binding* bindings, std::size_t bindingCount)
|
||||
{
|
||||
StackVector<VkDescriptorBufferInfo> bufferBinding = NazaraStackVector(VkDescriptorBufferInfo, bindingCount);
|
||||
StackVector<VkDescriptorImageInfo> imageBinding = NazaraStackVector(VkDescriptorImageInfo, bindingCount);
|
||||
std::size_t bufferBindingCount = 0;
|
||||
std::size_t imageBindingCount = 0;
|
||||
for (std::size_t i = 0; i < bindingCount; ++i)
|
||||
{
|
||||
const Binding& binding = bindings[i];
|
||||
|
||||
std::visit([&](auto&& arg)
|
||||
{
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, StorageBufferBinding> || std::is_same_v<T, UniformBufferBinding>)
|
||||
bufferBindingCount++;
|
||||
else if constexpr (std::is_same_v<T, TextureBinding>)
|
||||
imageBindingCount++;
|
||||
else if constexpr (std::is_same_v<T, TextureBindings>)
|
||||
imageBindingCount += arg.arraySize;
|
||||
else
|
||||
static_assert(AlwaysFalse<T>(), "non-exhaustive visitor");
|
||||
|
||||
}, binding.content);
|
||||
}
|
||||
|
||||
NazaraAssert(bufferBindingCount < 128, "too many concurrent buffer update");
|
||||
NazaraAssert(imageBindingCount < 128, "too many concurrent image binding update");
|
||||
NazaraAssert(bindingCount < 128, "too many binding update");
|
||||
|
||||
StackVector<VkDescriptorBufferInfo> bufferBinding = NazaraStackVector(VkDescriptorBufferInfo, bufferBindingCount);
|
||||
StackVector<VkDescriptorImageInfo> imageBinding = NazaraStackVector(VkDescriptorImageInfo, imageBindingCount);
|
||||
StackVector<VkWriteDescriptorSet> writeOps = NazaraStackVector(VkWriteDescriptorSet, bindingCount);
|
||||
|
||||
for (std::size_t i = 0; i < bindingCount; ++i)
|
||||
|
|
@ -34,7 +60,7 @@ namespace Nz
|
|||
|
||||
if constexpr (std::is_same_v<T, StorageBufferBinding>)
|
||||
{
|
||||
VulkanBuffer* vkBuffer = static_cast<VulkanBuffer*>(arg.buffer);
|
||||
VulkanBuffer* vkBuffer = SafeCast<VulkanBuffer*>(arg.buffer);
|
||||
|
||||
VkDescriptorBufferInfo& bufferInfo = bufferBinding.emplace_back();
|
||||
bufferInfo.buffer = (vkBuffer) ? vkBuffer->GetBuffer() : VK_NULL_HANDLE;
|
||||
|
|
@ -47,8 +73,8 @@ namespace Nz
|
|||
}
|
||||
else if constexpr (std::is_same_v<T, TextureBinding>)
|
||||
{
|
||||
const VulkanTexture* vkTexture = static_cast<const VulkanTexture*>(arg.texture);
|
||||
const VulkanTextureSampler* vkSampler = static_cast<const VulkanTextureSampler*>(arg.sampler);
|
||||
const VulkanTexture* vkTexture = SafeCast<const VulkanTexture*>(arg.texture);
|
||||
const VulkanTextureSampler* vkSampler = SafeCast<const VulkanTextureSampler*>(arg.sampler);
|
||||
|
||||
VkDescriptorImageInfo& imageInfo = imageBinding.emplace_back();
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
|
@ -59,6 +85,23 @@ namespace Nz
|
|||
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
writeOp.pImageInfo = &imageInfo;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, TextureBindings>)
|
||||
{
|
||||
for (UInt32 i = 0; i < arg.arraySize; ++i)
|
||||
{
|
||||
const VulkanTexture* vkTexture = SafeCast<const VulkanTexture*>(arg.textureBindings[i].texture);
|
||||
const VulkanTextureSampler* vkSampler = SafeCast<const VulkanTextureSampler*>(arg.textureBindings[i].sampler);
|
||||
|
||||
VkDescriptorImageInfo& imageInfo = imageBinding.emplace_back();
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
imageInfo.imageView = (vkTexture) ? vkTexture->GetImageView() : VK_NULL_HANDLE;
|
||||
imageInfo.sampler = (vkSampler) ? vkSampler->GetSampler() : VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
writeOp.descriptorCount = arg.arraySize;
|
||||
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
writeOp.pImageInfo = &imageBinding[imageBinding.size() - arg.arraySize];
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, UniformBufferBinding>)
|
||||
{
|
||||
VulkanBuffer* vkBuffer = static_cast<VulkanBuffer*>(arg.buffer);
|
||||
|
|
|
|||
|
|
@ -293,15 +293,19 @@ namespace Nz
|
|||
if (!copyCommandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT))
|
||||
return false;
|
||||
|
||||
VkImageAspectFlagBits aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
if (PixelFormatInfo::GetContent(m_params.pixelFormat) == PixelFormatContent::Depth)
|
||||
aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
|
||||
VkImageSubresourceLayers subresourceLayers = { //< FIXME
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
aspect,
|
||||
level, //< mipLevel
|
||||
0, //< baseArrayLayer
|
||||
UInt32((m_params.type == ImageType::Cubemap) ? 6 : 1) //< layerCount
|
||||
};
|
||||
|
||||
VkImageSubresourceRange subresourceRange = { //< FIXME
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
aspect,
|
||||
0, //< baseMipLevel
|
||||
1, //< levelCount
|
||||
subresourceLayers.baseArrayLayer, //< baseArrayLayer
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ namespace Nz
|
|||
createInfo.addressModeW = ToVulkan(samplerInfo.wrapModeW);
|
||||
createInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||
createInfo.mipmapMode = ToVulkan(samplerInfo.mipmapMode);
|
||||
createInfo.compareEnable = samplerInfo.depthCompare;
|
||||
createInfo.compareOp = ToVulkan(samplerInfo.depthComparison);
|
||||
|
||||
if (samplerInfo.anisotropyLevel > 1.f)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
[0mchecking for platform ... [38;5;2;1mlinux[0m
|
||||
[0mchecking for architecture ... [38;5;2;1mx86_64[0m
|
||||
[0mchecking for gcc ... [38;5;2;1m/usr/bin/gcc[0m
|
||||
[0m[38;5;3;1mcheckinfo: [0;2mcannot runv(dmd --version), No such file or directory[0m
|
||||
[0mchecking for dmd ... [38;5;1;1mno[0m
|
||||
[0m[38;5;3;1mcheckinfo: [0;2mcannot runv(ldc2 --version), No such file or directory[0m
|
||||
[0mchecking for ldc2 ... [38;5;1;1mno[0m
|
||||
[0m[38;5;3;1mcheckinfo: [0;2mcannot runv(gdc --version), No such file or directory[0m
|
||||
[0mchecking for gdc ... [38;5;1;1mno[0m
|
||||
[0m[38;5;3;1mcheckinfo: [0;2mcannot runv(zig version), No such file or directory[0m
|
||||
[0mchecking for zig ... [38;5;1;1mno[0m
|
||||
[0m[38;5;3;1mcheckinfo: [0;2mcannot runv(zig version), No such file or directory[0m
|
||||
[0mchecking for zig ... [38;5;1;1mno[0m
|
||||
Loading…
Reference in New Issue