plenty of additions to rendering. transformation now work almost as expected ...

This commit is contained in:
Hartmut Seichter 2019-02-12 21:28:20 +01:00
parent 841b0eeb46
commit 40b84fb78f
18 changed files with 242 additions and 251 deletions

View file

@ -24,6 +24,7 @@
#define PW_CORE_MATH_HPP
#include <cmath>
#include <algorithm>
namespace pw {
@ -45,6 +46,20 @@ inline T deg_to_rad(const T& angle_in_degree) {
return angle_in_degree * __DEG2RAD;
}
template <typename T>
static inline
T repeat(const T& t, const T& length) {
return std::clamp(t - std::floor(t / length) * length, T(0), length);
}
template <typename T>
static inline
T ping_pong(const T& t,const T& length) {
auto tn = repeat(t, length * T(2));
return length - std::abs(tn - length);
}
}
#endif

View file

@ -39,23 +39,42 @@ struct transform_tools {
}
inline static
matrix_<4,4,T> projection_from_frustum(T left,T right,T bottom,T top,T z_near,T z_far)
matrix_<4,4,T> projection_from_frustum(const T &left,const T &right,
const T &bottom,const T &top,
const T &z_near,const T &z_far)
{
matrix_<4,4,T> frustum; frustum.zero();
frustum(0,0) = T(2) * z_near / (right - left);
frustum(1,1) = T(2) * z_near / (top - bottom);
frustum(0,0) = T(2) * z_near / (right - left);
frustum(1,1) = T(2) * z_near / (top - bottom);
frustum(2,0) = (right+left)/(right-left); //A
frustum(2,1) = (top+bottom)/(top-bottom); //B
frustum(2,2) = - (z_far+z_near)/(z_far-z_near); //C
frustum(2,3) = -(T(2) * z_far*z_near)/(z_far-z_near); //D
frustum(0,2) = (right+left)/(right-left); //A
frustum(1,2) = (top+bottom)/(top-bottom); //B
frustum(2,2) = -(z_far+z_near)/(z_far-z_near); //C
frustum(2,3) = -T(2) * z_far*z_near/(z_far-z_near); //D
frustum(3,2) = -T(1);
frustum(3,2) = -T(1);
return frustum;
}
inline static
matrix_<4,4,T> perspective_projection(const T &field_of_view,
const T &aspect_ratio,
const T &z_near,const T &z_far)
{
const T tan_half = tan(field_of_view / T(2));
const T right = aspect_ratio * tan_half * z_near;
const T left = -right;
const T top = aspect_ratio * tan_half;
const T bottom = -top;
return projection_from_frustum(left,right,
bottom,top,
z_near,z_far);
}
inline static
matrix_<4,4,T> orthogonal_projection(T left, T right,
T bottom,T top,
@ -78,63 +97,25 @@ struct transform_tools {
return ortho;
}
inline static
matrix_<4,4,T> perspective_projection(T fov_y, T aspect_ratio, T z_near, T z_far)
{
const T height = z_near * tan(fov_y/T(360) * pi<T>()); // half height of near plane
const T width = height * aspect_ratio; // half width of near plane
return projection_from_frustum(-width, width, -height, height, z_near, z_far );
}
inline static
matrix_<4,4,T> look_at(
const vector3_<T> &eye,
const vector3_<T> &target,
const vector3_<T> &up)
{
inline static
matrix_<4,4,T> look_at(const vector3_<T> &position,
const vector3_<T> &target,
const vector3_<T> &up)
{
matrix_<4,4,T> view_matrix; view_matrix.set_identity();
const vector3_<T> L = (target - eye).normalized(); // line of sight
const vector3_<T> S = L.cross(up).normalized();
const vector3_<T> Ud = S.cross(L).normalized();
const vector3_<T> los = (target - position).normalized(); // line of sight
const vector3_<T> sid = los.cross(up).normalized();
const vector3_<T> upd = sid.cross(los).normalized();
// set base vectors
view_matrix.set_slice(S, 0,0);
view_matrix.set_slice(Ud, 0,1);
view_matrix.set_slice(L*T(-1), 0,2);
view_matrix.set_slice(eye, 0,3);
return view_matrix;
// matrix<3,1,T> S = matrix31<T>::Cross(L,up);
// S.normalize();
// matrix<3,1,T> Ud = matrix31<T>::Cross(S,L);
// Ud.normalize();
// lookat(0,0) = S.at(0);
// lookat(0,1) = S.at(1);
// lookat(0,2) = S.at(2);
// lookat(0,3) = T(0);
// lookat(1,0) = Ud.at(0);
// lookat(1,1) = Ud.at(1);
// lookat(1,2) = Ud.at(2);
// lookat(1,3) = T(0);
// lookat(2,0) = -L.at(0);
// lookat(2,1) = -L.at(1);
// lookat(2,2) = -L.at(2);
// lookat(3,2) = T(0);
// lookat(3,0) = eye.at(0);
// lookat(3,1) = eye.at(1);
// lookat(3,2) = eye.at(2);
// lookat(3,3) = 1;
// return lookat;
view_matrix.set_slice(sid, 0, 0);
view_matrix.set_slice(upd, 0, 1);
view_matrix.set_slice(los * T(-1), 0, 2);
view_matrix.set_slice(position, 0, 3);
return view_matrix;
}
};

View file

@ -24,6 +24,9 @@ struct image_io::impl
image r;
r.create(sizei(x,y),image::pixel_layout::RGBA8,data);
stbi_image_free(data);
return r;
}

