191 lines
5.1 KiB
C++
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
|