This commit is contained in:
SirLynix 2022-11-19 17:10:27 +01:00 committed by Jérôme Leclercq
parent 4a10c1f8fe
commit e990a320cc
54 changed files with 618 additions and 154 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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
}
}
});

View File

@ -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)
{

View File

@ -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;

View File

@ -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;
};
};

View File

@ -95,6 +95,8 @@ namespace Nz
InstanceDataUbo,
LightDataUbo,
OverlayTexture,
Shadowmap2D,
ShadowmapCube,
SkeletalDataUbo,
ViewerDataUbo,

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -74,6 +74,7 @@ namespace Nz
struct DefaultTextures
{
std::array<std::shared_ptr<Texture>, ImageTypeCount> depthTextures;
std::array<std::shared_ptr<Texture>, ImageTypeCount> whiteTextures;
};

View File

@ -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;

View File

@ -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;

View File

@ -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>

View File

@ -33,6 +33,7 @@ namespace Nz
private:
std::vector<ShaderBinding::Binding> m_bindingCache;
std::vector<ShaderBinding::TextureBinding> m_textureBindingCache;
RenderElementPool<RenderSubmesh> m_submeshPool;
};

View File

@ -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;

View File

@ -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);

View File

@ -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));

View File

@ -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) \

View File

@ -21,8 +21,9 @@ namespace Nz
{
struct Binding
{
UInt32 setIndex = 0;
UInt32 arraySize = 1;
UInt32 bindingIndex;
UInt32 setIndex = 0;
ShaderBindingType type;
nzsl::ShaderStageTypeFlags shaderStageFlags;
};

View File

@ -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;
};

View File

@ -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
{

View File

@ -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:

View File

@ -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;

View File

@ -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;
}

View File

@ -147,7 +147,7 @@ namespace Nz
Max = Point
};
enum class FaceSide
enum class FaceCulling
{
None,

View File

@ -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);

View File

@ -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));

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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());

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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)
);

View File

@ -13,7 +13,8 @@ struct Light
parameter1: vec4[f32],
parameter2: vec4[f32],
parameter3: vec4[f32],
hasShadowMapping: u32
hasShadowMapping: u32,
viewProjMatrix: mat4[f32]
}
[export]

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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*/)

View File

@ -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()
};
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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)
{

View File

@ -39,7 +39,7 @@ namespace Nz
RenderPipelineLayoutInfo layoutInfo;
layoutInfo.bindings.assign({
{
0, 0,
1, 0, 0,
ShaderBindingType::UniformBuffer,
nzsl::ShaderStageType::Vertex
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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)
{

13
test.txt Normal file
View File

@ -0,0 +1,13 @@
checking for platform ... linux
checking for architecture ... x86_64
checking for gcc ... /usr/bin/gcc
checkinfo: cannot runv(dmd --version), No such file or directory
checking for dmd ... no
checkinfo: cannot runv(ldc2 --version), No such file or directory
checking for ldc2 ... no
checkinfo: cannot runv(gdc --version), No such file or directory
checking for gdc ... no
checkinfo: cannot runv(zig version), No such file or directory
checking for zig ... no
checkinfo: cannot runv(zig version), No such file or directory
checking for zig ... no