This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/draw/engines/gpencil/gpencil_render.c

270 lines
9.2 KiB
C

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2017, Blender Foundation.
*/
/** \file
* \ingroup draw
*/
#include "BLI_rect.h"
#include "DRW_render.h"
#include "BKE_object.h"
#include "DNA_gpencil_types.h"
#include "DEG_depsgraph_query.h"
#include "RE_pipeline.h"
#include "gpencil_engine.h"
/* init render data */
void GPENCIL_render_init(GPENCIL_Data *vedata,
RenderEngine *engine,
struct RenderLayer *render_layer,
const Depsgraph *depsgraph,
const rcti *rect)
{
GPENCIL_FramebufferList *fbl = vedata->fbl;
GPENCIL_TextureList *txl = vedata->txl;
Scene *scene = DEG_get_evaluated_scene(depsgraph);
const float *viewport_size = DRW_viewport_size_get();
const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
/* Set the pers & view matrix. */
float winmat[4][4], viewmat[4][4], viewinv[4][4];
struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
RE_GetCameraWindow(engine->re, camera, winmat);
RE_GetCameraModelMatrix(engine->re, camera, viewinv);
invert_m4_m4(viewmat, viewinv);
DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL);
DRW_view_default_set(view);
DRW_view_set_active(view);
/* Create depth texture & color texture from render result. */
const char *viewname = RE_GetActiveRenderView(engine->re);
RenderPass *rpass_z_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
RenderPass *rpass_col_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
float *pix_z = (rpass_z_src) ? rpass_z_src->rect : NULL;
float *pix_col = (rpass_col_src) ? rpass_col_src->rect : NULL;
if (!pix_z || !pix_col) {
RE_engine_set_error_message(engine,
"Warning: To render grease pencil, enable Combined and Z passes.");
}
if (pix_z) {
/* Depth need to be remapped to [0..1] range. */
pix_z = MEM_dupallocN(pix_z);
int pix_ct = rpass_z_src->rectx * rpass_z_src->recty;
if (DRW_view_is_persp_get(view)) {
for (int i = 0; i < pix_ct; i++) {
pix_z[i] = (-winmat[3][2] / -pix_z[i]) - winmat[2][2];
pix_z[i] = clamp_f(pix_z[i] * 0.5f + 0.5f, 0.0f, 1.0f);
}
}
else {
/* Keep in mind, near and far distance are negatives. */
float near = DRW_view_near_distance_get(view);
float far = DRW_view_far_distance_get(view);
float range_inv = 1.0f / fabsf(far - near);
for (int i = 0; i < pix_ct; i++) {
pix_z[i] = (pix_z[i] + near) * range_inv;
pix_z[i] = clamp_f(pix_z[i], 0.0f, 1.0f);
}
}
}
const bool do_region = (scene->r.mode & R_BORDER) != 0;
const bool do_clear_z = !pix_z || do_region;
const bool do_clear_col = !pix_col || do_region;
/* FIXME(fclem): we have a precision loss in the depth buffer because of this reupload.
* Find where it comes from! */
/* In multi view render the textures can be reused. */
if (txl->render_depth_tx && !do_clear_z) {
GPU_texture_update(txl->render_depth_tx, GPU_DATA_FLOAT, pix_z);
}
else {
txl->render_depth_tx = DRW_texture_create_2d(
size[0], size[1], GPU_DEPTH_COMPONENT24, 0, do_region ? NULL : pix_z);
}
if (txl->render_color_tx && !do_clear_col) {
GPU_texture_update(txl->render_color_tx, GPU_DATA_FLOAT, pix_col);
}
else {
txl->render_color_tx = DRW_texture_create_2d(
size[0], size[1], GPU_RGBA16F, 0, do_region ? NULL : pix_col);
}
GPU_framebuffer_ensure_config(&fbl->render_fb,
{
GPU_ATTACHMENT_TEXTURE(txl->render_depth_tx),
GPU_ATTACHMENT_TEXTURE(txl->render_color_tx),
});
if (do_clear_z || do_clear_col) {
/* To avoid unpredictable result, clear buffers that have not be initialized. */
GPU_framebuffer_bind(fbl->render_fb);
if (do_clear_col) {
float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(fbl->render_fb, clear_col);
}
if (do_clear_z) {
GPU_framebuffer_clear_depth(fbl->render_fb, 1.0f);
}
}
if (do_region) {
int x = rect->xmin;
int y = rect->ymin;
int w = BLI_rcti_size_x(rect);
int h = BLI_rcti_size_y(rect);
if (pix_col) {
GPU_texture_update_sub(txl->render_color_tx, GPU_DATA_FLOAT, pix_col, x, y, 0, w, h, 0);
}
if (pix_z) {
GPU_texture_update_sub(txl->render_depth_tx, GPU_DATA_FLOAT, pix_z, x, y, 0, w, h, 0);
}
}
MEM_SAFE_FREE(pix_z);
}
/* render all objects and select only grease pencil */
static void GPENCIL_render_cache(void *vedata,
struct Object *ob,
struct RenderEngine *UNUSED(engine),
Depsgraph *UNUSED(depsgraph))
{
if (ob && ELEM(ob->type, OB_GPENCIL, OB_LAMP)) {
if (DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF) {
GPENCIL_cache_populate(vedata, ob);
}
}
}
static void GPENCIL_render_result_z(struct RenderLayer *rl,
const char *viewname,
GPENCIL_Data *vedata,
const rcti *rect)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
if ((view_layer->passflag & SCE_PASS_Z) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
GPU_framebuffer_read_depth(vedata->fbl->render_fb,
rect->xmin,
rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
rp->rect);
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
/* Convert ogl depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(NULL)) {
for (int i = 0; i < pix_ct; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
else {
rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
}
}
}
else {
/* Keep in mind, near and far distance are negatives. */
float near = DRW_view_near_distance_get(NULL);
float far = DRW_view_far_distance_get(NULL);
float range = fabsf(far - near);
for (int i = 0; i < pix_ct; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
else {
rp->rect[i] = -rp->rect[i] * range + near;
}
}
}
}
}
static void GPENCIL_render_result_combined(struct RenderLayer *rl,
const char *viewname,
GPENCIL_Data *vedata,
const rcti *rect)
{
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
GPU_framebuffer_bind(fbl->render_fb);
GPU_framebuffer_read_color(vedata->fbl->render_fb,
rect->xmin,
rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
4,
0,
GPU_DATA_FLOAT,
rp->rect);
}
void GPENCIL_render_to_image(void *ved,
RenderEngine *engine,
struct RenderLayer *render_layer,
const rcti *rect)
{
GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
const char *viewname = RE_GetActiveRenderView(engine->re);
const DRWContextState *draw_ctx = DRW_context_state_get();
Depsgraph *depsgraph = draw_ctx->depsgraph;
GPENCIL_render_init(vedata, engine, render_layer, depsgraph, rect);
GPENCIL_engine_init(vedata);
vedata->stl->pd->camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
/* Loop over all objects and create draw structure. */
GPENCIL_cache_init(vedata);
DRW_render_object_iter(vedata, engine, depsgraph, GPENCIL_render_cache);
GPENCIL_cache_finish(vedata);
DRW_render_instance_buffer_finish();
/* Render the gpencil object and merge the result to the underlying render. */
GPENCIL_draw_scene(vedata);
GPENCIL_render_result_combined(render_layer, viewname, vedata, rect);
GPENCIL_render_result_z(render_layer, viewname, vedata, rect);
}