Commit 0d558ddf authored by Patrik Huber's avatar Patrik Huber

First version of new software renderer

It is modeled after the vertex shader / fragment shader approach of modern OpenGL.
It also includes a texture extraction fragment shader, which hopefully will replace the current affine texture extraction.

This is still very much experimental, containing lots of todo's. For example it contains lots of if-hacks to select the correct fragment shader (for rendering or texture extraction).
parent 67f93793
......@@ -93,6 +93,10 @@ set(HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/include/eos/render/detail/render_affine_detail.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/eos/render/texture_extraction.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/eos/render/detail/texture_extraction_detail.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/eos/render/SoftwareRenderer.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/eos/render/VertexShader.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/eos/render/FragmentShader.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/eos/render/detail/Vertex.hpp
)
add_library(eos INTERFACE)
......
/*
* eos - A 3D Morphable Model fitting library written in modern C++11/14.
*
* File: include/eos/render/FragmentShader.hpp
*
* Copyright 2017 Patrik Huber
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#ifndef FRAGMENTSHADER_HPP_
#define FRAGMENTSHADER_HPP_
#include "eos/render/detail/Vertex.hpp"
#include "eos/render/utils.hpp"
#include "glm/vec3.hpp"
#include "glm/vec4.hpp"
#include "boost/optional.hpp"
// Fragment shaders are a more accurate name for the same functionality as Pixel shaders. They aren't pixels
// yet, since the output still has to past several tests (depth, alpha, stencil) as well as the fact that one
// may be using antialiasing, which renders one-fragment-to-one-pixel non-true.
// The "pixel" in "pixel shader" is a misnomer because the pixel shader doesn't operate on pixels directly.
// The pixel shader operates on "fragments" which may or may not end up as actual pixels, depending on several
// factors outside of the pixel shader.
// The shaders *can not* depend on any state - they have to be able to run independently and in parallel!
// But can they really? What about the z-test? It happens earlier at the moment - which is good?
namespace eos {
namespace render {
/**
* @brief A simple fragment shader that does vertex-colouring.
*
* Uses the vertex colour data to shade the given fragment / pixel location.
*/
class VertexColoringFragmentShader
{
public:
/**
* @brief Todo.
*
* X
* lambda is not perspectively corrected. Note: In our case, it is, as we do it in the raster loop at
* the moment?
* Note/TODO: We should document in what range we expect ::color to be! Eg specify that Mesh should be
* [0,255]? But don't we then lose precision sometimes (e.g. superres)? I think we can leave Mesh /
* everything in [0,1] and convert at the very end.
*
* @param[in] x X.
* @ return RGBA... in [0, 1]?
*/
template <typename T, glm::precision P = glm::defaultp>
glm::tvec4<T, P>
shade_triangle_pixel(int x, int y, const detail::v2::Vertex<T, P>& point_a,
const detail::v2::Vertex<T, P>& point_b, const detail::v2::Vertex<T, P>& point_c,
const glm::tvec3<T, P>& lambda, const boost::optional<Texture>& texture, float dudx,
float dudy, float dvdx, float dvdy)
{
// attributes interpolation
glm::tvec3<T, P> color_persp =
lambda[0] * point_a.color + lambda[1] * point_b.color + lambda[2] * point_c.color;
return glm::tvec4<T, P>(color_persp, T(1));
};
};
/**
* @brief A fragment shader that textures...
*
* X.
*/
class TexturingFragmentShader
{
public:
/**
* @brief Todo.
*
* See comments above about lambda (persp. corrected?) and the colour range.
*
* @param[in] x X.
* @ return RGBA... in [0, 1]?
*/
template <typename T, glm::precision P = glm::defaultp>
glm::tvec4<T, P>
shade_triangle_pixel(int x, int y, const detail::v2::Vertex<T, P>& point_a,
const detail::v2::Vertex<T, P>& point_b, const detail::v2::Vertex<T, P>& point_c,
const glm::tvec3<T, P>& lambda, const boost::optional<eos::render::Texture>& texture,
float dudx, float dudy, float dvdx, float dvdy)
{
glm::tvec2<T, P> texcoords_persp =
lambda[0] * point_a.texcoords + lambda[1] * point_b.texcoords + lambda[2] * point_c.texcoords;
// The Texture is in BGR, thus tex2D returns BGR
// Todo: Think about changing that.
glm::tvec3<T, P> texture_color =
detail::tex2d(texcoords_persp, texture.get(), dudx, dudy, dvdx, dvdy); // uses the current texture
glm::tvec3<T, P> pixel_color = glm::tvec3<T, P>(texture_color[2], texture_color[1], texture_color[0]);
// other: color.mul(tex2D(texture, texCoord));
return glm::tvec4<T, P>(pixel_color, T(1));
};
};
/**
* @brief X.
*
* X.
* Inverts the perspective texture mapping. Can be derived using some tedious algebra.
* Todo: Probably move to a texturing file, internal/detail one, where we will also put the tex2d, mipmapping
* etc stuff?
*
* @param[in] X X.
* @return X.
*/
template <typename T, glm::precision P = glm::defaultp>
glm::tvec3<T, P> compute_inverse_perspectively_correct_lambda(const glm::tvec3<T, P>& lambda_world,
const T& one_over_w0, const T& one_over_w1,
const T& one_over_w2)
{
float w0 = 1 / one_over_w0;
float w1 = 1 / one_over_w1;
float w2 = 1 / one_over_w2;
float d = w0 - (w0 - w1) * lambda_world.y - (w0 - w2) * lambda_world.z;
if (d == 0)
return lambda_world;
glm::tvec3<T, P> lambda;
lambda.z = lambda_world.z * w2 / d;
lambda.y = lambda_world.y * w1 / d;
lambda.x = 1 - lambda.y - lambda.z;
return lambda;
};
class ExtractionFragmentShader
{
public:
/**
* @brief X.
*
* X.
* Inverts the perspective texture mapping. Can be derived using some tedious algebra.
* NOTE: This one actually takes/needs the perspectively corrected lambda I think!
*
* Todo: Probably move to a texturing file, internal/detail one, where we will also put the tex2d,
* mipmapping etc stuff?
*
* @param[in] X X.
* @return X.
*/
template <typename T, glm::precision P = glm::defaultp>
glm::tvec4<T, P>
shade_triangle_pixel(int x, int y, const detail::v2::Vertex<T, P>& point_a,
const detail::v2::Vertex<T, P>& point_b, const detail::v2::Vertex<T, P>& point_c,
const glm::tvec3<T, P>& lambda, const boost::optional<Texture>& texture, float dudx,
float dudy, float dvdx, float dvdy)
{
auto corrected_lambda = compute_inverse_perspectively_correct_lambda(
lambda, point_a.position.w, point_b.position.w, point_c.position.w);
glm::tvec2<T, P> texcoords_persp = corrected_lambda[0] * point_a.texcoords +
corrected_lambda[1] * point_b.texcoords +
corrected_lambda[2] * point_c.texcoords;
// Texturing, no mipmapping:
cv::Vec2f image_tex_coords = detail::texcoord_wrap(cv::Vec2f(texcoords_persp.s, texcoords_persp.t));
image_tex_coords[0] *= texture->mipmaps[0].cols;
image_tex_coords[1] *= texture->mipmaps[0].rows;
cv::Vec3f texture_color = detail::tex2d_linear(image_tex_coords, 0, texture.get()) / 255.0;
glm::tvec3<T, P> pixel_color = glm::tvec3<T, P>(texture_color[2], texture_color[1], texture_color[0]);
return glm::tvec4<T, P>(pixel_color, T(1));
};
};
} /* namespace render */
} /* namespace eos */
#endif /* FRAGMENTSHADER_HPP_ */
This diff is collapsed.
/*
* eos - A 3D Morphable Model fitting library written in modern C++11/14.
*
* File: include/eos/render/VertexShader.hpp
*
* Copyright 2017 Patrik Huber
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#ifndef VERTEXSHADER_HPP_
#define VERTEXSHADER_HPP_
#include "glm/mat4x4.hpp"
#include "glm/vec4.hpp"
namespace eos {
namespace render {
/**
* @brief A simple vertex shader that projects the vertex and returns the vertex in clip-space coordinates.
*/
class VertexShader
{
public:
/**
* @brief Projects the given vertex into clip-space and returns it.
*
* @param[in] vertex The vertex to project.
* @param[in] model_view_matrix The model-view matrix.
* @param[in] projection_matrix The projection matrix.
* @tparam VT Vertex type.
* @tparam VP Vertex precision.
* @tparam MT Matrix type.
* @tparam MP Matrix precision.
* @return Vertex projected to clip space.
*/
template <typename VT, glm::precision VP, typename MT, glm::precision MP = glm::defaultp>
glm::tvec4<MT, MP> operator()(const glm::tvec4<VT, VP>& vertex,
const glm::tmat4x4<MT, MP>& model_view_matrix,
const glm::tmat4x4<MT, MP>& projection_matrix)
{
return projection_matrix * model_view_matrix * vertex;
};
};
} /* namespace render */
} /* namespace eos */
#endif /* VERTEXSHADER_HPP_ */
/*
* eos - A 3D Morphable Model fitting library written in modern C++11/14.
*
* File: include/eos/render/detail/Vertex.hpp
*
* Copyright 2017 Patrik Huber
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#ifndef VERTEX_HPP_
#define VERTEX_HPP_
#include "glm/vec2.hpp"
#include "glm/vec3.hpp"
#include "glm/vec4.hpp"
/**
* The detail namespace contains implementations of internal functions, not part of the API we expose and not
* meant to be used by a user.
*/
namespace eos {
namespace render {
namespace detail {
// In a v2 namespace for now to disambiguate between this and the "older" Vertex class:
namespace v2 {
/**
* @brief A representation for a vertex during rendering, used internally.
*
* It's used to build the vertices that will be rendered, and new vertices that are generated by the renderer
* (during clipping).
* I should check at some point that no unnecessary copies of the vertex data is created in some places, but I
* think it's pretty much fine.
*
* FragmentShader and SoftwareRenderer use this.
*
* This is the same as the one in the current render_detail.hpp, except that this is fully templated.
*
*/
template <typename T, glm::precision P = glm::defaultp>
struct Vertex
{
glm::tvec4<T, P> position; // XYZW
glm::tvec3<T, P> color; // RGB order
glm::tvec2<T, P> texcoords; // UV
};
} /* namespace v2 */
} /* namespace detail */
} /* namespace render */
} /* namespace eos */
#endif /* VERTEX_HPP_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment