tornavis/source/blender/draw/intern/draw_view.hh

191 lines
5.1 KiB
C++

/* SPDX-FileCopyrightText: 2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#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;
protected:
/** 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;
bool procedural_ = false;
public:
View(const char *name, int view_len = 1, bool procedural = false)
: visibility_buf_(name), debug_name_(name), view_len_(view_len), procedural_(procedural)
{
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)
{
this->sync(view);
}
void sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id = 0);
/* For compatibility with old system. Will be removed at some point. */
void sync(const DRWView *view);
/** Disable a range in the multi-view array. Disabled view will not produce any instances. */
void disable(IndexRange range);
/** Enable or disable every visibility test (frustum culling, HiZ culling). */
void visibility_test(bool enable)
{
do_visibility_ = enable;
}
/**
* Update culling data using a compute shader.
* This is to be used if the matrices were updated externally
* on the GPU (not using the `sync()` method).
**/
void compute_procedural_bounds();
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 float3 &location(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
return data_[view_id].viewinv.location();
}
const float3 &forward(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
return data_[view_id].viewinv.z_axis();
}
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;
}
/* Compute and return the perspective matrix. */
const float4x4 persmat(int view_id = 0) const
{
BLI_assert(view_id < view_len_);
return data_[view_id].winmat * data_[view_id].viewmat;
}
int visibility_word_per_draw() const
{
return (view_len_ == 1) ? 0 : divide_ceil_u(view_len_, 32);
}
UniformArrayBuffer<ViewMatrices, DRW_VIEW_MAX> &matrices_ubo_get()
{
return data_;
}
protected:
/** Called from draw manager. */
void bind();
virtual void compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool debug_freeze);
virtual VisibilityBuf &get_visibility_buffer();
void update_viewport_size();
/* WARNING: These 3 functions must be called in order */
void frustum_boundbox_calc(int view_id);
void frustum_culling_planes_calc(int view_id);
void frustum_culling_sphere_calc(int view_id);
};
} // namespace blender::draw