Renderer: Implement and fix front face (winding order) between Vulkan / OpenGL

This commit is contained in:
Jérôme Leclercq 2021-05-28 22:58:14 +02:00
parent 299585a7de
commit ff505e9019
15 changed files with 71 additions and 30 deletions

View File

@ -63,6 +63,7 @@ int main()
std::shared_ptr<Nz::Material> material = std::make_shared<Nz::Material>(Nz::BasicMaterial::GetSettings());
material->EnableDepthBuffer(true);
material->EnableFaceCulling(true);
Nz::BasicMaterial basicMat(*material);
basicMat.EnableAlphaTest(true);

View File

@ -190,6 +190,7 @@ int main()
Nz::RenderPipelineInfo pipelineInfo;
pipelineInfo.pipelineLayout = renderPipelineLayout;
pipelineInfo.faceCulling = true;
pipelineInfo.depthBuffer = true;
pipelineInfo.shaderModules.emplace_back(fragVertShader);

View File

@ -22,9 +22,7 @@ namespace Nz
OpenGLRenderPipeline(OpenGLDevice& device, RenderPipelineInfo pipelineInfo);
~OpenGLRenderPipeline() = default;
void Apply(const GL::Context& context) const;
void FlipY(bool shouldFlipY) const;
void Apply(const GL::Context& context, bool flipViewport) const;
inline const RenderPipelineInfo& GetPipelineInfo() const override;
@ -32,7 +30,7 @@ namespace Nz
RenderPipelineInfo m_pipelineInfo;
GL::Program m_program;
GLint m_flipYUniformLocation;
mutable bool m_isYFlipped;
mutable bool m_isViewportFlipped;
};
}

View File

@ -31,7 +31,8 @@ namespace Nz
inline GLenum ToOpenGL(BlendEquation blendEquation);
inline GLenum ToOpenGL(BlendFunc blendFunc);
inline GLenum ToOpenGL(FaceSide filter);
inline GLenum ToOpenGL(FaceSide side);
inline GLenum ToOpenGL(FrontFace face);
inline GLenum ToOpenGL(PrimitiveMode primitiveMode);
inline GLenum ToOpenGL(SamplerFilter filter);
inline GLenum ToOpenGL(SamplerFilter minFilter, SamplerMipmapMode mipmapFilter);

View File

