Renderer: Implement and fix front face (winding order) between Vulkan / OpenGL
This commit is contained in:
parent
299585a7de
commit
ff505e9019
|
|
@ -63,6 +63,7 @@ int main()
|
||||||
|
|
||||||
std::shared_ptr<Nz::Material> material = std::make_shared<Nz::Material>(Nz::BasicMaterial::GetSettings());
|
std::shared_ptr<Nz::Material> material = std::make_shared<Nz::Material>(Nz::BasicMaterial::GetSettings());
|
||||||
material->EnableDepthBuffer(true);
|
material->EnableDepthBuffer(true);
|
||||||
|
material->EnableFaceCulling(true);
|
||||||
|
|
||||||
Nz::BasicMaterial basicMat(*material);
|
Nz::BasicMaterial basicMat(*material);
|
||||||
basicMat.EnableAlphaTest(true);
|
basicMat.EnableAlphaTest(true);
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,7 @@ int main()
|
||||||
|
|
||||||
Nz::RenderPipelineInfo pipelineInfo;
|
Nz::RenderPipelineInfo pipelineInfo;
|
||||||
pipelineInfo.pipelineLayout = renderPipelineLayout;
|
pipelineInfo.pipelineLayout = renderPipelineLayout;
|
||||||
|
pipelineInfo.faceCulling = true;
|
||||||
|
|
||||||
pipelineInfo.depthBuffer = true;
|
pipelineInfo.depthBuffer = true;
|
||||||
pipelineInfo.shaderModules.emplace_back(fragVertShader);
|
pipelineInfo.shaderModules.emplace_back(fragVertShader);
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,7 @@ namespace Nz
|
||||||
OpenGLRenderPipeline(OpenGLDevice& device, RenderPipelineInfo pipelineInfo);
|
OpenGLRenderPipeline(OpenGLDevice& device, RenderPipelineInfo pipelineInfo);
|
||||||
~OpenGLRenderPipeline() = default;
|
~OpenGLRenderPipeline() = default;
|
||||||
|
|
||||||
void Apply(const GL::Context& context) const;
|
void Apply(const GL::Context& context, bool flipViewport) const;
|
||||||
|
|
||||||
void FlipY(bool shouldFlipY) const;
|
|
||||||
|
|
||||||
inline const RenderPipelineInfo& GetPipelineInfo() const override;
|
inline const RenderPipelineInfo& GetPipelineInfo() const override;
|
||||||
|
|
||||||
|
|
@ -32,7 +30,7 @@ namespace Nz
|
||||||
RenderPipelineInfo m_pipelineInfo;
|
RenderPipelineInfo m_pipelineInfo;
|
||||||
GL::Program m_program;
|
GL::Program m_program;
|
||||||
GLint m_flipYUniformLocation;
|
GLint m_flipYUniformLocation;
|
||||||
mutable bool m_isYFlipped;
|
mutable bool m_isViewportFlipped;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,8 @@ namespace Nz
|
||||||
|
|
||||||
inline GLenum ToOpenGL(BlendEquation blendEquation);
|
inline GLenum ToOpenGL(BlendEquation blendEquation);
|
||||||
inline GLenum ToOpenGL(BlendFunc blendFunc);
|
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(PrimitiveMode primitiveMode);
|
||||||
inline GLenum ToOpenGL(SamplerFilter filter);
|
inline GLenum ToOpenGL(SamplerFilter filter);
|
||||||
inline GLenum ToOpenGL(SamplerFilter minFilter, SamplerMipmapMode mipmapFilter);
|
inline GLenum ToOpenGL(SamplerFilter minFilter, SamplerMipmapMode mipmapFilter);
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,9 @@ namespace Nz
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline GLenum ToOpenGL(FaceSide filter)
|
inline GLenum ToOpenGL(FaceSide side)
|
||||||
{
|
{
|
||||||
switch (filter)
|
switch (side)
|
||||||
{
|
{
|
||||||
case FaceSide::None:
|
case FaceSide::None:
|
||||||
break;
|
break;
|
||||||
|
|
@ -84,11 +84,23 @@ namespace Nz
|
||||||
case FaceSide::FrontAndBack: return GL_FRONT_AND_BACK;
|
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 {};
|
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)
|
switch (primitiveMode)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ namespace Nz::GL
|
||||||
|
|
||||||
virtual void SwapBuffers() = 0;
|
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;
|
#define NAZARA_OPENGLRENDERER_FUNC(name, sig) sig name = nullptr;
|
||||||
NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_FUNC)
|
NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_FUNC)
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G
|
||||||
cb(glFramebufferRenderbuffer, PFNGLFRAMEBUFFERRENDERBUFFERPROC) \
|
cb(glFramebufferRenderbuffer, PFNGLFRAMEBUFFERRENDERBUFFERPROC) \
|
||||||
cb(glFramebufferTexture2D, PFNGLFRAMEBUFFERTEXTURE2DPROC) \
|
cb(glFramebufferTexture2D, PFNGLFRAMEBUFFERTEXTURE2DPROC) \
|
||||||
cb(glFramebufferTextureLayer, PFNGLFRAMEBUFFERTEXTURELAYERPROC) \
|
cb(glFramebufferTextureLayer, PFNGLFRAMEBUFFERTEXTURELAYERPROC) \
|
||||||
|
cb(glFrontFace, PFNGLFRONTFACEPROC) \
|
||||||
cb(glGenBuffers, PFNGLGENBUFFERSPROC) \
|
cb(glGenBuffers, PFNGLGENBUFFERSPROC) \
|
||||||
cb(glGenFramebuffers, PFNGLGENFRAMEBUFFERSPROC) \
|
cb(glGenFramebuffers, PFNGLGENFRAMEBUFFERSPROC) \
|
||||||
cb(glGenQueries, PFNGLGENQUERIESPROC) \
|
cb(glGenQueries, PFNGLGENQUERIESPROC) \
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
FaceFilling faceFilling = FaceFilling::Fill;
|
FaceFilling faceFilling = FaceFilling::Fill;
|
||||||
FaceSide cullingSide = FaceSide::Back;
|
FaceSide cullingSide = FaceSide::Back;
|
||||||
|
FrontFace frontFace = FrontFace::Clockwise;
|
||||||
RendererComparison depthCompare = RendererComparison::Less;
|
RendererComparison depthCompare = RendererComparison::Less;
|
||||||
PrimitiveMode primitiveMode = PrimitiveMode::TriangleList;
|
PrimitiveMode primitiveMode = PrimitiveMode::TriangleList;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,14 @@ namespace Nz
|
||||||
Max = FrontAndBack
|
Max = FrontAndBack
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class FrontFace
|
||||||
|
{
|
||||||
|
Clockwise,
|
||||||
|
CounterClockwise,
|
||||||
|
|
||||||
|
Max = CounterClockwise
|
||||||
|
};
|
||||||
|
|
||||||
enum class ImageType
|
enum class ImageType
|
||||||
{
|
{
|
||||||
E1D,
|
E1D,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ namespace Nz
|
||||||
inline VkFormat ToVulkan(ComponentType componentType);
|
inline VkFormat ToVulkan(ComponentType componentType);
|
||||||
inline VkCullModeFlagBits ToVulkan(FaceSide faceSide);
|
inline VkCullModeFlagBits ToVulkan(FaceSide faceSide);
|
||||||
inline VkPolygonMode ToVulkan(FaceFilling faceFilling);
|
inline VkPolygonMode ToVulkan(FaceFilling faceFilling);
|
||||||
|
inline VkFrontFace ToVulkan(FrontFace frontFace);
|
||||||
inline VkAccessFlagBits ToVulkan(MemoryAccess memoryAccess);
|
inline VkAccessFlagBits ToVulkan(MemoryAccess memoryAccess);
|
||||||
inline VkAccessFlags ToVulkan(MemoryAccessFlags memoryAccessFlags);
|
inline VkAccessFlags ToVulkan(MemoryAccessFlags memoryAccessFlags);
|
||||||
inline VkPipelineStageFlagBits ToVulkan(PipelineStage pipelineStage);
|
inline VkPipelineStageFlagBits ToVulkan(PipelineStage pipelineStage);
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,19 @@ namespace Nz
|
||||||
NazaraError("Unhandled FaceFilling 0x" + NumberToString(UnderlyingCast(faceFilling), 16));
|
NazaraError("Unhandled FaceFilling 0x" + NumberToString(UnderlyingCast(faceFilling), 16));
|
||||||
return VK_POLYGON_MODE_FILL;
|
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)
|
inline VkAccessFlagBits ToVulkan(MemoryAccess memoryAccess)
|
||||||
{
|
{
|
||||||
switch (memoryAccess)
|
switch (memoryAccess)
|
||||||
|
|
|
||||||
|
|
@ -241,10 +241,7 @@ namespace Nz
|
||||||
|
|
||||||
void OpenGLCommandBuffer::ApplyStates(const GL::Context& context, const DrawStates& states)
|
void OpenGLCommandBuffer::ApplyStates(const GL::Context& context, const DrawStates& states)
|
||||||
{
|
{
|
||||||
states.pipeline->Apply(context);
|
states.pipeline->Apply(context, states.shouldFlipY);
|
||||||
|
|
||||||
states.pipeline->FlipY(states.shouldFlipY);
|
|
||||||
|
|
||||||
states.shaderBindings->Apply(context);
|
states.shaderBindings->Apply(context);
|
||||||
|
|
||||||
if (states.scissorRegion)
|
if (states.scissorRegion)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
OpenGLRenderPipeline::OpenGLRenderPipeline(OpenGLDevice& device, RenderPipelineInfo pipelineInfo) :
|
OpenGLRenderPipeline::OpenGLRenderPipeline(OpenGLDevice& device, RenderPipelineInfo pipelineInfo) :
|
||||||
m_pipelineInfo(std::move(pipelineInfo)),
|
m_pipelineInfo(std::move(pipelineInfo)),
|
||||||
m_isYFlipped(false)
|
m_isViewportFlipped(false)
|
||||||
{
|
{
|
||||||
if (!m_program.Create(device))
|
if (!m_program.Create(device))
|
||||||
throw std::runtime_error("failed to create program");
|
throw std::runtime_error("failed to create program");
|
||||||
|
|
@ -39,18 +39,14 @@ namespace Nz
|
||||||
m_program.Uniform(m_flipYUniformLocation, 1.f);
|
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.UpdateStates(m_pipelineInfo, flipViewport);
|
||||||
context.BindProgram(m_program.GetObjectId()); //< Bind program after states
|
context.BindProgram(m_program.GetObjectId()); //< Bind program after states (for shader caching)
|
||||||
}
|
if (m_isViewportFlipped != flipViewport)
|
||||||
|
|
||||||
void OpenGLRenderPipeline::FlipY(bool shouldFlipY) const
|
|
||||||
{
|
|
||||||
if (m_isYFlipped != shouldFlipY)
|
|
||||||
{
|
{
|
||||||
m_program.Uniform(m_flipYUniformLocation, (shouldFlipY) ? -1.f : 1.f);
|
m_program.Uniform(m_flipYUniformLocation, (flipViewport) ? -1.f : 1.f);
|
||||||
m_isYFlipped = shouldFlipY;
|
m_isViewportFlipped = flipViewport;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,6 +363,8 @@ namespace Nz::GL
|
||||||
glGetIntegerv(GL_VIEWPORT, res.data());
|
glGetIntegerv(GL_VIEWPORT, res.data());
|
||||||
m_state.viewport = { res[0], res[1], res[2], res[3] };
|
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);
|
EnableVerticalSync(false);
|
||||||
|
|
||||||
return true;
|
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))
|
if (!SetCurrentContext(this))
|
||||||
throw std::runtime_error("failed to activate context");
|
throw std::runtime_error("failed to activate context");
|
||||||
|
|
@ -482,11 +484,21 @@ namespace Nz::GL
|
||||||
{
|
{
|
||||||
if (m_state.renderStates.cullingSide != renderStates.cullingSide)
|
if (m_state.renderStates.cullingSide != renderStates.cullingSide)
|
||||||
{
|
{
|
||||||
glCullFace(ToOpenGL(m_state.renderStates.cullingSide));
|
glCullFace(ToOpenGL(renderStates.cullingSide));
|
||||||
m_state.renderStates.cullingSide = 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)
|
TODO: Use glPolyonMode if available (OpenGL)
|
||||||
if (m_state.renderStates.faceFilling != renderStates.faceFilling)
|
if (m_state.renderStates.faceFilling != renderStates.faceFilling)
|
||||||
|
|
|
||||||
|
|
@ -140,8 +140,8 @@ namespace Nz
|
||||||
VkPipelineRasterizationStateCreateInfo createInfo = {};
|
VkPipelineRasterizationStateCreateInfo createInfo = {};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
createInfo.polygonMode = ToVulkan(pipelineInfo.faceFilling);
|
createInfo.polygonMode = ToVulkan(pipelineInfo.faceFilling);
|
||||||
createInfo.cullMode = ToVulkan(pipelineInfo.cullingSide);
|
createInfo.cullMode = (pipelineInfo.faceCulling) ? ToVulkan(pipelineInfo.cullingSide) : VK_CULL_MODE_NONE;
|
||||||
createInfo.frontFace = VK_FRONT_FACE_CLOCKWISE; //< TODO
|
createInfo.frontFace = ToVulkan(pipelineInfo.frontFace);
|
||||||
createInfo.lineWidth = pipelineInfo.lineWidth;
|
createInfo.lineWidth = pipelineInfo.lineWidth;
|
||||||
|
|
||||||
return createInfo;
|
return createInfo;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue