Browse Source

Add tangent and bitangent calculation to painting system

master
C. J. Howard 3 years ago
parent
commit
44bafa5e8e
6 changed files with 142 additions and 37 deletions
  1. +120
    -31
      src/game/systems/painting-system.cpp
  2. +5
    -1
      src/game/systems/painting-system.hpp
  3. +1
    -1
      src/geometry/mesh-accelerator.cpp
  4. +8
    -0
      src/geometry/mesh-functions.cpp
  5. +4
    -0
      src/geometry/mesh-functions.hpp
  6. +4
    -4
      src/renderer/passes/material-pass.cpp

+ 120
- 31
src/game/systems/painting-system.cpp View File

@ -35,6 +35,7 @@
#include "rasterizer/vertex-buffer.hpp"
#include "rasterizer/vertex-attribute-type.hpp"
#include "renderer/vertex-attributes.hpp"
#include "geometry/mesh-functions.hpp"
#include <limits>
using namespace ecs;
@ -56,9 +57,9 @@ painting_system::painting_system(entt::registry& registry, ::event_dispatcher* e
min_stroke_length_squared = min_stroke_length * min_stroke_length;
max_stroke_segments = 4096;
current_stroke_segment = 0;
std::size_t vertex_size = 4;
std::size_t vertex_stride = sizeof(float) * vertex_size;
std::size_t vertex_count = max_stroke_segments * 6;
vertex_size = 15;
vertex_stride = sizeof(float) * vertex_size;
vertex_count = max_stroke_segments * 6;
// Create stroke model
stroke_model = new model();
@ -69,6 +70,10 @@ painting_system::painting_system(entt::registry& registry, ::event_dispatcher* e
stroke_vbo = stroke_model->get_vertex_buffer();
stroke_vbo->repurpose(sizeof(float) * vertex_size * vertex_count, nullptr, buffer_usage::dynamic_draw);
stroke_model->get_vertex_array()->bind_attribute(VERTEX_POSITION_LOCATION, *stroke_vbo, 4, vertex_attribute_type::float_32, vertex_stride, 0);
stroke_model->get_vertex_array()->bind_attribute(VERTEX_NORMAL_LOCATION, *stroke_vbo, 3, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * 4);
stroke_model->get_vertex_array()->bind_attribute(VERTEX_TEXCOORD_LOCATION, *stroke_vbo, 2, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * 7);
stroke_model->get_vertex_array()->bind_attribute(VERTEX_TANGENT_LOCATION, *stroke_vbo, 3, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * 9);
stroke_model->get_vertex_array()->bind_attribute(VERTEX_BITANGENT_LOCATION, *stroke_vbo, 3, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * 12);
// Create stroke model instance
stroke_model_instance = new model_instance();
@ -100,21 +105,25 @@ void painting_system::update(double t, double dt)
auto cast_result = cast_ray(tool.cursor);
if (cast_result.has_value())
{
float3 p2 =
stroke_end = cast_result.value();
stroke_end = std::get<0>(cast_result.value());
float3 surface_normal = std::get<1>(cast_result.value());
float3 segment_difference = stroke_end - stroke_start;
float segment_length_squared = math::dot(segment_difference, segment_difference);
if (segment_length_squared >= min_stroke_length_squared)
{
float segment_length = std::sqrt(segment_length_squared);
float3 segment_forward = segment_difference / segment_length;
float3 segment_right = math::normalize(math::cross(segment_forward, float3{0, 1, 0}));
float3 segment_up = math::cross(segment_right, segment_forward);
float3 segment_right = math::normalize(math::cross(segment_forward, surface_normal));
float3 segment_up = math::cross(segment_right, segment_forward);
float angle = std::acos(math::dot(segment_forward, float3{0, 0, -1}));
float3 cross = math::cross(segment_forward, float3{0, 0, -1});
if (math::dot(surface_normal, cross) < 0.0f)
angle = -angle;
float3 segment_center = (stroke_start + stroke_end) * 0.5f;
math::quaternion<float> tangent_rotation = math::normalize(math::angle_axis(-angle, surface_normal));
float3 p1 = stroke_start;
float3 p2 = stroke_end;
@ -145,30 +154,99 @@ void painting_system::update(double t, double dt)
}
}
float4 segment_vertices[12];
float w = static_cast<float>(t);
const float3 positions[] =
{
a, b, c,
c, b, d,
c, d, e,
e, d, f
};
const float w = static_cast<float>(t);
float2 texcoords[] =
{
{0, 0}, {1, 0}, {0, 1},
{0, 1}, {1, 0}, {1, 1},
{0, 0}, {1, 0}, {0, 1},
{0, 1}, {1, 0}, {1, 1},
};
float3 tangent_positions[] =
{
{0, 0, 0}, {1, 0, 0}, {0, 0, 1},
{0, 0, 1}, {1, 0, 0}, {1, 0, 1},
{0, 0, 0}, {1, 0, 0}, {0, 0, 1},
{0, 0, 1}, {1, 0, 0}, {1, 0, 1}
};
/// @TODO: smooth normals in middle of segment
float3 tangents[12];
float3 bitangents[12];
for (int i = 0; i < 4; ++i)
{
const float3& a = tangent_positions[i * 3];
const float3& b = tangent_positions[i * 3 + 1];
const float3& c = tangent_positions[i * 3 + 2];
const float2& uva = texcoords[i * 3];
const float2& uvb = texcoords[i * 3 + 1];
const float2& uvc = texcoords[i * 3 + 2];
float3 ba = b - a;
float3 ca = c - a;
float2 uvba = uvb - uva;
float2 uvca = uvc - uva;
float f = 1.0f / (uvba.x * uvca.y - uvca.x * uvba.y);
float3 tangent = math::normalize((ba * uvca.y - ca * uvba.y) * f);
float3 bitangent = math::normalize((ba * -uvca.x + ca * uvba.x) * f);
// Rotate tangent and bitangent according to segment rotation
tangent = math::normalize(tangent_rotation * tangent);
bitangent = math::normalize(tangent_rotation * bitangent);
tangents[i * 3] = tangent;
tangents[i * 3 + 1] = tangent;
tangents[i * 3 + 2] = tangent;
bitangents[i * 3] = bitangent;
bitangents[i * 3 + 1] = bitangent;
bitangents[i * 3 + 2] = bitangent;
}
segment_vertices[0] = {a.x, a.y, a.z, w};
segment_vertices[1] = {b.x, b.y, b.z, w};
segment_vertices[2] = {c.x, c.y, c.z, w};
segment_vertices[3] = {c.x, c.y, c.z, w};
segment_vertices[4] = {b.x, b.y, b.z, w};
segment_vertices[5] = {d.x, d.y, d.z, w};
segment_vertices[6] = {c.x, c.y, c.z, w};
segment_vertices[7] = {d.x, d.y, d.z, w};
segment_vertices[8] = {e.x, e.y, e.z, w};
segment_vertices[9] = {e.x, e.y, e.z, w};
segment_vertices[10] = {d.x, d.y, d.z, w};
segment_vertices[11] = {f.x, f.y, f.z, w};
float vertex_data[15 * 12];
float* v = &vertex_data[0];
for (int i = 0; i < 12; ++i)
{
*(v++) = positions[i].x;
*(v++) = positions[i].y;
*(v++) = positions[i].z;
*(v++) = w;
*(v++) = surface_normal.x;
*(v++) = surface_normal.y;
*(v++) = surface_normal.z;
*(v++) = texcoords[i].x;
*(v++) = texcoords[i].y;
*(v++) = tangents[i].x;
*(v++) = tangents[i].y;
*(v++) = tangents[i].z;
*(v++) = bitangents[i].x;
*(v++) = bitangents[i].y;
*(v++) = bitangents[i].z;
}
std::size_t segment_size = sizeof(float) * 4 * 6;
std::size_t segment_size = sizeof(float) * vertex_size * 6;
if (mitered)
{
stroke_vbo->update((current_stroke_segment - 1) * segment_size, segment_size * 2, &segment_vertices[0][0]);
stroke_vbo->update((current_stroke_segment - 1) * segment_size, segment_size * 2, &vertex_data[0]);
}
else
{
stroke_vbo->update(current_stroke_segment * segment_size, segment_size, &segment_vertices[6][0]);
stroke_vbo->update(current_stroke_segment * segment_size, segment_size, &vertex_data[vertex_size * 6]);
}
++current_stroke_segment;
@ -211,7 +289,7 @@ void painting_system::handle_event(const tool_pressed_event& event)
{
brush_entity = event.entity;
painting = true;
stroke_start = cast_result.value();
stroke_start = std::get<0>(cast_result.value());
stroke_end = stroke_start;
p0 = stroke_start;
p0a = p0;
@ -229,7 +307,7 @@ void painting_system::handle_event(const tool_released_event& event)
if (cast_result.has_value())
{
stroke_end = cast_result.value();
stroke_end = std::get<0>(cast_result.value());
}
brush_entity = entt::null;
@ -237,9 +315,13 @@ void painting_system::handle_event(const tool_released_event& event)
}
}
std::optional<float3> painting_system::cast_ray(const float3& position) const
std::optional<std::tuple<float3, float3>> painting_system::cast_ray(const float3& position) const
{
std::optional<float3> result;
std::optional<std::tuple<float3, float3>> result;
float3 intersection;
float3 surface_normal;
mesh::face* face = nullptr;
ray<float> untransformed_ray = {position + float3{0.0f, 10000.0f, 0.0f}, {0, -1, 0}};
float min_distance = std::numeric_limits<float>::infinity();
@ -267,10 +349,17 @@ std::optional painting_system::cast_ray(const float3& position) const
if (mesh_result->t < min_distance)
{
min_distance = mesh_result->t;
result = untransformed_ray.extrapolate(min_distance);
intersection = untransformed_ray.extrapolate(min_distance);
face = mesh_result->face;
}
}
});
if (face != nullptr)
{
surface_normal = calculate_face_normal(*face);
result = std::make_tuple(intersection, surface_normal);
}
return result;
}

