Blender V4.5
gpencil_render.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8#include "BLI_math_geom.h"
9#include "BLI_math_matrix.h"
10#include "BLI_rect.h"
11
12#include "DRW_render.hh"
13
14#include "BKE_object.hh"
15
17
18#include "RE_engine.h"
19#include "RE_pipeline.h"
20#include "render_types.h"
21
22#include "IMB_imbuf_types.hh"
23
25
26namespace blender::draw::gpencil {
27
28/* Remap depth from views-pace to [0..1] to be able to use it with as GPU depth buffer. */
29static void remap_depth(const View &view, MutableSpan<float> pix_z)
30{
31 if (view.is_persp()) {
32 const float4x4 &winmat = view.winmat();
33 for (auto &pix : pix_z) {
34 pix = (-winmat[3][2] / -pix) - winmat[2][2];
35 pix = clamp_f(pix * 0.5f + 0.5f, 0.0f, 1.0f);
36 }
37 }
38 else {
39 /* Keep in mind, near and far distance are negatives. */
40 const float near = view.near_clip();
41 const float far = view.far_clip();
42 const float range_inv = 1.0f / fabsf(far - near);
43 for (auto &pix : pix_z) {
44 pix = (pix + near) * range_inv;
45 pix = clamp_f(pix, 0.0f, 1.0f);
46 }
47 }
48}
49
50static void render_set_view(RenderEngine *engine,
51 const Depsgraph *depsgraph,
52 const float2 aa_offset = float2{0.0f})
53{
55
56 float4x4 winmat, viewinv;
57 RE_GetCameraWindow(engine->re, camera, winmat.ptr());
58 RE_GetCameraModelMatrix(engine->re, camera, viewinv.ptr());
59
60 window_translate_m4(winmat.ptr(), winmat.ptr(), UNPACK2(aa_offset));
61
62 View::default_set(math::invert(viewinv), winmat);
63}
64
65static void render_init_buffers(const DRWContext *draw_ctx,
66 Instance &inst,
67 RenderEngine *engine,
68 RenderLayer *render_layer,
69 const rcti *rect,
70 const bool use_separated_pass)
71{
72 const int2 size = int2(draw_ctx->viewport_size_get());
74
75 /* Create depth texture & color texture from render result. */
76 const char *viewname = RE_GetActiveRenderView(engine->re);
77 RenderPass *rpass_z_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
78 RenderPass *rpass_col_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
79
80 float *pix_z = (rpass_z_src) ? rpass_z_src->ibuf->float_buffer.data : nullptr;
81 float *pix_col = (rpass_col_src) ? rpass_col_src->ibuf->float_buffer.data : nullptr;
82
83 if (!pix_z || !pix_col) {
85 "Warning: To render Grease Pencil, enable Combined and Z passes.");
86 }
87
88 if (pix_z) {
89 /* Depth need to be remapped to [0..1] range. */
90 pix_z = static_cast<float *>(MEM_dupallocN(pix_z));
91 remap_depth(view, {pix_z, rpass_z_src->rectx * rpass_z_src->recty});
92 }
93
94 const bool do_region = (!use_separated_pass) &&
95 (!(rect->xmin == 0 && rect->ymin == 0 && rect->xmax == size.x &&
96 rect->ymax == size.y));
97 const bool do_clear_z = !pix_z || do_region;
98 const bool do_clear_col = use_separated_pass || (!pix_col) || do_region;
99
100 /* FIXME(fclem): we have a precision loss in the depth buffer because of this re-upload.
101 * Find where it comes from! */
102 /* In multi view render the textures can be reused. */
103 if (inst.render_depth_tx.is_valid() && !do_clear_z) {
105 }
106 else {
110 GPU_DEPTH_COMPONENT24, int2(size), usage, do_region ? nullptr : pix_z);
111 }
112 if (inst.render_color_tx.is_valid() && !do_clear_col) {
114 }
115 else {
118 inst.render_color_tx.ensure_2d(GPU_RGBA16F, int2(size), usage, do_region ? nullptr : pix_col);
119 }
120
123
124 if (do_clear_z || do_clear_col) {
125 /* To avoid unpredictable result, clear buffers that have not be initialized. */
127 if (do_clear_col) {
128 const float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
129 GPU_framebuffer_clear_color(inst.render_fb, clear_col);
130 }
131 if (do_clear_z) {
133 }
134 }
135
136 if (do_region) {
137 int x = rect->xmin;
138 int y = rect->ymin;
139 int w = BLI_rcti_size_x(rect);
140 int h = BLI_rcti_size_y(rect);
141 if (pix_col) {
142 GPU_texture_update_sub(inst.render_color_tx, GPU_DATA_FLOAT, pix_col, x, y, 0, w, h, 0);
143 }
144 if (pix_z) {
145 GPU_texture_update_sub(inst.render_depth_tx, GPU_DATA_FLOAT, pix_z, x, y, 0, w, h, 0);
146 }
147 }
148
149 MEM_SAFE_FREE(pix_z);
150}
151
152static void render_result_z(const DRWContext *draw_ctx,
153 RenderLayer *rl,
154 const char *viewname,
155 Instance &instance,
156 const rcti *rect)
157{
158 ViewLayer *view_layer = draw_ctx->view_layer;
159 if ((view_layer->passflag & SCE_PASS_Z) == 0) {
160 return;
161 }
162 RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
163 if (rp == nullptr) {
164 return;
165 }
166
167 float *ro_buffer_data = rp->ibuf->float_buffer.data;
168
170 rect->xmin,
171 rect->ymin,
172 BLI_rcti_size_x(rect),
173 BLI_rcti_size_y(rect),
175 ro_buffer_data);
176
177 float4x4 winmat = View::default_get().winmat();
178
179 int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
180
181 /* Convert GPU depth [0..1] to view Z [near..far] */
182 if (View::default_get().is_persp()) {
183 for (int i = 0; i < pix_num; i++) {
184 if (ro_buffer_data[i] == 1.0f) {
185 ro_buffer_data[i] = 1e10f; /* Background */
186 }
187 else {
188 ro_buffer_data[i] = ro_buffer_data[i] * 2.0f - 1.0f;
189 ro_buffer_data[i] = winmat[3][2] / (ro_buffer_data[i] + winmat[2][2]);
190 }
191 }
192 }
193 else {
194 /* Keep in mind, near and far distance are negatives. */
195 float near = View::default_get().near_clip();
196 float far = View::default_get().far_clip();
197 float range = fabsf(far - near);
198
199 for (int i = 0; i < pix_num; i++) {
200 if (ro_buffer_data[i] == 1.0f) {
201 ro_buffer_data[i] = 1e10f; /* Background */
202 }
203 else {
204 ro_buffer_data[i] = ro_buffer_data[i] * range - near;
205 }
206 }
207 }
208}
209
211 const char *viewname,
212 Instance &instance,
213 const rcti *rect)
214{
216
217 Framebuffer read_fb;
219 GPU_framebuffer_bind(read_fb);
221 rect->xmin,
222 rect->ymin,
223 BLI_rcti_size_x(rect),
224 BLI_rcti_size_y(rect),
225 4,
226 0,
228 rp->ibuf->float_buffer.data);
229}
230
231static void render_result_separated_pass(float *data, Instance &instance, const rcti *rect)
232{
233 Framebuffer read_fb;
235 GPU_framebuffer_bind(read_fb);
237 rect->xmin,
238 rect->ymin,
239 BLI_rcti_size_x(rect),
240 BLI_rcti_size_y(rect),
241 4,
242 0,
244 data);
245}
246
247static void render_frame(RenderEngine *engine,
248 Depsgraph *depsgraph,
249 const DRWContext *draw_ctx,
250 RenderLayer *render_layer,
251 const rcti rect,
252 gpencil::Instance &inst,
253 Manager &manager,
254 const bool separated_pass)
255{
256 const float aa_radius = clamp_f(draw_ctx->scene->r.gauss, 0.0f, 100.0f);
257 const int sample_count = draw_ctx->scene->grease_pencil_settings.aa_samples;
258 for (const int sample_i : IndexRange(sample_count)) {
259 const float2 aa_sample = Instance::antialiasing_sample_get(sample_i, sample_count) * aa_radius;
260 const float2 aa_offset = 2.0f * aa_sample / float2(inst.render_color_tx.size());
261 render_set_view(engine, depsgraph, aa_offset);
262 render_init_buffers(draw_ctx, inst, engine, render_layer, &rect, separated_pass);
263
264 /* Render the gpencil object and merge the result to the underlying render. */
265 inst.draw(manager);
266
267 /* Weight of this render SSAA sample. The sum of previous samples is weighted by `1 - weight`.
268 * This diminishes after each new sample as we want all samples to be equally weighted inside
269 * the final result (inside the combined buffer). This weighting scheme allows to always store
270 * the resolved result making it ready for in-progress display or read-back. */
271 const float weight = 1.0f / (1.0f + sample_i);
272 inst.antialiasing_accumulate(manager, weight);
273 }
274}
275
276void Engine::render_to_image(RenderEngine *engine, RenderLayer *render_layer, const rcti rect)
277{
278 const char *viewname = RE_GetActiveRenderView(engine->re);
279
280 const DRWContext *draw_ctx = DRW_context_get();
281 Depsgraph *depsgraph = draw_ctx->depsgraph;
282
284 Render *re = engine->re;
286 re->result, RE_PASSNAME_GREASE_PENCIL, 4, "RGBA", render_layer->name, viewname, true);
287 }
288
290
291 Manager &manager = *DRW_manager_get();
292
293 render_set_view(engine, depsgraph);
294 render_init_buffers(draw_ctx, inst, engine, render_layer, &rect, false);
295 inst.init();
296
298
299 manager.begin_sync();
300
301 /* Loop over all objects and create draw structure. */
302 inst.begin_sync();
303 DRW_render_object_iter(engine, depsgraph, [&](ObjectRef &ob_ref, RenderEngine *, Depsgraph *) {
304 if (!ELEM(ob_ref.object->type, OB_GREASE_PENCIL, OB_LAMP)) {
305 return;
306 }
308 return;
309 }
310 inst.object_sync(ob_ref, manager);
311 });
312 inst.end_sync();
313
314 manager.end_sync();
315
316 render_frame(engine, depsgraph, draw_ctx, render_layer, rect, inst, manager, false);
317 render_result_combined(render_layer, viewname, inst, &rect);
318
319 float *pass_data = RE_RenderLayerGetPass(render_layer, RE_PASSNAME_GREASE_PENCIL, viewname);
320 if (pass_data) {
321 render_frame(engine, depsgraph, draw_ctx, render_layer, rect, inst, manager, true);
322 render_result_separated_pass(pass_data, inst, &rect);
323 }
324
325 /* Transfer depth in the last step, because if we need to render separate pass, we need original
326 * untouched depth buffer. */
327 render_result_z(draw_ctx, render_layer, viewname, inst, &rect);
328}
329
330} // namespace blender::draw::gpencil
General operations, lookup, etc. for blender objects.
@ OB_VISIBLE_SELF
MINLINE float clamp_f(float value, float min, float max)
void window_translate_m4(float winmat[4][4], float perspmat[4][4], float x, float y)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
#define UNPACK2(a)
#define ELEM(...)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ GREASE_PENCIL_AS_SEPARATE_PASS
@ OB_GREASE_PENCIL
@ OB_LAMP
#define RE_PASSNAME_COMBINED
#define RE_PASSNAME_Z
#define RE_PASSNAME_GREASE_PENCIL
@ SCE_PASS_Z
static AppView * view
void GPU_framebuffer_read_color(GPUFrameBuffer *fb, int x, int y, int width, int height, int channels, int slot, eGPUDataFormat data_format, void *r_data)
#define GPU_ATTACHMENT_TEXTURE(_texture)
void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int width, int height, eGPUDataFormat data_format, void *r_data)
#define GPU_ATTACHMENT_NONE
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
void GPU_framebuffer_clear_color(GPUFrameBuffer *fb, const float clear_col[4])
void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
@ GPU_DATA_FLOAT
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_HOST_READ
@ GPU_TEXTURE_USAGE_ATTACHMENT
void GPU_texture_update_sub(GPUTexture *texture, eGPUDataFormat data_format, const void *pixels, int offset_x, int offset_y, int offset_z, int width, int height, int depth)
@ GPU_RGBA16F
@ GPU_DEPTH_COMPONENT24
void GPU_texture_update(GPUTexture *texture, eGPUDataFormat data_format, const void *data)
BMesh const char void * data
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
void ensure(GPUAttachment depth=GPU_ATTACHMENT_NONE, GPUAttachment color1=GPU_ATTACHMENT_NONE, GPUAttachment color2=GPU_ATTACHMENT_NONE, GPUAttachment color3=GPU_ATTACHMENT_NONE, GPUAttachment color4=GPU_ATTACHMENT_NONE, GPUAttachment color5=GPU_ATTACHMENT_NONE, GPUAttachment color6=GPU_ATTACHMENT_NONE, GPUAttachment color7=GPU_ATTACHMENT_NONE, GPUAttachment color8=GPU_ATTACHMENT_NONE)
void begin_sync(Object *object_active=nullptr)
bool ensure_2d(eGPUTextureFormat format, int2 extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
int3 size(int miplvl=0) const
static void default_set(const float4x4 &view_mat, const float4x4 &win_mat)
Definition draw_view.cc:322
const float4x4 & winmat(int view_id=0) const
Definition draw_view.hh:148
float near_clip(int view_id=0) const
Definition draw_view.hh:115
static View & default_get()
Definition draw_view.cc:317
float far_clip(int view_id=0) const
Definition draw_view.hh:106
#define fabsf(x)
const DRWContext * DRW_context_get()
void DRW_render_object_iter(RenderEngine *engine, Depsgraph *depsgraph, std::function< void(blender::draw::ObjectRef &, RenderEngine *, Depsgraph *)> callback)
int DRW_object_visibility_in_active_context(const Object *ob)
blender::draw::Manager * DRW_manager_get()
#define MEM_SAFE_FREE(v)
void RE_GetCameraModelMatrix(const Render *re, const Object *camera, float r_modelmat[4][4])
void RE_GetCameraWindow(Render *re, const Object *camera, float r_winmat[4][4])
Object * RE_GetCamera(Render *re)
void RE_engine_set_error_message(RenderEngine *engine, const char *msg)
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
static void render_set_view(RenderEngine *engine, const Depsgraph *depsgraph, const float2 aa_offset=float2{0.0f})
static void render_result_separated_pass(float *data, Instance &instance, const rcti *rect)
static void render_result_combined(RenderLayer *rl, const char *viewname, Instance &instance, const rcti *rect)
static void render_frame(RenderEngine *engine, Depsgraph *depsgraph, const DRWContext *draw_ctx, RenderLayer *render_layer, const rcti rect, gpencil::Instance &inst, Manager &manager, const bool separated_pass)
static void remap_depth(const View &view, MutableSpan< float > pix_z)
static void render_init_buffers(const DRWContext *draw_ctx, Instance &inst, RenderEngine *engine, RenderLayer *render_layer, const rcti *rect, const bool use_separated_pass)
static void render_result_z(const DRWContext *draw_ctx, RenderLayer *rl, const char *viewname, Instance &instance, const rcti *rect)
CartesianBasis invert(const CartesianBasis &basis)
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
void RE_create_render_pass(RenderResult *rr, const char *name, int channels, const char *chan_id, const char *layername, const char *viewname, const bool allocate)
RenderPass * RE_pass_find_by_name(RenderLayer *rl, const char *name, const char *viewname)
const char * RE_GetActiveRenderView(Render *re)
float * RE_RenderLayerGetPass(RenderLayer *rl, const char *name, const char *viewname)
RenderResult * result
Depsgraph * depsgraph
blender::float2 viewport_size_get() const
Scene * scene
ViewLayer * view_layer
ImBufFloatBuffer float_buffer
struct Render * re
Definition RE_engine.h:138
char name[RE_MAXNAME]
Definition RE_pipeline.h:81
struct ImBuf * ibuf
Definition RE_pipeline.h:60
struct SceneGpencil grease_pencil_settings
struct RenderData r
int grease_pencil_flags
const c_style_mat & ptr() const
static void render_to_image(RenderEngine *engine, RenderLayer *render_layer, const rcti rect)
void draw(Manager &manager) final
static float2 antialiasing_sample_get(int sample_index, int sample_count)
void object_sync(ObjectRef &ob_ref, Manager &manager) final
void antialiasing_accumulate(Manager &manager, float alpha)
int ymin
int ymax
int xmin
int xmax
i
Definition text_draw.cc:230