Updated ozz-animation to version 0.14.1 @35b2efd4
This commit is contained in:
+2
-5
@@ -29,9 +29,7 @@ add_library(sample_framework STATIC
|
||||
# Samples requires OpenGL package.
|
||||
if(NOT EMSCRIPTEN)
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/extern/glfw glfw)
|
||||
|
||||
target_link_libraries(sample_framework
|
||||
glfw)
|
||||
target_link_libraries(sample_framework glfw)
|
||||
endif()
|
||||
|
||||
target_link_libraries(sample_framework
|
||||
@@ -43,7 +41,6 @@ if(TARGET BUILD_DATA_SAMPLE)
|
||||
add_dependencies(sample_framework BUILD_DATA_SAMPLE)
|
||||
endif()
|
||||
|
||||
set_target_properties(sample_framework
|
||||
PROPERTIES FOLDER "samples")
|
||||
set_target_properties(sample_framework PROPERTIES FOLDER "samples")
|
||||
|
||||
add_subdirectory(tools)
|
||||
|
||||
@@ -476,6 +476,12 @@ bool Application::Gui() {
|
||||
|
||||
// Downcast to public imgui.
|
||||
ImGui* im_gui = im_gui_.get();
|
||||
|
||||
// Do floating gui.
|
||||
if (!show_help_) {
|
||||
success = OnFloatingGui(im_gui);
|
||||
}
|
||||
|
||||
// Help gui.
|
||||
{
|
||||
math::RectFloat rect(kGuiMargin, kGuiMargin,
|
||||
@@ -658,6 +664,31 @@ bool Application::FrameworkGui() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::OnInitialize() { return true; }
|
||||
|
||||
void Application::OnDestroy() {}
|
||||
|
||||
bool Application::OnUpdate(float _dt, float _time) {
|
||||
(void)_dt;
|
||||
(void)_time;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::OnGui(ImGui* _im_gui) {
|
||||
(void)_im_gui;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::OnFloatingGui(ImGui* _im_gui) {
|
||||
(void)_im_gui;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::OnDisplay(Renderer* _renderer) {
|
||||
(void)_renderer;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Application::GetCameraInitialSetup(math::Float3* _center,
|
||||
math::Float2* _angles,
|
||||
float* _distance) const {
|
||||
@@ -674,6 +705,23 @@ bool Application::GetCameraOverride(math::Float4x4* _transform) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Application::GetSceneBounds(math::Box* _bound) const { (void)_bound; }
|
||||
|
||||
math::Float2 Application::WorldToScreen(const math::Float3& _world) const {
|
||||
const math::SimdFloat4 ndc =
|
||||
(camera_->projection() * camera_->view()) *
|
||||
math::simd_float4::Load(_world.x, _world.y, _world.z, 1.f);
|
||||
|
||||
const math::SimdFloat4 resolution = math::simd_float4::FromInt(
|
||||
math::simd_int4::Load(resolution_.width, resolution_.height, 0, 0));
|
||||
const ozz::math::SimdFloat4 screen =
|
||||
resolution * ((ndc / math::SplatW(ndc)) + math::simd_float4::one()) /
|
||||
math::simd_float4::Load1(2.f);
|
||||
math::Float2 ret;
|
||||
math::Store2PtrU(screen, &ret.x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Application::ResizeCbk(int _width, int _height) {
|
||||
// Stores new resolution settings.
|
||||
application_->resolution_.width = _width;
|
||||
|
||||
+18
-6
@@ -29,6 +29,7 @@
|
||||
#define OZZ_SAMPLES_FRAMEWORK_APPLICATION_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "ozz/base/containers/string.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
@@ -78,36 +79,47 @@ class Application {
|
||||
int Run(int _argc, const char** _argv, const char* _version,
|
||||
const char* _title);
|
||||
|
||||
protected:
|
||||
// Allows application to convert from world space to screen coordinates.
|
||||
math::Float2 WorldToScreen(const math::Float3& _world) const;
|
||||
|
||||
private:
|
||||
// Provides initialization event to the inheriting application. Called while
|
||||
// the help screen is being displayed.
|
||||
// OnInitialize can return false which will in turn skip the display loop and
|
||||
// exit the application with EXIT_FAILURE. Note that OnDestroy is called in
|
||||
// any case.
|
||||
virtual bool OnInitialize() = 0;
|
||||
virtual bool OnInitialize();
|
||||
|
||||
// Provides de-initialization event to the inheriting application.
|
||||
// OnDestroy is called even if OnInitialize failed and returned an error.
|
||||
virtual void OnDestroy() = 0;
|
||||
virtual void OnDestroy();
|
||||
|
||||
// Provides update event to the inheriting application.
|
||||
// _dt is the elapsed time (in seconds) since the last update.
|
||||
// _time is application time including scaling (aka accumulated _dt).
|
||||
// OnUpdate can return false which will in turn stop the loop and exit the
|
||||
// application with EXIT_FAILURE. Note that OnDestroy is called in any case.
|
||||
virtual bool OnUpdate(float _dt, float _time) = 0;
|
||||
virtual bool OnUpdate(float _dt, float _time);
|
||||
|
||||
// Provides immediate mode gui display event to the inheriting application.
|
||||
// This function is called in between the OnDisplay and swap functions.
|
||||
// OnGui can return false which will in turn stop the loop and exit the
|
||||
// application with EXIT_FAILURE. Note that OnDestroy is called in any case.
|
||||
virtual bool OnGui(ImGui* _im_gui) = 0;
|
||||
virtual bool OnGui(ImGui* _im_gui);
|
||||
|
||||
// Provides immediate mode floating gui display event to the inheriting
|
||||
// application. Floating gui allows to render a Gui anywere one screen. User
|
||||
// must provide the form. OnFloatingGui can return false which will in turn
|
||||
// stop the loop and exit the application with EXIT_FAILURE. Note that
|
||||
// OnDestroy is called in any case.
|
||||
virtual bool OnFloatingGui(ImGui* _im_gui);
|
||||
|
||||
// Provides display event to the inheriting application.
|
||||
// This function is called in between the clear and swap functions.
|
||||
// OnDisplay can return false which will in turn stop the loop and exit the
|
||||
// application with EXIT_FAILURE. Note that OnDestroy is called in any case.
|
||||
virtual bool OnDisplay(Renderer* _renderer) = 0;
|
||||
virtual bool OnDisplay(Renderer* _renderer);
|
||||
|
||||
// Initial camera values. These will only be considered if function returns
|
||||
// true;
|
||||
@@ -125,7 +137,7 @@ class Application {
|
||||
// the camera to frame all the scene.
|
||||
// This function is never called before a first OnUpdate.
|
||||
// If _bound is set to "invalid", then camera won't be updated.
|
||||
virtual void GetSceneBounds(math::Box* _bound) const = 0;
|
||||
virtual void GetSceneBounds(math::Box* _bound) const;
|
||||
|
||||
// Implements framework internal loop function.
|
||||
bool Loop();
|
||||
|
||||
+14
-6
@@ -28,12 +28,14 @@
|
||||
#ifndef OZZ_SAMPLES_FRAMEWORK_IMGUI_H_
|
||||
#define OZZ_SAMPLES_FRAMEWORK_IMGUI_H_
|
||||
|
||||
#include <ozz/base/containers/array.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace ozz {
|
||||
namespace math {
|
||||
struct RectFloat;
|
||||
}
|
||||
} // namespace math
|
||||
namespace sample {
|
||||
|
||||
// Interface for immediate mode graphical user interface rendering.
|
||||
@@ -54,8 +56,9 @@ class ImGui {
|
||||
// A form is a root in the frame's container stack.
|
||||
// The _rect argument is relative to the parent's rect and is automatically
|
||||
// shrunk to fit inside parent's rect and to the size of its widgets.
|
||||
// Providing a non nullptr _title argument displays a title on top of the form.
|
||||
// Providing a non nullptr _open argument enables the open/close mechanism.
|
||||
// Providing a non nullptr _title argument displays a title on top of the
|
||||
// form. Providing a non nullptr _open argument enables the open/close
|
||||
// mechanism.
|
||||
class Form {
|
||||
public:
|
||||
Form(ImGui* _im_gui, const char* _title, const math::RectFloat& _rect,
|
||||
@@ -115,6 +118,11 @@ class ImGui {
|
||||
float* _value, float _pow = 1.f,
|
||||
bool _enabled = true) = 0;
|
||||
|
||||
virtual bool DoSlider2D(const char* _label, ozz::array<float, 2> _min,
|
||||
ozz::array<float, 2> _max,
|
||||
ozz::array<float, 2>* _value,
|
||||
bool _enabled = true) = 0;
|
||||
|
||||
// Adds an integer slider to the current context and returns true if _value
|
||||
// was modified.
|
||||
// _value is the in-out parameter that stores slider value. It's clamped
|
||||
@@ -172,9 +180,9 @@ class ImGui {
|
||||
// container automatically shrinks to fit the size of the widgets it contains.
|
||||
// Providing a non nullptr _title argument displays a title on top of the
|
||||
// container.
|
||||
// Providing a nullptr _rect argument means that the container will use all its
|
||||
// parent size.
|
||||
// Providing a non nullptr _open argument enables the open/close mechanism.
|
||||
// Providing a nullptr _rect argument means that the container will use all
|
||||
// its parent size. Providing a non nullptr _open argument enables the
|
||||
// open/close mechanism.
|
||||
virtual void BeginContainer(const char* _title, const math::RectFloat* _rect,
|
||||
bool* _open, bool _constrain) = 0;
|
||||
|
||||
|
||||
+144
-23
@@ -34,11 +34,11 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "immediate.h"
|
||||
#include "ozz/base/maths/math_constant.h"
|
||||
#include "ozz/base/maths/math_ex.h"
|
||||
#include "ozz/base/maths/vec_float.h"
|
||||
#include "ozz/base/memory/allocator.h"
|
||||
|
||||
#include "immediate.h"
|
||||
#include "renderer_impl.h"
|
||||
|
||||
namespace ozz {
|
||||
@@ -211,6 +211,11 @@ bool ImGuiImpl::AddWidget(float _height, math::RectFloat* _rect) {
|
||||
// Get current container.
|
||||
Container& container = containers_.back();
|
||||
|
||||
// Make it a square if height is negative.
|
||||
if (_height < 0) {
|
||||
_height = container.rect.width - kWidgetMarginX * 2.f;
|
||||
}
|
||||
|
||||
// Early out if outside of the container.
|
||||
// But don't modify current container's state.
|
||||
if (container.offset_y < kWidgetMarginY + _height) {
|
||||
@@ -740,6 +745,33 @@ void ImGuiImpl::DoGraph(const char* _label, float _min, float _max, float _mean,
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
float SliderControl(float _value, float _min, float _max, float _pow,
|
||||
int _mouse, int _mouse_max, bool _enabled, bool _active,
|
||||
float* _cursor) {
|
||||
const float pow_min = powf(_min, _pow);
|
||||
const float pow_max = powf(_max, _pow);
|
||||
const float clamped_value = ozz::math::Clamp(_min, _value, _max);
|
||||
float pow_value = powf(clamped_value, _pow);
|
||||
|
||||
// Finds cursor position and rect.
|
||||
*_cursor = floorf((_mouse_max * (pow_value - pow_min)) / (pow_max - pow_min));
|
||||
|
||||
if (_enabled) {
|
||||
if (_active) {
|
||||
_mouse = ozz::math::Clamp(0, _mouse, _mouse_max);
|
||||
pow_value = (_mouse * (pow_max - pow_min)) / _mouse_max + pow_min;
|
||||
return ozz::math::Clamp(_min, powf(pow_value, 1.f / _pow), _max);
|
||||
} else {
|
||||
// Clamping is only applied if the widget is enabled.
|
||||
return clamped_value;
|
||||
}
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
|
||||
float* _value, float _pow, bool _enabled) {
|
||||
math::RectFloat rect;
|
||||
@@ -751,7 +783,6 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
|
||||
|
||||
// Calculate mouse cursor's relative y offset.
|
||||
const float initial_value = *_value;
|
||||
const float clamped_value = ozz::math::Clamp(_min, initial_value, _max);
|
||||
|
||||
// Check for hotness.
|
||||
bool hot = false, active = false;
|
||||
@@ -795,24 +826,100 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
|
||||
}
|
||||
|
||||
// Update widget value.
|
||||
const float pow_min = powf(_min, _pow);
|
||||
const float pow_max = powf(_max, _pow);
|
||||
float pow_value = powf(clamped_value, _pow);
|
||||
float cursor;
|
||||
*_value =
|
||||
SliderControl(initial_value, _min, _max, _pow,
|
||||
inputs_.mouse_x - static_cast<int>(rect.left),
|
||||
static_cast<int>(rect.width), _enabled, active, &cursor);
|
||||
|
||||
// Renders slider's rail.
|
||||
const math::RectFloat rail_rect(rect.left, rect.bottom, rect.width,
|
||||
rect.height);
|
||||
FillRect(rail_rect, kSliderRoundRectRadius, background_color);
|
||||
StrokeRect(rail_rect, kSliderRoundRectRadius, border_color);
|
||||
|
||||
const math::RectFloat cursor_rect(
|
||||
rect.left + cursor - kWidgetCursorWidth / 2.f, rect.bottom - 1.f,
|
||||
kWidgetCursorWidth, rect.height + 2.f);
|
||||
FillRect(cursor_rect, kSliderRoundRectRadius, slider_color);
|
||||
StrokeRect(cursor_rect, kSliderRoundRectRadius, slider_border_color);
|
||||
|
||||
const math::RectFloat text_rect(
|
||||
rail_rect.left + kSliderRoundRectRadius, rail_rect.bottom,
|
||||
rail_rect.width - kSliderRoundRectRadius * 2.f, rail_rect.height);
|
||||
Print(_label, text_rect, kMiddle, text_color);
|
||||
|
||||
// Returns true if the value has changed or if it was clamped in _min / _max
|
||||
// bounds.
|
||||
return initial_value != *_value;
|
||||
}
|
||||
|
||||
bool ImGuiImpl::DoSlider2D(const char* _label, ozz::array<float, 2> _min,
|
||||
ozz::array<float, 2> _max,
|
||||
ozz::array<float, 2>* _value, bool _enabled) {
|
||||
math::RectFloat rect;
|
||||
if (!AddWidget(-1.f, &rect)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto_gen_id_++;
|
||||
|
||||
// Calculate mouse cursor's relative y offset.
|
||||
const ozz::array<float, 2> initial_value = *_value;
|
||||
|
||||
// Check for hotness.
|
||||
bool hot = false, active = false;
|
||||
if (_enabled) {
|
||||
// Includes the cursor size in the pick region.
|
||||
math::RectFloat pick_rect = rect;
|
||||
pick_rect.left -= kWidgetHeight / 2.f;
|
||||
pick_rect.width += kWidgetHeight;
|
||||
pick_rect.bottom -= kWidgetHeight / 2.f;
|
||||
pick_rect.height += kWidgetHeight;
|
||||
ButtonLogic(pick_rect, auto_gen_id_, &hot, &active);
|
||||
|
||||
// A slider is active on lmb pressed, not released. It's different to the
|
||||
// usual button behavior.
|
||||
active &= inputs_.lmb_pressed;
|
||||
}
|
||||
|
||||
// Render the scrollbar
|
||||
const GLubyte* background_color = kSliderBackgroundColor;
|
||||
const GLubyte* border_color = kWidgetBorderColor;
|
||||
const GLubyte* slider_color = kSliderCursorColor;
|
||||
const GLubyte* slider_border_color = kWidgetBorderColor;
|
||||
const GLubyte* text_color = kWidgetTextColor;
|
||||
|
||||
if (!_enabled) {
|
||||
background_color = kWidgetDisabledBackgroundColor;
|
||||
border_color = kWidgetDisabledBorderColor;
|
||||
slider_color = kSliderDisabledCursorColor;
|
||||
slider_border_color = kWidgetDisabledBorderColor;
|
||||
text_color = kWidgetDisabledTextColor;
|
||||
} else if (hot) {
|
||||
if (active) {
|
||||
int mousepos = inputs_.mouse_x - static_cast<int>(rect.left);
|
||||
if (mousepos < 0) {
|
||||
mousepos = 0;
|
||||
}
|
||||
if (mousepos > rect.width) {
|
||||
mousepos = static_cast<int>(rect.width);
|
||||
}
|
||||
pow_value = (mousepos * (pow_max - pow_min)) / rect.width + pow_min;
|
||||
*_value = ozz::math::Clamp(_min, powf(pow_value, 1.f / _pow), _max);
|
||||
// Button is both 'hot' and 'active'.
|
||||
slider_color = kWidgetActiveBackgroundColor;
|
||||
slider_border_color = kWidgetActiveBorderColor;
|
||||
} else {
|
||||
// Clamping is only applied if the widget is enabled.
|
||||
*_value = clamped_value;
|
||||
// Button is merely 'hot'.
|
||||
slider_color = kSliderCursorHotColor;
|
||||
slider_border_color = kWidgetHotBorderColor;
|
||||
}
|
||||
} else {
|
||||
// button is not hot, but it may be active. Use default colors.
|
||||
}
|
||||
|
||||
// Update widget value.
|
||||
ozz::array<float, 2> cursor;
|
||||
const int mouse[2] = {inputs_.mouse_x - static_cast<int>(rect.left),
|
||||
inputs_.mouse_y - static_cast<int>(rect.bottom)};
|
||||
const int mouse_max[2] = {static_cast<int>(rect.width),
|
||||
static_cast<int>(rect.height)};
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
_value->at(i) =
|
||||
SliderControl(initial_value[i], _min[i], _max[i], 1.f, mouse[i],
|
||||
mouse_max[i], _enabled, active, &cursor[i]);
|
||||
}
|
||||
|
||||
// Renders slider's rail.
|
||||
@@ -822,14 +929,24 @@ bool ImGuiImpl::DoSlider(const char* _label, float _min, float _max,
|
||||
StrokeRect(rail_rect, kSliderRoundRectRadius, border_color);
|
||||
|
||||
// Finds cursor position and rect.
|
||||
const float cursor =
|
||||
floorf((rect.width * (pow_value - pow_min)) / (pow_max - pow_min));
|
||||
const math::RectFloat cursor_rect(
|
||||
rect.left + cursor - kWidgetCursorWidth / 2.f, rect.bottom - 1.f,
|
||||
kWidgetCursorWidth, rect.height + 2.f);
|
||||
rect.left + cursor[0] - kWidgetHeight / 2.f,
|
||||
rect.bottom + cursor[1] - kWidgetHeight / 2.f, kWidgetHeight,
|
||||
kWidgetHeight);
|
||||
|
||||
// Cursor cross
|
||||
const math::RectFloat cross_hrect(rect.left, rect.bottom + cursor[1],
|
||||
rect.width, 1);
|
||||
StrokeRect(cross_hrect, 0.f, slider_color);
|
||||
const math::RectFloat cross_vrect(rect.left + cursor[0], rect.bottom, 1,
|
||||
rect.height);
|
||||
StrokeRect(cross_vrect, 0.f, slider_color);
|
||||
|
||||
// Draw slider
|
||||
FillRect(cursor_rect, kSliderRoundRectRadius, slider_color);
|
||||
StrokeRect(cursor_rect, kSliderRoundRectRadius, slider_border_color);
|
||||
|
||||
// Text
|
||||
const math::RectFloat text_rect(
|
||||
rail_rect.left + kSliderRoundRectRadius, rail_rect.bottom,
|
||||
rail_rect.width - kSliderRoundRectRadius * 2.f, rail_rect.height);
|
||||
@@ -1361,7 +1478,9 @@ float ImGuiImpl::Print(const char* _text, const math::RectFloat& _rect,
|
||||
ly = _rect.bottom + (line_count - 1) * (font_.glyph_height + interlign);
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GL(BindTexture(GL_TEXTURE_2D, glyph_texture_));
|
||||
@@ -1385,7 +1504,9 @@ float ImGuiImpl::Print(const char* _text, const math::RectFloat& _rect,
|
||||
lx = _rect.right() - (line_char_count * font_.glyph_width);
|
||||
break;
|
||||
}
|
||||
default: { break; }
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Loops through all characters of the current line, and renders them using
|
||||
|
||||
@@ -36,10 +36,8 @@
|
||||
// See imgui.h for details about function specifications.
|
||||
|
||||
#include "framework/imgui.h"
|
||||
|
||||
#include "ozz/base/containers/vector.h"
|
||||
#include "ozz/base/maths/rect.h"
|
||||
|
||||
#include "renderer_impl.h"
|
||||
|
||||
namespace ozz {
|
||||
@@ -90,6 +88,10 @@ class ImGuiImpl : public ImGui {
|
||||
virtual bool DoSlider(const char* _label, float _min, float _max,
|
||||
float* _value, float _pow, bool _enabled);
|
||||
|
||||
virtual bool DoSlider2D(const char* _label, ozz::array<float, 2> _min,
|
||||
ozz::array<float, 2> _max,
|
||||
ozz::array<float, 2>* _value, bool _enabled);
|
||||
|
||||
virtual bool DoSlider(const char* _label, int _min, int _max, int* _value,
|
||||
float _pow, bool _enabled);
|
||||
|
||||
|
||||
+214
-91
@@ -132,6 +132,12 @@ bool RendererImpl::Initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate instanced ambient rendering shader.
|
||||
points_shader = PointsShader::Build();
|
||||
if (!points_shader) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -239,7 +245,7 @@ bool RendererImpl::DrawGrid(int _cell_count, float _cell_size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Computes the model space bind pose and renders it.
|
||||
// Computes the model space rest pose and renders it.
|
||||
bool RendererImpl::DrawSkeleton(const ozz::animation::Skeleton& _skeleton,
|
||||
const ozz::math::Float4x4& _transform,
|
||||
bool _draw_joints) {
|
||||
@@ -253,9 +259,9 @@ bool RendererImpl::DrawSkeleton(const ozz::animation::Skeleton& _skeleton,
|
||||
// Reallocate matrix array if necessary.
|
||||
prealloc_models_.resize(num_joints);
|
||||
|
||||
// Compute model space bind pose.
|
||||
// Compute model space rest pose.
|
||||
ozz::animation::LocalToModelJob job;
|
||||
job.input = _skeleton.joint_bind_poses();
|
||||
job.input = _skeleton.joint_rest_poses();
|
||||
job.output = make_span(prealloc_models_);
|
||||
job.skeleton = &_skeleton;
|
||||
if (!job.Run()) {
|
||||
@@ -460,10 +466,7 @@ int DrawPosture_FillUniforms(const ozz::animation::Skeleton& _skeleton,
|
||||
// Copy parent joint's raw matrix, to render a bone between the parent
|
||||
// and current matrix.
|
||||
float* uniform = _uniforms + instances * 16;
|
||||
math::StorePtr(parent.cols[0], uniform + 0);
|
||||
math::StorePtr(parent.cols[1], uniform + 4);
|
||||
math::StorePtr(parent.cols[2], uniform + 8);
|
||||
math::StorePtr(parent.cols[3], uniform + 12);
|
||||
std::memcpy(uniform, parent.cols, 16 * sizeof(float));
|
||||
|
||||
// Set bone direction (bone_dir). The shader expects to find it at index
|
||||
// [3,7,11] of the matrix.
|
||||
@@ -483,11 +486,7 @@ int DrawPosture_FillUniforms(const ozz::animation::Skeleton& _skeleton,
|
||||
// Only the joint is rendered for leaves, the bone model isn't.
|
||||
if (IsLeaf(_skeleton, i)) {
|
||||
// Copy current joint's raw matrix.
|
||||
uniform = _uniforms + instances * 16;
|
||||
math::StorePtr(current.cols[0], uniform + 0);
|
||||
math::StorePtr(current.cols[1], uniform + 4);
|
||||
math::StorePtr(current.cols[2], uniform + 8);
|
||||
math::StorePtr(current.cols[3], uniform + 12);
|
||||
std::memcpy(uniform, current.cols, 16 * sizeof(float));
|
||||
|
||||
// Re-use bone_dir to fix the size of the leaf (same as previous bone).
|
||||
// The shader expects to find it at index [3,7,11] of the matrix.
|
||||
@@ -621,6 +620,84 @@ bool RendererImpl::DrawPosture(const ozz::animation::Skeleton& _skeleton,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RendererImpl::DrawPoints(const ozz::span<const float>& _positions,
|
||||
const ozz::span<const float>& _sizes,
|
||||
const ozz::span<const Color>& _colors,
|
||||
const ozz::math::Float4x4& _transform,
|
||||
bool _round, bool _screen_space) {
|
||||
// Early out if no instance to render.
|
||||
if (_positions.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sizes and colors must be of size 1 or equal to _positions' size.
|
||||
if (_sizes.size() != 1 && _sizes.size() != _positions.size() / 3) {
|
||||
return false;
|
||||
}
|
||||
if (_colors.size() != 1 && _colors.size() != _positions.size() / 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const GLsizei positions_size = static_cast<GLsizei>(_positions.size_bytes());
|
||||
const GLsizei colors_size =
|
||||
static_cast<GLsizei>(_colors.size() == 1 ? 0 : _colors.size_bytes());
|
||||
const GLsizei sizes_size =
|
||||
static_cast<GLsizei>(_sizes.size() == 1 ? 0 : _sizes.size_bytes());
|
||||
const GLsizei buffer_size = positions_size + colors_size + sizes_size;
|
||||
const GLsizei positions_offset = 0;
|
||||
const GLsizei colors_offset = positions_offset + positions_size;
|
||||
const GLsizei sizes_offset = colors_offset + colors_size;
|
||||
|
||||
// Reallocate vertex buffer.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_));
|
||||
GL(BufferData(GL_ARRAY_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW));
|
||||
|
||||
GL(BufferSubData(GL_ARRAY_BUFFER, positions_offset, positions_size,
|
||||
_positions.data()));
|
||||
GL(BufferSubData(GL_ARRAY_BUFFER, colors_offset, colors_size,
|
||||
_colors.data()));
|
||||
GL(BufferSubData(GL_ARRAY_BUFFER, sizes_offset, sizes_size, _sizes.data()));
|
||||
|
||||
// Square or round sprites. Beware msaa makes sprites round if GL_POINT_SPRITE
|
||||
// isn't enabled
|
||||
if (_round) {
|
||||
GL(Enable(GL_POINT_SMOOTH));
|
||||
GL(Disable(GL_POINT_SPRITE));
|
||||
} else {
|
||||
GL(Disable(GL_POINT_SMOOTH));
|
||||
GL(Enable(GL_POINT_SPRITE));
|
||||
}
|
||||
|
||||
// Size is managed in vertex shader side.
|
||||
GL(Enable(GL_PROGRAM_POINT_SIZE));
|
||||
|
||||
const PointsShader::GenericAttrib attrib =
|
||||
points_shader->Bind(_transform, camera()->view_proj(), 12,
|
||||
positions_offset, colors_size ? 4 : 0, colors_offset,
|
||||
sizes_size ? 4 : 0, sizes_offset, _screen_space);
|
||||
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
|
||||
// Apply remaining general attributes
|
||||
if (_colors.size() <= 1) {
|
||||
const Color color = _colors.empty() ? kWhite : _colors[0];
|
||||
GL(VertexAttrib4f(attrib.color, color.r / 255.f, color.g / 255.f,
|
||||
color.b / 255.f, color.a / 255.f));
|
||||
}
|
||||
if (_sizes.size() <= 1) {
|
||||
const float size = _sizes.empty() ? 1.f : _sizes[0];
|
||||
GL(VertexAttrib1f(attrib.size, size));
|
||||
}
|
||||
|
||||
// Draws the mesh.
|
||||
GL(DrawArrays(GL_POINTS, 0, static_cast<GLsizei>(_positions.size() / 3)));
|
||||
|
||||
// Unbinds.
|
||||
points_shader->Unbind();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RendererImpl::DrawBoxIm(const ozz::math::Box& _box,
|
||||
const ozz::math::Float4x4& _transform,
|
||||
const Color _colors[2]) {
|
||||
@@ -1218,49 +1295,70 @@ bool RendererImpl::DrawMesh(const Mesh& _mesh,
|
||||
vertex_offset += part_vertex_count;
|
||||
}
|
||||
|
||||
// Binds shader with this array buffer, depending on rendering options.
|
||||
Shader* shader = nullptr;
|
||||
if (_options.texture) {
|
||||
ambient_textured_shader->Bind(_transform, camera()->view_proj(),
|
||||
positions_stride, positions_offset,
|
||||
normals_stride, normals_offset, colors_stride,
|
||||
colors_offset, uvs_stride, uvs_offset);
|
||||
shader = ambient_textured_shader.get();
|
||||
if (_options.triangles) {
|
||||
// Binds shader with this array buffer, depending on rendering options.
|
||||
Shader* shader = nullptr;
|
||||
if (_options.texture) {
|
||||
ambient_textured_shader->Bind(
|
||||
_transform, camera()->view_proj(), positions_stride, positions_offset,
|
||||
normals_stride, normals_offset, colors_stride, colors_offset,
|
||||
uvs_stride, uvs_offset);
|
||||
shader = ambient_textured_shader.get();
|
||||
|
||||
// Binds default texture
|
||||
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
|
||||
} else {
|
||||
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
|
||||
positions_offset, normals_stride, normals_offset,
|
||||
colors_stride, colors_offset);
|
||||
shader = ambient_shader.get();
|
||||
// Binds default texture
|
||||
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
|
||||
} else {
|
||||
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
|
||||
positions_offset, normals_stride, normals_offset,
|
||||
colors_stride, colors_offset);
|
||||
shader = ambient_shader.get();
|
||||
}
|
||||
|
||||
// Maps the index dynamic buffer and update it.
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
|
||||
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
|
||||
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
|
||||
array_begin(indices), GL_STREAM_DRAW));
|
||||
|
||||
// Draws the mesh.
|
||||
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
|
||||
"Expects 2 bytes indices.");
|
||||
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
|
||||
GL_UNSIGNED_SHORT, 0));
|
||||
|
||||
// Unbinds.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
GL(BindTexture(GL_TEXTURE_2D, 0));
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
shader->Unbind();
|
||||
}
|
||||
|
||||
// Maps the index dynamic buffer and update it.
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
|
||||
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
|
||||
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
|
||||
array_begin(indices), GL_STREAM_DRAW));
|
||||
|
||||
// Draws the mesh.
|
||||
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
|
||||
"Expects 2 bytes indices.");
|
||||
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
|
||||
GL_UNSIGNED_SHORT, 0));
|
||||
|
||||
// Unbinds.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
GL(BindTexture(GL_TEXTURE_2D, 0));
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
shader->Unbind();
|
||||
|
||||
if (_options.wireframe) {
|
||||
#ifndef EMSCRIPTEN
|
||||
GL(PolygonMode(GL_FRONT_AND_BACK, GL_FILL));
|
||||
#endif // EMSCRIPTEN
|
||||
}
|
||||
|
||||
// Renders debug vertices.
|
||||
if (_options.vertices) {
|
||||
for (size_t i = 0; i < _mesh.parts.size(); ++i) {
|
||||
const Mesh::Part& part = _mesh.parts[i];
|
||||
ozz::sample::Color color = ozz::sample::kWhite;
|
||||
span<const ozz::sample::Color> colors;
|
||||
if (_options.colors && part.colors.size() == part.positions.size() / 3) {
|
||||
colors = {
|
||||
reinterpret_cast<const ozz::sample::Color*>(part.colors.data()),
|
||||
part.positions.size() / 3};
|
||||
} else {
|
||||
colors = {&color, 1};
|
||||
}
|
||||
const float size = 2.f;
|
||||
DrawPoints({part.positions.data(), part.positions.size()}, {&size, 1},
|
||||
{&color, 1}, _transform, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Renders debug normals.
|
||||
if (_options.normals) {
|
||||
for (size_t i = 0; i < _mesh.parts.size(); ++i) {
|
||||
@@ -1313,7 +1411,7 @@ bool RendererImpl::DrawSkinnedMesh(
|
||||
const Mesh& _mesh, const span<math::Float4x4> _skinning_matrices,
|
||||
const ozz::math::Float4x4& _transform, const Options& _options) {
|
||||
// Forward to DrawMesh function is skinning is disabled.
|
||||
if (_options.skip_skinning) {
|
||||
if (_options.skip_skinning || !_mesh.skinned()) {
|
||||
return DrawMesh(_mesh, _transform, _options);
|
||||
}
|
||||
|
||||
@@ -1327,13 +1425,16 @@ bool RendererImpl::DrawSkinnedMesh(
|
||||
|
||||
// Positions and normals are interleaved to improve caching while executing
|
||||
// skinning job.
|
||||
|
||||
const GLsizei positions_offset = 0;
|
||||
const GLsizei normals_offset = sizeof(float) * 3;
|
||||
const GLsizei tangents_offset = sizeof(float) * 6;
|
||||
const GLsizei positions_stride = sizeof(float) * 9;
|
||||
const GLsizei normals_stride = positions_stride;
|
||||
const GLsizei tangents_stride = positions_stride;
|
||||
const GLsizei skinned_data_size = vertex_count * positions_stride;
|
||||
const GLsizei positions_stride = sizeof(float) * 3;
|
||||
const GLsizei normals_offset = vertex_count * positions_stride;
|
||||
const GLsizei normals_stride = sizeof(float) * 3;
|
||||
const GLsizei tangents_offset =
|
||||
normals_offset + vertex_count * normals_stride;
|
||||
const GLsizei tangents_stride = sizeof(float) * 3;
|
||||
const GLsizei skinned_data_size =
|
||||
tangents_offset + vertex_count * tangents_stride;
|
||||
|
||||
// Colors and uvs are contiguous. They aren't transformed, so they can be
|
||||
// directly copied from source mesh which is non-interleaved as-well.
|
||||
@@ -1542,54 +1643,76 @@ bool RendererImpl::DrawSkinnedMesh(
|
||||
processed_vertex_count += part_vertex_count;
|
||||
}
|
||||
|
||||
// Updates dynamic vertex buffer with skinned data.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_));
|
||||
GL(BufferData(GL_ARRAY_BUFFER, vbo_size, nullptr, GL_STREAM_DRAW));
|
||||
GL(BufferSubData(GL_ARRAY_BUFFER, 0, vbo_size, vbo_map));
|
||||
if (_options.triangles) {
|
||||
// Updates dynamic vertex buffer with skinned data.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, dynamic_array_bo_));
|
||||
GL(BufferData(GL_ARRAY_BUFFER, vbo_size, nullptr, GL_STREAM_DRAW));
|
||||
GL(BufferSubData(GL_ARRAY_BUFFER, 0, vbo_size, vbo_map));
|
||||
|
||||
// Binds shader with this array buffer, depending on rendering options.
|
||||
Shader* shader = nullptr;
|
||||
if (_options.texture) {
|
||||
ambient_textured_shader->Bind(_transform, camera()->view_proj(),
|
||||
positions_stride, positions_offset,
|
||||
normals_stride, normals_offset, colors_stride,
|
||||
colors_offset, uvs_stride, uvs_offset);
|
||||
shader = ambient_textured_shader.get();
|
||||
// Binds shader with this array buffer, depending on rendering options.
|
||||
Shader* shader = nullptr;
|
||||
if (_options.texture) {
|
||||
ambient_textured_shader->Bind(
|
||||
_transform, camera()->view_proj(), positions_stride, positions_offset,
|
||||
normals_stride, normals_offset, colors_stride, colors_offset,
|
||||
uvs_stride, uvs_offset);
|
||||
shader = ambient_textured_shader.get();
|
||||
|
||||
// Binds default texture
|
||||
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
|
||||
} else {
|
||||
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
|
||||
positions_offset, normals_stride, normals_offset,
|
||||
colors_stride, colors_offset);
|
||||
shader = ambient_shader.get();
|
||||
// Binds default texture
|
||||
GL(BindTexture(GL_TEXTURE_2D, checkered_texture_));
|
||||
} else {
|
||||
ambient_shader->Bind(_transform, camera()->view_proj(), positions_stride,
|
||||
positions_offset, normals_stride, normals_offset,
|
||||
colors_stride, colors_offset);
|
||||
shader = ambient_shader.get();
|
||||
}
|
||||
|
||||
// Maps the index dynamic buffer and update it.
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
|
||||
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
|
||||
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
|
||||
array_begin(indices), GL_STREAM_DRAW));
|
||||
|
||||
// Draws the mesh.
|
||||
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
|
||||
"Expects 2 bytes indices.");
|
||||
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
|
||||
GL_UNSIGNED_SHORT, 0));
|
||||
|
||||
// Unbinds.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
GL(BindTexture(GL_TEXTURE_2D, 0));
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
shader->Unbind();
|
||||
}
|
||||
|
||||
// Maps the index dynamic buffer and update it.
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, dynamic_index_bo_));
|
||||
const Mesh::TriangleIndices& indices = _mesh.triangle_indices;
|
||||
GL(BufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
indices.size() * sizeof(Mesh::TriangleIndices::value_type),
|
||||
array_begin(indices), GL_STREAM_DRAW));
|
||||
|
||||
// Draws the mesh.
|
||||
static_assert(sizeof(Mesh::TriangleIndices::value_type) == 2,
|
||||
"Expects 2 bytes indices.");
|
||||
GL(DrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()),
|
||||
GL_UNSIGNED_SHORT, 0));
|
||||
|
||||
// Unbinds.
|
||||
GL(BindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
GL(BindTexture(GL_TEXTURE_2D, 0));
|
||||
GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
shader->Unbind();
|
||||
|
||||
if (_options.wireframe) {
|
||||
#ifndef EMSCRIPTEN
|
||||
GL(PolygonMode(GL_FRONT_AND_BACK, GL_FILL));
|
||||
#endif // EMSCRIPTEN
|
||||
}
|
||||
|
||||
// Renders debug vertices.
|
||||
if (_options.vertices) {
|
||||
ozz::sample::Color color = ozz::sample::kWhite;
|
||||
span<const ozz::sample::Color> colors;
|
||||
if (_options.colors) {
|
||||
colors = {reinterpret_cast<const ozz::sample::Color*>(
|
||||
ozz::PointerStride(vbo_map, colors_offset)),
|
||||
static_cast<size_t>(vertex_count)};
|
||||
} else {
|
||||
colors = {&color, 1};
|
||||
}
|
||||
|
||||
const span<const float> vertices{
|
||||
reinterpret_cast<const float*>(
|
||||
ozz::PointerStride(vbo_map, positions_offset)),
|
||||
static_cast<size_t>(vertex_count * 3)};
|
||||
const float size = 2.f;
|
||||
DrawPoints(vertices, {&size, 1}, colors, _transform, true, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
|
||||
// Include features as extentions
|
||||
#include "GL/glext.h"
|
||||
|
||||
#include "framework/renderer.h"
|
||||
#include "ozz/base/containers/vector.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
@@ -91,6 +90,7 @@ namespace sample {
|
||||
namespace internal {
|
||||
class Camera;
|
||||
class Shader;
|
||||
class PointsShader;
|
||||
class SkeletonShader;
|
||||
class AmbientShader;
|
||||
class AmbientTexturedShader;
|
||||
@@ -119,6 +119,12 @@ class RendererImpl : public Renderer {
|
||||
const ozz::math::Float4x4& _transform,
|
||||
bool _draw_joints);
|
||||
|
||||
virtual bool DrawPoints(
|
||||
const ozz::span<const float>& _positions,
|
||||
const ozz::span<const float>& _sizes,
|
||||
const ozz::span<const Color>& _colors,
|
||||
const ozz::math::Float4x4& _transform, bool _round, bool _screen_space);
|
||||
|
||||
virtual bool DrawBoxIm(const ozz::math::Box& _box,
|
||||
const ozz::math::Float4x4& _transform,
|
||||
const Color _colors[2]);
|
||||
@@ -241,6 +247,7 @@ class RendererImpl : public Renderer {
|
||||
ozz::unique_ptr<AmbientShader> ambient_shader;
|
||||
ozz::unique_ptr<AmbientTexturedShader> ambient_textured_shader;
|
||||
ozz::unique_ptr<AmbientShaderInstanced> ambient_shader_instanced;
|
||||
ozz::unique_ptr<PointsShader> points_shader;
|
||||
|
||||
// Checkered texture
|
||||
unsigned int checkered_texture_;
|
||||
|
||||
@@ -326,6 +326,91 @@ void ImmediatePTCShader::Bind(const math::Float4x4& _model,
|
||||
GL(Uniform1i(texture, 0));
|
||||
}
|
||||
|
||||
ozz::unique_ptr<PointsShader> PointsShader::Build() {
|
||||
bool success = true;
|
||||
|
||||
const char* kSimplePointsVS =
|
||||
"uniform mat4 u_mvp;\n"
|
||||
"attribute vec3 a_position;\n"
|
||||
"attribute vec4 a_color;\n"
|
||||
"attribute float a_size;\n"
|
||||
"attribute float a_screen_space;\n"
|
||||
"varying vec4 v_vertex_color;\n"
|
||||
"void main() {\n"
|
||||
" vec4 vertex = vec4(a_position.xyz, 1.);\n"
|
||||
" gl_Position = u_mvp * vertex;\n"
|
||||
" gl_PointSize = a_screen_space == 0. ? a_size / gl_Position.w : a_size;\n"
|
||||
" v_vertex_color = a_color;\n"
|
||||
"}\n";
|
||||
const char* kSimplePointsPS =
|
||||
"varying vec4 v_vertex_color;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = v_vertex_color;\n"
|
||||
"}\n";
|
||||
|
||||
const char* vs[] = {kPlatformSpecivicVSHeader, kSimplePointsVS};
|
||||
const char* fs[] = {kPlatformSpecivicFSHeader, kSimplePointsPS};
|
||||
|
||||
ozz::unique_ptr<PointsShader> shader = make_unique<PointsShader>();
|
||||
success &=
|
||||
shader->BuildFromSource(OZZ_ARRAY_SIZE(vs), vs, OZZ_ARRAY_SIZE(fs), fs);
|
||||
|
||||
// Binds default attributes
|
||||
success &= shader->FindAttrib("a_position");
|
||||
success &= shader->FindAttrib("a_color");
|
||||
success &= shader->FindAttrib("a_size");
|
||||
success &= shader->FindAttrib("a_screen_space");
|
||||
|
||||
// Binds default uniforms
|
||||
success &= shader->BindUniform("u_mvp");
|
||||
|
||||
if (!success) {
|
||||
shader.reset();
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
PointsShader::GenericAttrib PointsShader::Bind(
|
||||
const math::Float4x4& _model, const math::Float4x4& _view_proj,
|
||||
GLsizei _pos_stride, GLsizei _pos_offset, GLsizei _color_stride,
|
||||
GLsizei _color_offset, GLsizei _size_stride, GLsizei _size_offset,
|
||||
bool _screen_space) {
|
||||
GL(UseProgram(program()));
|
||||
|
||||
const GLint position_attrib = attrib(0);
|
||||
GL(EnableVertexAttribArray(position_attrib));
|
||||
GL(VertexAttribPointer(position_attrib, 3, GL_FLOAT, GL_FALSE, _pos_stride,
|
||||
GL_PTR_OFFSET(_pos_offset)));
|
||||
|
||||
const GLint color_attrib = attrib(1);
|
||||
if (_color_stride) {
|
||||
GL(EnableVertexAttribArray(color_attrib));
|
||||
GL(VertexAttribPointer(color_attrib, 4, GL_UNSIGNED_BYTE, GL_TRUE,
|
||||
_color_stride, GL_PTR_OFFSET(_color_offset)));
|
||||
}
|
||||
const GLint size_attrib = attrib(2);
|
||||
if (_size_stride) {
|
||||
GL(EnableVertexAttribArray(size_attrib));
|
||||
GL(VertexAttribPointer(size_attrib, 1, GL_FLOAT, GL_TRUE, _size_stride,
|
||||
GL_PTR_OFFSET(_size_offset)));
|
||||
}
|
||||
const GLint screen_space_attrib = attrib(3);
|
||||
GL(VertexAttrib1f(screen_space_attrib, 1.f * _screen_space));
|
||||
|
||||
// Binds mvp uniform
|
||||
const GLint mvp_uniform = uniform(0);
|
||||
const ozz::math::Float4x4 mvp = _view_proj * _model;
|
||||
float values[16];
|
||||
math::StorePtrU(mvp.cols[0], values + 0);
|
||||
math::StorePtrU(mvp.cols[1], values + 4);
|
||||
math::StorePtrU(mvp.cols[2], values + 8);
|
||||
math::StorePtrU(mvp.cols[3], values + 12);
|
||||
GL(UniformMatrix4fv(mvp_uniform, 1, false, values));
|
||||
|
||||
return {_color_stride ? -1 : color_attrib, _size_stride ? -1 : size_attrib};
|
||||
}
|
||||
|
||||
namespace {
|
||||
const char* kPassUv =
|
||||
"attribute vec2 a_uv;\n"
|
||||
|
||||
@@ -126,6 +126,29 @@ class ImmediatePTCShader : public Shader {
|
||||
GLsizei _tex_offset, GLsizei _color_stride, GLsizei _color_offset);
|
||||
};
|
||||
|
||||
class PointsShader : public Shader {
|
||||
public:
|
||||
PointsShader() {}
|
||||
virtual ~PointsShader() {}
|
||||
|
||||
// Constructs the shader.
|
||||
// Returns nullptr if shader compilation failed or a valid Shader pointer on
|
||||
// success. The shader must then be deleted using default allocator Delete
|
||||
// function.
|
||||
static ozz::unique_ptr<PointsShader> Build();
|
||||
|
||||
// Binds the shader.
|
||||
struct GenericAttrib {
|
||||
GLint color;
|
||||
GLint size;
|
||||
};
|
||||
GenericAttrib Bind(const math::Float4x4& _model,
|
||||
const math::Float4x4& _view_proj, GLsizei _pos_stride,
|
||||
GLsizei _pos_offset, GLsizei _color_stride,
|
||||
GLsizei _color_offset, GLsizei _size_stride,
|
||||
GLsizei _size_offset, bool _screen_space);
|
||||
};
|
||||
|
||||
class SkeletonShader : public Shader {
|
||||
public:
|
||||
SkeletonShader() {}
|
||||
|
||||
+1
-6
@@ -69,12 +69,7 @@ struct Mesh {
|
||||
|
||||
// Test if the mesh has skinning informations.
|
||||
bool skinned() const {
|
||||
for (size_t i = 0; i < parts.size(); ++i) {
|
||||
if (parts[i].influences_count() != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return !inverse_bind_poses.empty();
|
||||
}
|
||||
|
||||
// Returns the number of joints used to skin the mesh.
|
||||
|
||||
+24
-6
@@ -79,7 +79,7 @@ class Renderer {
|
||||
// has a size of _cell_size.
|
||||
virtual bool DrawGrid(int _cell_count, float _cell_size) = 0;
|
||||
|
||||
// Renders a skeleton in its bind pose posture.
|
||||
// Renders a skeleton in its rest pose posture.
|
||||
virtual bool DrawSkeleton(const animation::Skeleton& _skeleton,
|
||||
const ozz::math::Float4x4& _transform,
|
||||
bool _draw_joints = true) = 0;
|
||||
@@ -93,6 +93,17 @@ class Renderer {
|
||||
const ozz::math::Float4x4& _transform,
|
||||
bool _draw_joints = true) = 0;
|
||||
|
||||
// Renders points.
|
||||
// _sizes and _colors must be either of ize 1 or equal to _positions' size.
|
||||
// If _screen_space is true, then points size is fixed in screen-space,
|
||||
// otherwise it changes with screen depth.
|
||||
virtual bool DrawPoints(
|
||||
const ozz::span<const float>& _positions,
|
||||
const ozz::span<const float>& _sizes,
|
||||
const ozz::span<const Color>& _colors,
|
||||
const ozz::math::Float4x4& _transform, bool _round = true,
|
||||
bool _screen_space = false) = 0;
|
||||
|
||||
// Renders a box at a specified location.
|
||||
// The 2 slots of _colors array respectively defines color of the filled
|
||||
// faces and color of the box outlines.
|
||||
@@ -116,16 +127,20 @@ class Renderer {
|
||||
Color _color) = 0;
|
||||
|
||||
struct Options {
|
||||
bool triangles; // Show triangles mesh.
|
||||
bool texture; // Show texture (default checkered texture).
|
||||
bool vertices; // Show vertices as points.
|
||||
bool normals; // Show normals.
|
||||
bool tangents; // Show tangents.
|
||||
bool binormals; // Show binormals, computed from the normal and tangent.
|
||||
bool colors; // Show vertex colors.
|
||||
bool wireframe; // Show vertex colors.
|
||||
bool wireframe; // Show vertex colors.
|
||||
bool skip_skinning; // Show texture (default checkered texture).
|
||||
|
||||
Options()
|
||||
: texture(false),
|
||||
: triangles(true),
|
||||
texture(false),
|
||||
vertices(false),
|
||||
normals(false),
|
||||
tangents(false),
|
||||
binormals(false),
|
||||
@@ -133,9 +148,12 @@ class Renderer {
|
||||
wireframe(false),
|
||||
skip_skinning(false) {}
|
||||
|
||||
Options(bool _texture, bool _normals, bool _tangents, bool _binormals,
|
||||
bool _colors, bool _wireframe, bool _skip_skinning)
|
||||
: texture(_texture),
|
||||
Options(bool _triangles, bool _texture, bool _vertices, bool _normals,
|
||||
bool _tangents, bool _binormals, bool _colors, bool _wireframe,
|
||||
bool _skip_skinning)
|
||||
: triangles(_triangles),
|
||||
texture(_texture),
|
||||
vertices(_vertices),
|
||||
normals(_normals),
|
||||
tangents(_tangents),
|
||||
binormals(_binormals),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Adds fbx2mesh utility target.
|
||||
if(ozz_build_fbx)
|
||||
|
||||
# share meshes with thte sample framework
|
||||
# share meshes with the sample framework
|
||||
add_executable(sample_fbx2mesh
|
||||
fbx2mesh.cc
|
||||
${PROJECT_SOURCE_DIR}/samples/framework/mesh.cc
|
||||
@@ -9,6 +9,7 @@ if(ozz_build_fbx)
|
||||
target_link_libraries(sample_fbx2mesh
|
||||
ozz_animation_fbx
|
||||
ozz_options)
|
||||
target_copy_shared_libraries(sample_fbx2mesh)
|
||||
set_target_properties(sample_fbx2mesh
|
||||
PROPERTIES FOLDER "samples/tools")
|
||||
|
||||
|
||||
+19
-20
@@ -25,12 +25,12 @@
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "framework/mesh.h"
|
||||
|
||||
#include "ozz/animation/offline/fbx/fbx.h"
|
||||
|
||||
#include "ozz/animation/runtime/skeleton.h"
|
||||
|
||||
#include "ozz/base/containers/map.h"
|
||||
#include "ozz/base/containers/vector.h"
|
||||
#include "ozz/base/io/archive.h"
|
||||
@@ -39,14 +39,8 @@
|
||||
#include "ozz/base/maths/math_ex.h"
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
#include "ozz/base/memory/allocator.h"
|
||||
|
||||
#include "ozz/options/options.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "fbxsdk/utils/fbxgeometryconverter.h"
|
||||
|
||||
// Declares command line options.
|
||||
OZZ_OPTIONS_DECLARE_STRING(file, "Specifies input file.", "", true)
|
||||
OZZ_OPTIONS_DECLARE_STRING(skeleton,
|
||||
@@ -504,19 +498,18 @@ bool BuildSkin(FbxMesh* _fbx_mesh,
|
||||
const int* ctrl_point_indices = cluster->GetControlPointIndices();
|
||||
const double* ctrl_point_weights = cluster->GetControlPointWeights();
|
||||
for (int cpi = 0; cpi < ctrl_point_index_count; ++cpi) {
|
||||
const SkinMapping mapping = {joint,
|
||||
static_cast<float>(ctrl_point_weights[cpi])};
|
||||
if (mapping.weight <= 0.f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int ctrl_point = ctrl_point_indices[cpi];
|
||||
assert(ctrl_point < static_cast<int>(_remap.size()));
|
||||
// It happens that weight is 0. In this case give the vertex a very small
|
||||
// weight so normalization succeeds.
|
||||
const float ctrl_point_weight =
|
||||
static_cast<float>(ctrl_point_weights[cpi]);
|
||||
const SkinMapping mapping = {
|
||||
joint, ctrl_point_weight == 0.f ? 1e-9f : ctrl_point_weight};
|
||||
|
||||
// remap.size() can be 0, skinned control point might not be used by any
|
||||
// polygon of the mesh. Sometimes, the mesh can have less points than at
|
||||
// the time of the skinning because a smooth operator was active when
|
||||
// skinning but has been deactivated during export.
|
||||
const int ctrl_point = ctrl_point_indices[cpi];
|
||||
const ControlPointRemap& remap = _remap[ctrl_point];
|
||||
for (size_t v = 0; v < remap.size(); ++v) {
|
||||
vertex_skin_mappings[remap[v]].push_back(mapping);
|
||||
@@ -560,6 +553,11 @@ bool BuildSkin(FbxMesh* _fbx_mesh,
|
||||
|
||||
// Stores joint's indices and weights.
|
||||
size_t influence_count = inv.size();
|
||||
if (influence_count == 0) {
|
||||
vertex_skin_mappings[i].push_back({0,1.f});
|
||||
influence_count = 1;
|
||||
}
|
||||
|
||||
if (influence_count > 0) {
|
||||
size_t j = 0;
|
||||
for (; j < influence_count; ++j) {
|
||||
@@ -579,11 +577,12 @@ bool BuildSkin(FbxMesh* _fbx_mesh,
|
||||
}
|
||||
|
||||
if (vertex_isnt_influenced) {
|
||||
ozz::log::Err() << "At least one vertex isn't influenced by any joints."
|
||||
<< std::endl;
|
||||
ozz::log::LogV() << "At least one vertex isn't influenced by any joints. "
|
||||
"It's been reassigned to root joint."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
return !vertex_isnt_influenced;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Limits the number of joints influencing a vertex.
|
||||
|
||||
+11
-17
@@ -30,28 +30,22 @@
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
#include "ozz/base/maths/box.h"
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
#include "ozz/base/maths/simd_quaternion.h"
|
||||
#include "ozz/base/maths/soa_transform.h"
|
||||
|
||||
#include "ozz/base/memory/allocator.h"
|
||||
|
||||
#include "framework/imgui.h"
|
||||
#include "framework/mesh.h"
|
||||
#include "ozz/animation/offline/raw_skeleton.h"
|
||||
#include "ozz/animation/runtime/animation.h"
|
||||
#include "ozz/animation/runtime/local_to_model_job.h"
|
||||
#include "ozz/animation/runtime/skeleton.h"
|
||||
#include "ozz/animation/runtime/track.h"
|
||||
|
||||
#include "ozz/animation/offline/raw_skeleton.h"
|
||||
|
||||
#include "ozz/geometry/runtime/skinning_job.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
#include "ozz/base/log.h"
|
||||
|
||||
#include "framework/imgui.h"
|
||||
#include "framework/mesh.h"
|
||||
#include "ozz/base/maths/box.h"
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
#include "ozz/base/maths/simd_quaternion.h"
|
||||
#include "ozz/base/maths/soa_transform.h"
|
||||
#include "ozz/base/memory/allocator.h"
|
||||
#include "ozz/geometry/runtime/skinning_job.h"
|
||||
|
||||
namespace ozz {
|
||||
namespace sample {
|
||||
@@ -224,9 +218,9 @@ void ComputeSkeletonBounds(const animation::Skeleton& _skeleton,
|
||||
// Allocate matrix array, out of memory is handled by the LocalToModelJob.
|
||||
ozz::vector<ozz::math::Float4x4> models(num_joints);
|
||||
|
||||
// Compute model space bind pose.
|
||||
// Compute model space rest pose.
|
||||
ozz::animation::LocalToModelJob job;
|
||||
job.input = _skeleton.joint_bind_poses();
|
||||
job.input = _skeleton.joint_rest_poses();
|
||||
job.output = make_span(models);
|
||||
job.skeleton = &_skeleton;
|
||||
if (job.Run()) {
|
||||
|
||||
Reference in New Issue
Block a user