Files
test/source/blender/draw/intern/draw_view.hh

147 lines
3.9 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2022 Blender Foundation. */
#pragma once
/** \file
* \ingroup draw
*
* View description and states.
*
* A `draw::View` object is required for drawing geometry using the DRW api and its internal
* culling system.
*
* One `View` object can actually contain multiple view matrices if the template parameter
* `view_len` is greater than 1. This is called multi-view rendering and the vertex shader must
* setting `drw_view_id` accordingly.
*/
#include "DRW_gpu_wrapper.hh"
#include "DRW_render.h"
#include "draw_shader_shared.h"
namespace blender::draw {
class Manager;
/* TODO: de-duplicate. */
using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>;
using VisibilityBuf = StorageArrayBuffer<uint, 4, true>;
class View {
friend Manager;
private:
/** TODO(fclem): Maybe try to reduce the minimum cost if the number of view is lower. */
UniformArrayBuffer<ViewMatrices, DRW_VIEW_MAX> data_;
UniformArrayBuffer<ViewCullingData, DRW_VIEW_MAX> culling_;
/** Frozen version of data_ used for debugging culling. */
UniformArrayBuffer<ViewMatrices, DRW_VIEW_MAX> data_freeze_;
UniformArrayBuffer<ViewCullingData, DRW_VIEW_MAX> culling_freeze_;
/** Result of the visibility computation. 1 bit or 1 or 2 word per resource ID per view. */
VisibilityBuf visibility_buf_;
const char *debug_name_;
int view_len_ = 0;
bool is_inverted_ = false;
bool do_visibility_ = true;
bool dirty_ = true;
bool frozen_ = false;
public:
View(const char *name, int view_len = 1)
: visibility_buf_(name), debug_name_(name), view_len_(view_len)
{
BLI_assert(view_len < DRW_VIEW_MAX);
}
/* For compatibility with old system. Will be removed at some point. */
View(const char *name, const DRWView *view)
: visibility_buf_(name), debug_name_(name), view_len_(1)
{
float4x4 view_mat, win_mat;
DRW_view_viewmat_get(view, view_mat.ptr(), false);
DRW_view_winmat_get(view, win_mat.ptr(), false);
this->sync(view_mat, win_mat);
}
void sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id = 0);
bool is_persp(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
return data_[view_id].winmat[3][3] == 0.0f;
}
bool is_inverted(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
UNUSED_VARS_NDEBUG(view_id);
return is_inverted_;
}
float far_clip(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
if (is_persp(view_id)) {
return -data_[view_id].winmat[3][2] / (data_[view_id].winmat[2][2] + 1.0f);
}
return -(data_[view_id].winmat[3][2] - 1.0f) / data_[view_id].winmat[2][2];
}
float near_clip(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
if (is_persp(view_id)) {
return -data_[view_id].winmat[3][2] / (data_[view_id].winmat[2][2] - 1.0f);
}
return -(data_[view_id].winmat[3][2] + 1.0f) / data_[view_id].winmat[2][2];
}
const float4x4 &viewmat(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
return data_[view_id].viewmat;
}
const float4x4 &viewinv(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
return data_[view_id].viewinv;
}
const float4x4 &winmat(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
return data_[view_id].winmat;
}
const float4x4 &wininv(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
return data_[view_id].wininv;
}
int visibility_word_per_draw() const
{
return (view_len_ == 1) ? 0 : divide_ceil_u(view_len_, 32);
}
private:
/** Called from draw manager. */
void bind();
void compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool debug_freeze);
void update_viewport_size();
void frustum_boundbox_calc(BoundBox &bbox, int view_id);
void frustum_culling_planes_calc(int view_id);
void frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bsphere, int view_id);
};
} // namespace blender::draw