View file

@ -47,7 +47,7 @@ public:
using component::component;
camera();
camera(node &host);
void set_projection(const matrix4x4 &projection);
const matrix4x4& projection() const;

View file

@ -42,11 +42,9 @@ class component {
public:
friend class node;
typedef std::vector<component> array;
typedef std::shared_ptr<component> ref;
typedef std::vector<ref> array;
component();
component(node &host);
component(const component& other);
virtual ~component();
@ -56,15 +54,14 @@ public:
uint32_t weight() const;
void set_weight(const uint32_t &weight);
template <typename T>
inline T* cast() { return static_cast<T*>(this);}
protected:
uint32_t _weight = 0;
uint32_t _weight = 1;
node* _node;
node &_node;
bool _enabled;
};

View file

@ -42,6 +42,8 @@ namespace pw {
class node {
public:
friend class component;
typedef shared_ptr<node> ref;
typedef std::vector<ref> ref_array;
@ -66,8 +68,8 @@ public:
//! return parent of this node
inline ptr parent() const { return _path.back(); }
//! add a child node
ref add_child();
//! add a child node
void add_child(ref child_node);
//! remove a child
void remove_child(ref child_node);
@ -85,29 +87,25 @@ public:
inline bool is_root() const { return _path.empty(); }
//! list of components
const component::array& components() const;
const component::array& components() const;
//! add a node component
void add_component(component::ref new_component);
void add_component(component new_component);
template<typename T>
void add_component_() {
_components.push_back(T(*this));
}
//! remove a node component
void remove_component(component::ref c);
void remove_component(component c);
//! paths to root
const ptr_array& path() const;
void traversal();
template <typename T>
T* find_component()
{
for (auto c : _components) {
T* r = static_cast<T*>(c.get());
if (r != nullptr) return r;
}
return nullptr;
}
// not sure about this
const class transform& transform() const { return _transform; }
class transform& transform() { return _transform; }
@ -116,10 +114,10 @@ protected:
ref_array _children; //!< list of children
ptr_array _path; //!< path to root
component::array _components; //<! components
class transform _transform;
component::array _components; //<! components
std::string _name;
// change mask

View file

@ -5,16 +5,14 @@
#include <pw/core/quaternion.hpp>
#include <pw/core/vector.hpp>
#include <pw/scene/component.hpp>
namespace pw {
class transform : public component {
class node;
class transform {
public:
using component::component;
transform();
transform(node &host);
inline const matrix4x4& local() const { return _local; }
void set_local(const matrix4x4 &local);
@ -22,42 +20,59 @@ public:
inline const matrix4x4& global() const { return _global; }
void set_global(const matrix4x4 &global);
inline void translate(const real_t &x, const real_t &y, const real_t &z) {
inline const matrix4x4& global_inverse() const { return _global_inverse; }
inline transform& translate(const real_t &x, const real_t &y, const real_t &z) {
_local(0,3) += x;_local(1,3) += y;_local(2,3) += z;
update_global_from_local();
return *this;
}
inline void rotate(const quaternion& q) {
inline transform& set_translation(const real_t &x, const real_t &y, const real_t &z) {
_local(0,3) = x;_local(1,3) = y;_local(2,3) = z;
update_global_from_local();
return *this;
}
inline transform& rotate(const quaternion& q) {
_local = _local * q.to_matrix();
update_global_from_local();
return *this;
}
inline void scale(const real_t &x, const real_t &y, const real_t &z) {
_local(0,0) *= x; _local(1,1) *= y; _local(2,2) *= z;
inline transform& set_rotation(const quaternion& q) {
_local = q.to_matrix();
update_global_from_local();
return *this;
}
inline void scale(const real_t& uniform_scale) {
scale(uniform_scale,uniform_scale,uniform_scale);
}
inline void set_translation(const real_t &x, const real_t &y, const real_t &z) {
_local(0,3) = x;_local(1,3) = y;_local(2,3) = z;
inline transform& scale(const real_t &sx, const real_t &sy, const real_t &sz) {
_local(0,0) *= sx; _local(1,1) *= sy; _local(2,2) *= sz;
update_global_from_local();
return *this;
}
inline transform& set_scale(const real_t &sx, const real_t &sy, const real_t &sz) {
_local(0,0) = sx; _local(1,1) = sy; _local(2,2) = sz;
update_global_from_local();
return *this;
}
void update(node &node);
inline transform& scale(const real_t& uniform_scale) {
return scale(uniform_scale,uniform_scale,uniform_scale);
}
protected:
matrix4x4 _local;
matrix4x4 _global;
matrix4x4 _global_inverse;
private:
node &_node;
//! updates the global transform from parent globals and local transform
void update_global_from_local();
@ -65,8 +80,6 @@ private:
void update_local_from_global();
};
}
#endif

View file

@ -3,8 +3,9 @@
namespace pw {
camera::camera()
: _fov(60.0)
camera::camera(node &host)
: component (host)
, _fov(60.0)
, _near_plane(0.2f)
, _far_plane(1000)
{
@ -16,6 +17,20 @@ void camera::set_projection(const matrix4x4 &projection)
this->_projection = projection;
// recompute the simplified parameters
auto near = _projection(3,4);
auto far = _projection(3,4);
// right = (1-m14) / m11
// near = (1+m34)/m33;
// far = -(1-m34)/m33;
// bottom = (1-m24)/m22;
// top = -(1+m24)/m22;
// left = -(1+m14)/m11;
// right = (1-m14)/m11;
// real_t fov_raw = float( atan (top / near_)) * * 2.0f;
}
const matrix4x4 &camera::projection() const

View file

@ -11,8 +11,8 @@
namespace pw {
component::component()
: _node(nullptr)
component::component(node &host)
: _node(host)
{
}
@ -23,7 +23,6 @@ component::component(const component &other)
component::~component()
{
// if (_node != nullptr) _node->unregister_component(this);
}
bool component::enabled() const

View file

@ -1,11 +1,12 @@
#include "pw/scene/transform.hpp"
#include "pw/scene/node.hpp"
#include <iostream>
#include "pw/core/debug.hpp"
namespace pw {
node::node()
: _transform(*this)
{
}
@ -13,7 +14,9 @@ node::node(const node &node)
: _children(node.children())
, _components(node.components())
, _name(node._name)
, _transform(*this)
{
// _components.push_back(std::make_unique<transform>(*this));
}
node::ref node::clone(const unsigned short &copymode) const
@ -31,22 +34,16 @@ void node::set_name(const std::string &name)
_name = name;
}
node::ref node::add_child()
void node::add_child(node::ref c)
{
// create new node
node::ref new_node = std::make_shared<node>();
// take parent nodepath ...
if (!this->is_root()) new_node->_path = this->_path;
c->_path = this->_path;
// add itself
new_node->_path.push_back(this);
// add current node
c->_path.push_back(this);
// add as child
_children.push_back(new_node);
// return
return new_node;
_children.push_back(c);
}
void node::remove_child(ref child_node)
@ -72,28 +69,22 @@ node::~node()
//
// components
//
void node::add_component(component::ref new_component)
void node::add_component(component new_component)
{
// assumption is that only transform is a "singular" node
_components.push_back(new_component);
}
void node::remove_component(component::ref c)
void node::remove_component(component c)
{
// component::array::iterator it = _components.end();
for (component::array::iterator it = _components.begin();
for (component::array::iterator it = _components.begin();
it != _components.end();
it++)
{
if (*it == c) it = _components.erase(it);
// if (*it == c) it = _components.erase(it);
}
// while ((it = std::find(_components.begin(),_components.end(),c)) != _components.end()) {
// (*it)->_node = nullptr;
// _components.erase(it);
// }
}
const node::ptr_array &node::path() const
@ -103,10 +94,11 @@ const node::ptr_array &node::path() const
void node::traversal()
{
// for (auto c : _components) c->visit(this);
}
const component::array& node::components() const
const component::array &node::components() const
{
return _components;
}

View file

@ -3,46 +3,48 @@
namespace pw {
transform::transform()
transform::transform(node &host)
: _node(host)
{
_local.set_identity();
_global.set_identity();
_global_inverse.set_identity();
}
void transform::set_local(const matrix4x4 &local)
{
// TODO need to rebuild the transforms: both -> global down and global up
_local = local;
_local = local;
update_global_from_local();
// TODO need to rebuild the transforms: both -> global down and global up
}
void transform::set_global(const matrix4x4 &global)
{
//TODO need to rebuild **_local** from parent
_global = global;
}
_global_inverse = global.inverse();
void transform::update(node& node)
{
update_local_from_global();
// TODO need to rebuild the transforms: both -> global down and global up
}
void transform::update_global_from_local()
{
// update the global transform
if (_node && _node->parent())
{
this->_global = _node->transform()._global * _local;
if (_node.is_root()) {
this->_global = _local;
} else
{
this->_global = _local;
this->_global = _node.parent()->transform().global() * _local;
}
_global_inverse = _global.inverse();
}
void transform::update_local_from_global()
{
_local = (_node.is_root()) ? _global :
_node.parent()->transform().global_inverse() * _global;
// _local = this->global()
}
}

View file

@ -22,45 +22,52 @@ void print_node_path(pw::node::ref node) {
int main(int argc,char **argv) {
using namespace pw;
using namespace pw;
node::ref n = std::make_shared<node>();
n->set_name("root");
auto n = std::make_shared<node>();
n->set_name("root-node");
// check
{
n->add_child()->set_name("node");
}
std::cout << "n name: " << n->name() << std::endl;
std::cout << "n leaf: " << n->is_leaf() << std::endl;
std::cout << "n root: " << n->is_root() << std::endl;
// add a child
auto c = std::make_shared<node>();
c->set_name("child-node");
n->add_child(c);
std::cout << "n name: " << n->name() << std::endl;
std::cout << "n leaf: " << n->is_leaf() << std::endl;
std::cout << "n root: " << n->is_root() << std::endl;
std::cout << "s name: " << n->children().front()->name() << std::endl;
std::cout << "s leaf: " << n->children()[0]->is_leaf() << std::endl;
std::cout << "s root: " << n->children()[0]->is_root() << std::endl;
std::cout << "s leaf: " << n->children().front()->is_leaf() << std::endl;
std::cout << "s root: " << n->children().front()->is_root() << std::endl;
// thats the only and most ugly way to register a component
// new component(n.get());
// thats the only and most ugly way to register a component
// new component(n.get());
n->add_component(std::make_shared<transform>());
std::cout << "n components: " << n->components().size() << std::endl;
std::cout << "n components: " << n->components().size() << std::endl;
n->transform().set_translation(5,4,3);
std::cout << "c transform g " << serialize::matrix(n->transform().global()) << std::endl;
std::cout << "c transform gi " << serialize::matrix(n->transform().global_inverse()) << std::endl;
std::cout << "c transform l " << serialize::matrix(n->transform().local()) << std::endl;
//n->add_component_<transform>();
print_node_path((n));
// auto t = n->transform();
// auto t = n->transform();
// if (t)
std::cout << n->transform().local()(0,0) << std::endl;
// else {
// std::cerr << "no transform?" << std::endl;
// }
// if (t)
// std::cout << n->transform().local()(0,0) << std::endl;
// else {
// std::cerr << "no transform?" << std::endl;
// }
return 0;
return 0;
}

View file

@ -42,7 +42,7 @@ int main(int argc,char **argv) {
node::ref root(std::make_shared<node>());
root->set_name("root");
root->add_child()->set_name("sub-1");
// root->add_child()->set_name("sub-1");
// node::ref sub_2_1 = std::make_shared<node>("sub-2-1");

View file

@ -12,6 +12,7 @@ void register_scene_function(sol::state&,sol::table &ns)
sol::constructors<node()>(),
"add_child",&node::add_child,
"children",sol::readonly_property(&node::children),
"parent",sol::readonly_property(&node::parent),
"child_count",sol::readonly_property(&node::child_count),
"create", []() -> std::shared_ptr<node> { return std::make_shared<node>(); },
"is_leaf", sol::readonly_property(&node::is_leaf),

View file

@ -30,20 +30,20 @@ public:
bool ready() const;
shader& bind(int location,float v);
shader& bind(int location,matrix4x4f const & v);
shader& bind(int location,vector4f const & v);
shader& set(int location,float v);
shader& set(int location,matrix4x4f const & v);
shader& set(int location,vector4f const & v);
int uniform_location(std::string const & name) const;
template<typename T>
shader & bind(std::string const & name, T&& value)
shader & set(std::string const & name, T&& value)
{
int location = uniform_location(name);
if (location >= 0)
return bind(location, std::forward<T>(value));
return set(location, std::forward<T>(value));
else
debug::e() << "missing uniform: "<< name;
debug::e() << "missing uniform: '" << name << "'";
return *this;
}

View file

@ -3,6 +3,8 @@
#include "pw/core/mesh.hpp"
#include "pw/core/timer.hpp"
#include "pw/core/axisangle.hpp"
#include "pw/core/serialize.hpp"
#include "pw/core/transform_tools.hpp"
#include "pw/core/debug.hpp"
#include "pw/visual/pipeline.hpp"
@ -17,6 +19,8 @@ class command {
};
class mesh_command : command {
// shader
@ -46,10 +50,13 @@ struct triangle_renderer
void setup()
{
const float z_val = -5.f;
mesh::vertex3array_t vertices = {
{ 0.0f, 0.5f, 0.0f} // 0
,{ 0.5f, -0.5f, 0.0f} // 1
,{-0.5f, -0.5f, 0.0f} // 2
{ 0.0f, 0.5f, z_val} // 0
,{ 0.5f, -0.5f, z_val} // 1
,{-0.5f, -0.5f, z_val} // 2
};
// actual indices
@ -59,71 +66,17 @@ struct triangle_renderer
amesh.set_vertices(vertices);
amesh_renderer.create(amesh);
#if 0
size_t vertex_size_bytes = amesh.vertices().size() * sizeof(mesh::vertex3array_t::value_type);
size_t vertex_stride = amesh.vertices().front().size();
debug::d() << 9 * sizeof(mesh::vertex3array_t::value_type::value_type) << " "
<< vertex_size_bytes;
// sizeof(mesh::vertex3array_t::value_type)
// 9 * sizeof(mesh::vertex3array_t::value_type::value_type)
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertex_size_bytes , amesh.vertices().data(), GL_STATIC_DRAW);
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, vertex_stride, GL_FLOAT, GL_FALSE, 0, nullptr);
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertex_shader, NULL);
glCompileShader(vs);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fragment_shader, NULL);
glCompileShader(fs);
shader_programme = glCreateProgram();
glAttachShader(shader_programme, fs);
glAttachShader(shader_programme, vs);
glLinkProgram(shader_programme);
#endif
const char* vertex_shader = R"(
#version 400
in vec3 vp;
void main() {
gl_Position = vec4(vp, 1.0);
}
)";
const char *fragment_shader = R"(
#version 400
uniform vec4 input_color = vec4(1.0, 0.0, 0.0, 1.0);
out vec4 frag_colour;
void main() {
frag_colour = input_color;
})";
const char* vertex_shader_2 = R"(
#version 400
uniform mat4 model_mat;
uniform mat4 view_mat = mat4
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
in vec3 vertex_p;
void main() {
gl_Position = model_mat * vec4(vertex_p, 1.0);
gl_Position = projection * view * model * vec4(vertex_p, 1.0);
}
)";
@ -136,7 +89,7 @@ struct triangle_renderer
})";
shader_p.set_source(vertex_shader_2,shader::vertex);
shader_p.set_source(fragment_shader,shader::fragment);
shader_p.set_source(fragment_shader_2,shader::fragment);
if (!shader_p.build())
exit(-1);
@ -148,19 +101,34 @@ struct triangle_renderer
shader_p.use();
static float v = 0.0f;
v+= 0.01f;
if (v>1.0f) v = 0.0f;
vector4f test({0.5f,1-v,v,1.0f});
auto v_col = ping_pong(static_cast<float>(timer::now()),1.0f);
vector4f col({0.5f,1-v_col,v_col,1.0f});
matrix4x4f model_mat; model_mat.set_identity();
axisangle rot(vector3::right(),v);
auto v_angle = ping_pong(static_cast<float>(timer::now()),::pw::pi<float>());
axisangle rot(vector3::forward(),v_angle);
model_mat = rot.to_matrix();
matrix4x4f view_mat = transform_tools<float>::look_at(vector3({0,0,0}),
vector3::forward(),
vector3::up());
matrix4x4f proj_mat = transform_tools<float>::perspective_projection(deg_to_rad(45.f),
1.3f,
0.2f,1000.f);
// debug::d() << serialize::matrix(proj_mat);
// highly inefficient - should be cached -
shader_p.bind("input_color",test);
shader_p.bind("model_mat",model_mat);
shader_p.set("input_color",col);
shader_p.set("model",model_mat);
shader_p.set("view",view_mat);
shader_p.set("projection",proj_mat);
amesh_renderer.draw();

View file

@ -180,12 +180,12 @@ bool shader::ready() const
return _impl->is_valid();
}
shader &shader::bind(int location, const vector4f &v)
shader &shader::set(int location, const vector4f &v)
{
_impl->bind(location,v); return *this;
}
shader &shader::bind(int location, const matrix4x4f &v)
shader &shader::set(int location, const matrix4x4f &v)
{
_impl->bind(location,v); return *this;
}