@ -72,9 +72,9 @@ namespace Nz
return {};
}
inline GLenum ToOpenGL(FaceSide filter)
inline GLenum ToOpenGL(FaceSide side)
{
switch (filter)
switch (side)
{
case FaceSide::None:
break;
@ -84,11 +84,23 @@ namespace Nz
case FaceSide::FrontAndBack: return GL_FRONT_AND_BACK;
}
NazaraError("Unhandled FaceSide 0x" + NumberToString(UnderlyingCast(filter), 16));
NazaraError("Unhandled FaceSide 0x" + NumberToString(UnderlyingCast(side), 16));
return {};
}
GLenum ToOpenGL(PrimitiveMode primitiveMode)
inline GLenum ToOpenGL(FrontFace face)
{
switch (face)
{
case FrontFace::Clockwise: return GL_CW;
case FrontFace::CounterClockwise: return GL_CCW;
}
NazaraError("Unhandled FrontFace 0x" + NumberToString(UnderlyingCast(face), 16));
return {};
}
inline GLenum ToOpenGL(PrimitiveMode primitiveMode)
{
switch (primitiveMode)
{

View File

@ -144,7 +144,7 @@ namespace Nz::GL
virtual void SwapBuffers() = 0;
void UpdateStates(const RenderStates& renderStates) const;
void UpdateStates(const RenderStates& renderStates, bool isViewportFlipped) const;
#define NAZARA_OPENGLRENDERER_FUNC(name, sig) sig name = nullptr;
NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_FUNC)

View File

@ -76,6 +76,7 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G
cb(glFramebufferRenderbuffer, PFNGLFRAMEBUFFERRENDERBUFFERPROC) \
cb(glFramebufferTexture2D, PFNGLFRAMEBUFFERTEXTURE2DPROC) \
cb(glFramebufferTextureLayer, PFNGLFRAMEBUFFERTEXTURELAYERPROC) \
cb(glFrontFace, PFNGLFRONTFACEPROC) \
cb(glGenBuffers, PFNGLGENBUFFERSPROC) \
cb(glGenFramebuffers, PFNGLGENFRAMEBUFFERSPROC) \
cb(glGenQueries, PFNGLGENQUERIESPROC) \

View File

@ -21,6 +21,7 @@ namespace Nz
{
FaceFilling faceFilling = FaceFilling::Fill;
FaceSide cullingSide = FaceSide::Back;
FrontFace frontFace = FrontFace::Clockwise;
RendererComparison depthCompare = RendererComparison::Less;
PrimitiveMode primitiveMode = PrimitiveMode::TriangleList;

View File

@ -149,6 +149,14 @@ namespace Nz
Max = FrontAndBack
};
enum class FrontFace
{
Clockwise,
CounterClockwise,
Max = CounterClockwise
};
enum class ImageType
{
E1D,

View File

@ -24,6 +24,7 @@ namespace Nz
inline VkFormat ToVulkan(ComponentType componentType);
inline VkCullModeFlagBits ToVulkan(FaceSide faceSide);
inline VkPolygonMode ToVulkan(FaceFilling faceFilling);
inline VkFrontFace ToVulkan(FrontFace frontFace);
inline VkAccessFlagBits ToVulkan(MemoryAccess memoryAccess);
inline VkAccessFlags ToVulkan(MemoryAccessFlags memoryAccessFlags);
inline VkPipelineStageFlagBits ToVulkan(PipelineStage pipelineStage);

View File

@ -154,6 +154,18 @@ namespace Nz
return VK_POLYGON_MODE_FILL;
}
inline VkFrontFace ToVulkan(FrontFace frontFace)
{
switch (frontFace)
{
case FrontFace::Clockwise: return VK_FRONT_FACE_CLOCKWISE;
case FrontFace::CounterClockwise: return VK_FRONT_FACE_COUNTER_CLOCKWISE;
}
NazaraError("Unhandled FrontFace 0x" + NumberToString(UnderlyingCast(frontFace), 16));
return {};
}
inline VkAccessFlagBits ToVulkan(MemoryAccess memoryAccess)
{
switch (memoryAccess)

View File

@ -241,10 +241,7 @@ namespace Nz
void OpenGLCommandBuffer::ApplyStates(const GL::Context& context, const DrawStates& states)
{
states.pipeline->Apply(context);
states.pipeline->FlipY(states.shouldFlipY);
states.pipeline->Apply(context, states.shouldFlipY);
states.shaderBindings->Apply(context);
if (states.scissorRegion)

View File

@ -16,7 +16,7 @@ namespace Nz
{
OpenGLRenderPipeline::OpenGLRenderPipeline(OpenGLDevice& device, RenderPipelineInfo pipelineInfo) :
m_pipelineInfo(std::move(pipelineInfo)),
m_isYFlipped(false)
m_isViewportFlipped(false)
{
if (!m_program.Create(device))
throw std::runtime_error("failed to create program");
@ -39,18 +39,14 @@ namespace Nz
m_program.Uniform(m_flipYUniformLocation, 1.f);
}
void OpenGLRenderPipeline::Apply(const GL::Context& context) const
void OpenGLRenderPipeline::Apply(const GL::Context& context, bool flipViewport) const
{
context.UpdateStates(m_pipelineInfo);
context.BindProgram(m_program.GetObjectId()); //< Bind program after states
}
void OpenGLRenderPipeline::FlipY(bool shouldFlipY) const
context.UpdateStates(m_pipelineInfo, flipViewport);
context.BindProgram(m_program.GetObjectId()); //< Bind program after states (for shader caching)
if (m_isViewportFlipped != flipViewport)
{
if (m_isYFlipped != shouldFlipY)
{
m_program.Uniform(m_flipYUniformLocation, (shouldFlipY) ? -1.f : 1.f);
m_isYFlipped = shouldFlipY;
m_program.Uniform(m_flipYUniformLocation, (flipViewport) ? -1.f : 1.f);
m_isViewportFlipped = flipViewport;
}
}
}

View File

@ -363,6 +363,8 @@ namespace Nz::GL
glGetIntegerv(GL_VIEWPORT, res.data());
m_state.viewport = { res[0], res[1], res[2], res[3] };
m_state.renderStates.frontFace = FrontFace::CounterClockwise; //< OpenGL default front face is counter-clockwise
EnableVerticalSync(false);
return true;
@ -435,7 +437,7 @@ namespace Nz::GL
}
}
void Context::UpdateStates(const RenderStates& renderStates) const
void Context::UpdateStates(const RenderStates& renderStates, bool isViewportFlipped) const
{
if (!SetCurrentContext(this))
throw std::runtime_error("failed to activate context");
@ -482,11 +484,21 @@ namespace Nz::GL
{
if (m_state.renderStates.cullingSide != renderStates.cullingSide)
{
glCullFace(ToOpenGL(m_state.renderStates.cullingSide));
glCullFace(ToOpenGL(renderStates.cullingSide));
m_state.renderStates.cullingSide = renderStates.cullingSide;
}
}
FrontFace targetFrontFace = renderStates.frontFace;
if (!isViewportFlipped)
targetFrontFace = (targetFrontFace == FrontFace::Clockwise) ? FrontFace::CounterClockwise : FrontFace::Clockwise;
if (m_state.renderStates.frontFace != targetFrontFace)
{
glFrontFace(ToOpenGL(targetFrontFace));
m_state.renderStates.frontFace = targetFrontFace;
}
/*
TODO: Use glPolyonMode if available (OpenGL)
if (m_state.renderStates.faceFilling != renderStates.faceFilling)

View File

@ -140,8 +140,8 @@ namespace Nz
VkPipelineRasterizationStateCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
createInfo.polygonMode = ToVulkan(pipelineInfo.faceFilling);
createInfo.cullMode = ToVulkan(pipelineInfo.cullingSide);
createInfo.frontFace = VK_FRONT_FACE_CLOCKWISE; //< TODO
createInfo.cullMode = (pipelineInfo.faceCulling) ? ToVulkan(pipelineInfo.cullingSide) : VK_CULL_MODE_NONE;
createInfo.frontFace = ToVulkan(pipelineInfo.frontFace);
createInfo.lineWidth = pipelineInfo.lineWidth;
return createInfo;