+ 5
- 1
src/game/systems/painting-system.hpp View File

@ -51,7 +51,7 @@ private:
virtual void handle_event(const tool_pressed_event& event);
virtual void handle_event(const tool_released_event& event);
std::optional<float3> cast_ray(const float3& position) const;
std::optional<std::tuple<float3, float3>> cast_ray(const float3& position) const;
event_dispatcher* event_dispatcher;
resource_manager* resource_manager;
@ -74,6 +74,10 @@ private:
float3 p0a;
float3 p0b;
std::size_t vertex_size;
std::size_t vertex_stride;
std::size_t vertex_count;
model* stroke_model;
model_group* stroke_model_group;
vertex_buffer* stroke_vbo;

+ 1
- 1
src/geometry/mesh-accelerator.cpp View File

@ -170,7 +170,7 @@ octree32::node_type mesh_accelerator::find_node(const float3& point) const
static_cast<std::uint32_t>(transformed_point.y),
static_cast<std::uint32_t>(transformed_point.z));
/// Return max depth node at the determined location
// Return max depth node at the determined location
return octree32::node(octree32::max_depth, location);
}

+ 8
- 0
src/geometry/mesh-functions.cpp View File

@ -87,6 +87,14 @@ void calculate_face_normals(float* normals, const mesh& mesh)
}
}
float3 calculate_face_normal(const mesh::face& face)
{
const float3& a = reinterpret_cast<const float3&>(face.edge->vertex->position);
const float3& b = reinterpret_cast<const float3&>(face.edge->next->vertex->position);
const float3& c = reinterpret_cast<const float3&>(face.edge->previous->vertex->position);
return math::normalize(math::cross(b - a, c - a));
}
aabb<float> calculate_bounds(const mesh& mesh)
{
float3 bounds_min;

+ 4
- 0
src/geometry/mesh-functions.hpp View File

@ -44,8 +44,12 @@ void create_triangle_mesh(mesh& mesh, const std::vector& vertices, const
*/
void calculate_face_normals(float* normals, const mesh& mesh);
float3 calculate_face_normal(const mesh::face& face);
void calculate_vertex_normals(float* normals, const mesh& mesh);
/**
* Calculates the AABB bounds of a mesh.
*/

+ 4
- 4
src/renderer/passes/material-pass.cpp View File

@ -353,10 +353,10 @@ void material_pass::render(render_context* context) const
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 1, ~0);
//glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
//glStencilMask(~0);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0);
glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
glStencilMask(~0);
//glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
//glStencilMask(0);
}
else
{

Loading…
Cancel
Save