Files
test/source/blender/render/intern/engine.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1434 lines
41 KiB
C++
Raw Normal View History

/* SPDX-FileCopyrightText: 2006 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup render
*/
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_math_bits.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_object_types.h"
Multi-View and Stereo 3D Official Documentation: http://www.blender.org/manual/render/workflows/multiview.html Implemented Features ==================== Builtin Stereo Camera * Convergence Mode * Interocular Distance * Convergence Distance * Pivot Mode Viewport * Cameras * Plane * Volume Compositor * View Switch Node * Image Node Multi-View OpenEXR support Sequencer * Image/Movie Strips 'Use Multiview' UV/Image Editor * Option to see Multi-View images in Stereo-3D or its individual images * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images I/O * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images Scene Render Views * Ability to have an arbitrary number of views in the scene Missing Bits ============ First rule of Multi-View bug report: If something is not working as it should *when Views is off* this is a severe bug, do mention this in the report. Second rule is, if something works *when Views is off* but doesn't (or crashes) when *Views is on*, this is a important bug. Do mention this in the report. Everything else is likely small todos, and may wait until we are sure none of the above is happening. Apart from that there are those known issues: * Compositor Image Node poorly working for Multi-View OpenEXR (this was working prefectly before the 'Use Multi-View' functionality) * Selecting camera from Multi-View when looking from camera is problematic * Animation Playback (ctrl+F11) doesn't support stereo formats * Wrong filepath when trying to play back animated scene * Viewport Rendering doesn't support Multi-View * Overscan Rendering * Fullscreen display modes need to warn the user * Object copy should be aware of views suffix Acknowledgments =============== * Francesco Siddi for the help with the original feature specs and design * Brecht Van Lommel for the original review of the code and design early on * Blender Foundation for the Development Fund to support the project wrap up Final patch reviewers: * Antony Riakiotakis (psy-fi) * Campbell Barton (ideasman42) * Julian Eisel (Severin) * Sergey Sharybin (nazgul) * Thomas Dinged (dingto) Code contributors of the original branch in github: * Alexey Akishin * Gabriel Caraballo
2015-04-06 10:40:12 -03:00
#include "BKE_camera.h"
#include "BKE_global.hh"
#include "BKE_node.hh"
#include "BKE_report.hh"
#include "BKE_scene.hh"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_debug.hh"
#include "DEG_depsgraph_query.hh"
#include "GPU_context.hh"
#ifdef WITH_PYTHON
# include "BPY_extern.hh"
#endif
2024-01-18 22:50:23 +02:00
#include "IMB_imbuf_types.hh"
#include "RE_bake.h"
#include "RE_engine.h"
#include "RE_pipeline.h"
2024-01-05 11:16:57 -05:00
#include "DRW_engine.hh"
#include "WM_api.hh"
#include "pipeline.hh"
#include "render_result.h"
#include "render_types.h"
/* Render Engine Types */
ListBase R_engines = {nullptr, nullptr};
void RE_engines_init()
{
DRW_engines_register();
DRW_module_init();
}
void RE_engines_exit()
{
RenderEngineType *type, *next;
DRW_engines_free();
DRW_module_exit();
for (type = static_cast<RenderEngineType *>(R_engines.first); type; type = next) {
2012-06-16 16:57:16 +00:00
next = type->next;
BLI_remlink(&R_engines, type);
if (!(type->flag & RE_INTERNAL)) {
if (type->rna_ext.free) {
type->rna_ext.free(type->rna_ext.data);
2019-04-22 09:08:06 +10:00
}
MEM_freeN(type);
}
}
}
void RE_engines_register(RenderEngineType *render_type)
{
BLI_addtail(&R_engines, render_type);
}
RenderEngineType *RE_engines_find(const char *idname)
{
RenderEngineType *type = static_cast<RenderEngineType *>(
BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname)));
2019-04-22 09:08:06 +10:00
if (!type) {
type = static_cast<RenderEngineType *>(
BLI_findstring(&R_engines, "BLENDER_EEVEE_NEXT", offsetof(RenderEngineType, idname)));
2019-04-22 09:08:06 +10:00
}
return type;
}
bool RE_engine_is_external(const Render *re)
{
return (re->engine && re->engine->type && re->engine->type->render);
}
Cycles: experimental integration of Alembic procedural in viewport rendering This patch exposes the Cycles Alembic Procedural through the MeshSequenceCache modifier in order to use and test it from Blender. To enable it, one has to switch the render feature set to experimental and activate the Procedural in the modifier. An Alembic Procedural is then created for each CacheFile from Blender set to use the Procedural, and each Blender object having a MeshSequenceCache modifier is added to list of objects of the right procedural. The procedural's parameters derive from the CacheFile's properties which are already exposed in the UI through the modifier, although more Cycles specific options might be added in the future. As there is currently no cache controls and since we load all the data at the beginning of the render session, the procedural is only available during viewport renders at the moment. When an Alembic procedural is rendered, data from the archive are not read on the Blender side. If a Cycles render is not active and the CacheFile is set to use the Cycles Procedural, bounding boxes are used to display the objects in the scene as a signal that the objects are not processed by Blender anymore. This is standard in other DCCs. However this does not reduce the memory usage from Blender as the Alembic data was already loaded either during an import or during a .blend file read. This is mostly a hack to test the Cycles Alembic procedural until we have a better Blender side mechanism for letting renderers load their own geometry, which will be based on import and export settings on Collections (T68933). Ref T79174, D3089 Reviewed By: brecht, sybren Maniphest Tasks: T79174 Differential Revision: https://developer.blender.org/D10197
2021-08-19 14:34:01 +02:00
bool RE_engine_supports_alembic_procedural(const RenderEngineType *render_type, Scene *scene)
{
if ((render_type->flag & RE_USE_ALEMBIC_PROCEDURAL) == 0) {
return false;
}
if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
return false;
}
return true;
}
/* Create, Free */
RenderEngine *RE_engine_create(RenderEngineType *type)
{
RenderEngine *engine = MEM_callocN<RenderEngine>("RenderEngine");
2012-06-16 16:57:16 +00:00
engine->type = type;
BLI_mutex_init(&engine->update_render_passes_mutex);
BLI_mutex_init(&engine->blender_gpu_context_mutex);
return engine;
}
static void engine_depsgraph_free(RenderEngine *engine)
{
if (engine->depsgraph) {
/* Need GPU context since this might free GPU buffers. */
const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT);
if (use_gpu_context) {
/* This function can be called on the main thread before RenderEngine is destroyed.
* In this case, just bind the main draw context to gather the deleted GPU buffers.
* Binding the same GPU context as the render engine is not needed (see #129019). */
if (BLI_thread_is_main()) {
DRW_gpu_context_enable();
}
else {
DRW_render_context_enable(engine->re);
}
}
DEG_graph_free(engine->depsgraph);
engine->depsgraph = nullptr;
if (use_gpu_context) {
if (BLI_thread_is_main()) {
DRW_gpu_context_disable();
}
else {
DRW_render_context_disable(engine->re);
}
}
}
}
void RE_engine_free(RenderEngine *engine)
{
#ifdef WITH_PYTHON
if (engine->py_instance) {
BPY_DECREF_RNA_INVALIDATE(engine->py_instance);
}
#endif
engine_depsgraph_free(engine);
BLI_mutex_end(&engine->blender_gpu_context_mutex);
BLI_mutex_end(&engine->update_render_passes_mutex);
MEM_freeN(engine);
}
/* Bake Render Results */
static RenderResult *render_result_from_bake(
RenderEngine *engine, int x, int y, int w, int h, const char *layername)
{
BakeImage *image = &engine->bake.targets->images[engine->bake.image_id];
const BakePixel *pixels = engine->bake.pixels + image->offset;
const size_t channels_num = engine->bake.targets->channels_num;
/* Remember layer name for to match images in render_frame_finish. */
if (image->render_layer_name[0] == '\0') {
STRNCPY(image->render_layer_name, layername);
}
/* Create render result with specified size. */
RenderResult *rr = MEM_callocN<RenderResult>(__func__);
rr->rectx = w;
rr->recty = h;
rr->tilerect.xmin = x;
rr->tilerect.ymin = y;
rr->tilerect.xmax = x + w;
rr->tilerect.ymax = y + h;
BKE_scene_ppm_get(&engine->re->r, rr->ppm);
/* Add single baking render layer. */
RenderLayer *rl = MEM_callocN<RenderLayer>("bake render layer");
STRNCPY(rl->name, layername);
rl->rectx = w;
rl->recty = h;
BLI_addtail(&rr->layers, rl);
/* Add render passes. */
render_layer_add_pass(rr, rl, channels_num, RE_PASSNAME_COMBINED, "", "RGBA", true);
RenderPass *primitive_pass = render_layer_add_pass(rr, rl, 3, "BakePrimitive", "", "RGB", true);
RenderPass *differential_pass = render_layer_add_pass(
rr, rl, 4, "BakeDifferential", "", "RGBA", true);
/* Per-pixel seeds are only needed for baking to vertex colors, see
* bake_targets_populate_pixels_color_attributes for more details. */
RenderPass *seed_pass = (image->image == nullptr) ?
render_layer_add_pass(rr, rl, 1, "BakeSeed", "", "X", true) :
nullptr;
/* Fill render passes from bake pixel array, to be read by the render engine. */
for (int ty = 0; ty < h; ty++) {
size_t offset = ty * w;
float *primitive = primitive_pass->ibuf->float_buffer.data + 3 * offset;
float *seed = (seed_pass != nullptr) ? (seed_pass->ibuf->float_buffer.data + offset) : nullptr;
float *differential = differential_pass->ibuf->float_buffer.data + 4 * offset;
size_t bake_offset = (y + ty) * image->width + x;
const BakePixel *bake_pixel = pixels + bake_offset;
for (int tx = 0; tx < w; tx++) {
if (bake_pixel->object_id != engine->bake.object_id) {
primitive[0] = int_as_float(-1);
primitive[1] = int_as_float(-1);
primitive[2] = int_as_float(-1);
}
else {
primitive[0] = bake_pixel->uv[0];
primitive[1] = bake_pixel->uv[1];
primitive[2] = int_as_float(bake_pixel->primitive_id);
differential[0] = bake_pixel->du_dx;
differential[1] = bake_pixel->du_dy;
differential[2] = bake_pixel->dv_dx;
differential[3] = bake_pixel->dv_dy;
}
if (seed_pass != nullptr) {
*seed = int_as_float(bake_pixel->seed);
seed += 1;
}
primitive += 3;
differential += 4;
bake_pixel++;
}
}
return rr;
}
static void render_result_to_bake(RenderEngine *engine, RenderResult *rr)
{
RenderLayer *rl = static_cast<RenderLayer *>(rr->layers.first);
RenderPass *rpass = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, "");
if (!rpass) {
return;
}
/* Find bake image corresponding to layer. */
int image_id = 0;
for (; image_id < engine->bake.targets->images_num; image_id++) {
if (STREQ(engine->bake.targets->images[image_id].render_layer_name, rl->name)) {
break;
}
}
if (image_id == engine->bake.targets->images_num) {
return;
}
const BakeImage *image = &engine->bake.targets->images[image_id];
const BakePixel *pixels = engine->bake.pixels + image->offset;
const size_t channels_num = engine->bake.targets->channels_num;
const size_t channels_size = channels_num * sizeof(float);
float *result = engine->bake.result + image->offset * channels_num;
/* Copy from tile render result to full image bake result. Just the pixels for the
* object currently being baked, to preserve other objects when baking multiple. */
const int x = rr->tilerect.xmin;
const int y = rr->tilerect.ymin;
const int w = rr->tilerect.xmax - rr->tilerect.xmin;
const int h = rr->tilerect.ymax - rr->tilerect.ymin;
for (int ty = 0; ty < h; ty++) {
const size_t offset = ty * w;
const size_t bake_offset = (y + ty) * image->width + x;
const float *pass_rect = rpass->ibuf->float_buffer.data + offset * channels_num;
const BakePixel *bake_pixel = pixels + bake_offset;
float *bake_result = result + bake_offset * channels_num;
for (int tx = 0; tx < w; tx++) {
if (bake_pixel->object_id == engine->bake.object_id) {
memcpy(bake_result, pass_rect, channels_size);
}
pass_rect += channels_num;
bake_result += channels_num;
bake_pixel++;
}
}
}
/* Render Results */
2017-04-24 12:41:54 +02:00
RenderResult *RE_engine_begin_result(
RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
{
if (engine->bake.targets) {
RenderResult *result = render_result_from_bake(engine, x, y, w, h, layername);
BLI_addtail(&engine->fullresult, result);
return result;
}
2012-06-16 16:57:16 +00:00
Render *re = engine->re;
RenderResult *result;
rcti disprect;
/* ensure the coordinates are within the right limits */
CLAMP(x, 0, re->result->rectx);
CLAMP(y, 0, re->result->recty);
CLAMP(w, 0, re->result->rectx);
CLAMP(h, 0, re->result->recty);
2019-04-22 09:08:06 +10:00
if (x + w > re->result->rectx) {
2012-06-16 16:57:16 +00:00
w = re->result->rectx - x;
2019-04-22 09:08:06 +10:00
}
if (y + h > re->result->recty) {
2012-06-16 16:57:16 +00:00
h = re->result->recty - y;
2019-04-22 09:08:06 +10:00
}
/* allocate a render result */
disprect.xmin = x;
2012-06-16 16:57:16 +00:00
disprect.xmax = x + w;
disprect.ymin = y;
2012-06-16 16:57:16 +00:00
disprect.ymax = y + h;
result = render_result_new(re, &disprect, layername, viewname);
/* TODO: make this thread safe. */
/* can be nullptr if we CLAMP the width or height to 0 */
if (result) {
render_result_clone_passes(re, result, viewname);
render_result_passes_allocated_ensure(result);
BLI_addtail(&engine->fullresult, result);
result->tilerect.xmin += re->disprect.xmin;
result->tilerect.xmax += re->disprect.xmin;
result->tilerect.ymin += re->disprect.ymin;
result->tilerect.ymax += re->disprect.ymin;
}
return result;
}
static void re_ensure_passes_allocated_thread_safe(Render *re)
{
if (!re->result->passes_allocated) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if (!re->result->passes_allocated) {
render_result_passes_allocated_ensure(re->result);
}
BLI_rw_mutex_unlock(&re->resultmutex);
}
}
void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
{
if (engine->bake.targets) {
/* No interactive baking updates for now. */
return;
}
2012-06-16 16:57:16 +00:00
Render *re = engine->re;
if (result) {
re_ensure_passes_allocated_thread_safe(re);
render_result_merge(re->result, result);
result->renlay = static_cast<RenderLayer *>(
result->layers.first); /* weak, draws first layer always */
re->display_update(result, nullptr);
}
}
void RE_engine_add_pass(RenderEngine *engine,
const char *name,
int channels,
const char *chan_id,
const char *layername)
{
Render *re = engine->re;
if (!re || !re->result) {
return;
}
RE_create_render_pass(re->result, name, channels, chan_id, layername, nullptr, false);
}
void RE_engine_end_result(
RenderEngine *engine, RenderResult *result, bool cancel, bool highlight, bool merge_results)
{
2012-06-16 16:57:16 +00:00
Render *re = engine->re;
if (!result) {
return;
}
if (engine->bake.targets) {
if (!cancel || merge_results) {
render_result_to_bake(engine, result);
}
BLI_remlink(&engine->fullresult, result);
render_result_free(result);
return;
}
if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES)) {
blender::render::TilesHighlight *tile_highlight = re->get_tile_highlight();
if (tile_highlight) {
if (highlight) {
tile_highlight->highlight_tile_for_result(result);
}
else {
tile_highlight->unhighlight_tile_for_result(result);
}
}
}
Changes to partial update during rendering Summary: Mainly addressed to solve old TODO with color managed fallback to CPU mode when displaying render result during rendering. That fallback was caused by the fact that partial image update was always acquiring image buffer for composite output and was only modifying display buffer directly. This was a big issue for Cycles rendering which renders layers one by one and wanted to display progress of each individual layer. This lead to situations when display buffer was based on what Cycles passes via RenderResult and didn't take layer/pass from image editor header into account. Now made it so image buffer which partial update is operating with always corresponds to what is set in image editor header. To make Cycles displaying progress of all the layers one by one made it so image_rect_update switches image editor user to newly rendering render layer. It happens only once when render engine starts rendering next render layer, so should not be annoying for navigation during rendering. Additional change to render engines was done to make it so they're able to merge composite output to final result without marking tile as done. This is done via do_merge_result argument to end_result() callback. This argument is optional so should not break script compatibility. Additional changes: - Partial display update for Blender Internal now happens from the same thread as tile rendering. This makes it so display conversion (which could be pretty heavy actually) is done in separate threads. Also gives better UI feedback when rendering easy scene with small tiles. - Avoid freeing/allocating byte buffer for render result if it's owned by the image buffer. Only mark it as invalid for color management. Saves loads of buffer re-allocations in cases when having several image editors opened with render result. This change in conjunction with the rest of the patch gave around 50%-100% speedup of render time when displaying non-combined pass during rendering on my laptop. - Partial display buffer update was wrong for buffers with number of channels different from 4. - Remove unused window from RenderJob. - Made image_buffer_rect_update static since it's only used in single file. Reviewers: brecht Reviewed By: brecht CC: dingto Differential Revision: http://developer.blender.org/D98
2013-12-17 23:42:38 +06:00
if (!cancel || merge_results) {
if (!(re->test_break() && (re->r.scemode & R_BUTS_PREVIEW))) {
re_ensure_passes_allocated_thread_safe(re);
render_result_merge(re->result, result);
2019-04-22 09:08:06 +10:00
}
/* draw */
if (!re->test_break()) {
result->renlay = static_cast<RenderLayer *>(
result->layers.first); /* weak, draws first layer always */
re->display_update(result, nullptr);
}
}
/* free */
BLI_remlink(&engine->fullresult, result);
render_result_free(result);
}
RenderResult *RE_engine_get_result(RenderEngine *engine)
{
return engine->re->result;
}
/* Cancel */
bool RE_engine_test_break(RenderEngine *engine)
{
2012-06-16 16:57:16 +00:00
Render *re = engine->re;
2019-04-22 09:08:06 +10:00
if (re) {
return re->test_break();
2019-04-22 09:08:06 +10:00
}
return false;
}
/* Statistics */
void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info)
{
2012-06-16 16:57:16 +00:00
Render *re = engine->re;
/* stats draw callback */
if (re) {
2012-06-16 16:57:16 +00:00
re->i.statstr = stats;
re->i.infostr = info;
re->stats_draw(&re->i);
re->i.infostr = nullptr;
re->i.statstr = nullptr;
}
/* set engine text */
engine->text[0] = '\0';
2019-04-22 09:08:06 +10:00
if (stats && stats[0] && info && info[0]) {
2023-05-09 12:50:37 +10:00
SNPRINTF(engine->text, "%s | %s", stats, info);
2019-04-22 09:08:06 +10:00
}
else if (info && info[0]) {
2023-05-09 12:50:37 +10:00
STRNCPY(engine->text, info);
2019-04-22 09:08:06 +10:00
}
else if (stats && stats[0]) {
2023-05-09 12:50:37 +10:00
STRNCPY(engine->text, stats);
2019-04-22 09:08:06 +10:00
}
}
void RE_engine_update_progress(RenderEngine *engine, float progress)
{
2012-06-16 16:57:16 +00:00
Render *re = engine->re;
if (re) {
CLAMP(progress, 0.0f, 1.0f);
re->progress(progress);
}
}
void RE_engine_update_memory_stats(RenderEngine *engine, float mem_used, float mem_peak)
{
Render *re = engine->re;
if (re) {
re->i.mem_used = mem_used;
re->i.mem_peak = mem_peak;
}
}
void RE_engine_report(RenderEngine *engine, int type, const char *msg)
{
Render *re = engine->re;
2019-04-22 09:08:06 +10:00
if (re) {
BKE_report(engine->re->reports, (eReportType)type, msg);
2019-04-22 09:08:06 +10:00
}
else if (engine->reports) {
BKE_report(engine->reports, (eReportType)type, msg);
2019-04-22 09:08:06 +10:00
}
}
void RE_engine_set_error_message(RenderEngine *engine, const char *msg)
{
Render *re = engine->re;
if (re != nullptr) {
RenderResult *rr = RE_AcquireResultRead(re);
if (rr) {
if (rr->error != nullptr) {
MEM_freeN(rr->error);
}
rr->error = BLI_strdup(msg);
}
RE_ReleaseResult(re);
}
}
RenderPass *RE_engine_pass_by_index_get(RenderEngine *engine, const char *layer_name, int index)
{
Render *re = engine->re;
if (re == nullptr) {
return nullptr;
}
RenderPass *pass = nullptr;
RenderResult *rr = RE_AcquireResultRead(re);
if (rr != nullptr) {
const RenderLayer *layer = RE_GetRenderLayer(rr, layer_name);
if (layer != nullptr) {
pass = static_cast<RenderPass *>(BLI_findlink(&layer->passes, index));
}
}
RE_ReleaseResult(re);
return pass;
}
Multi-View: Cycles - Spherical Stereo support (VR Panoramas) This is a new option for panorama cameras to render stereo that can be used in virtual reality devices The option is available under the camera panel when Multi-View is enabled (Views option in the Render Layers panel) Known limitations: ------------------ * Parallel convergence is not supported (you need to set a convergence distance really high to simulate this effect). * Pivot was not supposed to affect the render but it does, this has to be looked at, but for now set it to CENTER * Derivatives in perspective camera need to be pre-computed or we shuld get rid of kcam->dx/dy (Sergey words, I don't fully grasp the implication shere) * This works in perspective mode and in panorama mode. However, for fully benefit from this effect in perspective mode you need to render a cube map. (there is an addon for this, developed separately, perhaps we could include it in master). * We have no support for "neck distance" at the moment. This is supposed to help with objects at short distances. * We have no support to rotate the "Up Axis" of the stereo plane. Meaning, we hardcode 0,0,1 as UP, and create the stereo pair related to that. (although we could take the camera local UP when rendering panoramas, this wouldn't work for perspective cameras. * We have no support for interocular distance attenuation based on the proximity of the poles (which helps to reduce the pole rotation effect/artifact). THIS NEEDS DOCS - both in 2.78 release log and the Blender manual. Meanwhile you can read about it here: http://code.blender.org/2015/03/1451 This patch specifically dates from March 2015, as you can see in the code.blender.org post. Many thanks to all the reviewers, testers and minor sponsors who helped me maintain spherical-stereo for 1 year. All that said, have fun with this. This feature was what got me started with Multi-View development (at the time what I was looking for was Fulldome stereo support, but the implementation is the same). In order to make this into Blender I had to make it aiming at a less-specic user-case Thus Multi-View started. (this was December 2012, during Siggraph Asia and a chat I had with Paul Bourke during the conference). I don't have the original patch anymore, but you can find a re-based version of it from March 2013, right before I start with the Multi-View project https://developer.blender.org/P332 Reviewers: sergey, dingto Subscribers: #cycles Differential Revision: https://developer.blender.org/D1223
2016-03-10 09:28:29 -03:00
const char *RE_engine_active_view_get(RenderEngine *engine)
{
Render *re = engine->re;
return RE_GetActiveRenderView(re);
}
Multi-View and Stereo 3D Official Documentation: http://www.blender.org/manual/render/workflows/multiview.html Implemented Features ==================== Builtin Stereo Camera * Convergence Mode * Interocular Distance * Convergence Distance * Pivot Mode Viewport * Cameras * Plane * Volume Compositor * View Switch Node * Image Node Multi-View OpenEXR support Sequencer * Image/Movie Strips 'Use Multiview' UV/Image Editor * Option to see Multi-View images in Stereo-3D or its individual images * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images I/O * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images Scene Render Views * Ability to have an arbitrary number of views in the scene Missing Bits ============ First rule of Multi-View bug report: If something is not working as it should *when Views is off* this is a severe bug, do mention this in the report. Second rule is, if something works *when Views is off* but doesn't (or crashes) when *Views is on*, this is a important bug. Do mention this in the report. Everything else is likely small todos, and may wait until we are sure none of the above is happening. Apart from that there are those known issues: * Compositor Image Node poorly working for Multi-View OpenEXR (this was working prefectly before the 'Use Multi-View' functionality) * Selecting camera from Multi-View when looking from camera is problematic * Animation Playback (ctrl+F11) doesn't support stereo formats * Wrong filepath when trying to play back animated scene * Viewport Rendering doesn't support Multi-View * Overscan Rendering * Fullscreen display modes need to warn the user * Object copy should be aware of views suffix Acknowledgments =============== * Francesco Siddi for the help with the original feature specs and design * Brecht Van Lommel for the original review of the code and design early on * Blender Foundation for the Development Fund to support the project wrap up Final patch reviewers: * Antony Riakiotakis (psy-fi) * Campbell Barton (ideasman42) * Julian Eisel (Severin) * Sergey Sharybin (nazgul) * Thomas Dinged (dingto) Code contributors of the original branch in github: * Alexey Akishin * Gabriel Caraballo
2015-04-06 10:40:12 -03:00
void RE_engine_active_view_set(RenderEngine *engine, const char *viewname)
{
Render *re = engine->re;
RE_SetActiveRenderView(re, viewname);
}
float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, bool use_spherical_stereo)
Multi-View and Stereo 3D Official Documentation: http://www.blender.org/manual/render/workflows/multiview.html Implemented Features ==================== Builtin Stereo Camera * Convergence Mode * Interocular Distance * Convergence Distance * Pivot Mode Viewport * Cameras * Plane * Volume Compositor * View Switch Node * Image Node Multi-View OpenEXR support Sequencer * Image/Movie Strips 'Use Multiview' UV/Image Editor * Option to see Multi-View images in Stereo-3D or its individual images * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images I/O * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images Scene Render Views * Ability to have an arbitrary number of views in the scene Missing Bits ============ First rule of Multi-View bug report: If something is not working as it should *when Views is off* this is a severe bug, do mention this in the report. Second rule is, if something works *when Views is off* but doesn't (or crashes) when *Views is on*, this is a important bug. Do mention this in the report. Everything else is likely small todos, and may wait until we are sure none of the above is happening. Apart from that there are those known issues: * Compositor Image Node poorly working for Multi-View OpenEXR (this was working prefectly before the 'Use Multi-View' functionality) * Selecting camera from Multi-View when looking from camera is problematic * Animation Playback (ctrl+F11) doesn't support stereo formats * Wrong filepath when trying to play back animated scene * Viewport Rendering doesn't support Multi-View * Overscan Rendering * Fullscreen display modes need to warn the user * Object copy should be aware of views suffix Acknowledgments =============== * Francesco Siddi for the help with the original feature specs and design * Brecht Van Lommel for the original review of the code and design early on * Blender Foundation for the Development Fund to support the project wrap up Final patch reviewers: * Antony Riakiotakis (psy-fi) * Campbell Barton (ideasman42) * Julian Eisel (Severin) * Sergey Sharybin (nazgul) * Thomas Dinged (dingto) Code contributors of the original branch in github: * Alexey Akishin * Gabriel Caraballo
2015-04-06 10:40:12 -03:00
{
/* When using spherical stereo, get camera shift without multiview,
* leaving stereo to be handled by the engine. */
Render *re = engine->re;
if (use_spherical_stereo || re == nullptr) {
return BKE_camera_multiview_shift_x(nullptr, camera, nullptr);
}
2020-08-17 14:00:42 -04:00
return BKE_camera_multiview_shift_x(&re->r, camera, re->viewname);
Multi-View and Stereo 3D Official Documentation: http://www.blender.org/manual/render/workflows/multiview.html Implemented Features ==================== Builtin Stereo Camera * Convergence Mode * Interocular Distance * Convergence Distance * Pivot Mode Viewport * Cameras * Plane * Volume Compositor * View Switch Node * Image Node Multi-View OpenEXR support Sequencer * Image/Movie Strips 'Use Multiview' UV/Image Editor * Option to see Multi-View images in Stereo-3D or its individual images * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images I/O * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images Scene Render Views * Ability to have an arbitrary number of views in the scene Missing Bits ============ First rule of Multi-View bug report: If something is not working as it should *when Views is off* this is a severe bug, do mention this in the report. Second rule is, if something works *when Views is off* but doesn't (or crashes) when *Views is on*, this is a important bug. Do mention this in the report. Everything else is likely small todos, and may wait until we are sure none of the above is happening. Apart from that there are those known issues: * Compositor Image Node poorly working for Multi-View OpenEXR (this was working prefectly before the 'Use Multi-View' functionality) * Selecting camera from Multi-View when looking from camera is problematic * Animation Playback (ctrl+F11) doesn't support stereo formats * Wrong filepath when trying to play back animated scene * Viewport Rendering doesn't support Multi-View * Overscan Rendering * Fullscreen display modes need to warn the user * Object copy should be aware of views suffix Acknowledgments =============== * Francesco Siddi for the help with the original feature specs and design * Brecht Van Lommel for the original review of the code and design early on * Blender Foundation for the Development Fund to support the project wrap up Final patch reviewers: * Antony Riakiotakis (psy-fi) * Campbell Barton (ideasman42) * Julian Eisel (Severin) * Sergey Sharybin (nazgul) * Thomas Dinged (dingto) Code contributors of the original branch in github: * Alexey Akishin * Gabriel Caraballo
2015-04-06 10:40:12 -03:00
}
2017-04-24 12:41:54 +02:00
void RE_engine_get_camera_model_matrix(RenderEngine *engine,
2018-07-01 16:22:06 +02:00
Object *camera,
bool use_spherical_stereo,
float r_modelmat[16])
Multi-View and Stereo 3D Official Documentation: http://www.blender.org/manual/render/workflows/multiview.html Implemented Features ==================== Builtin Stereo Camera * Convergence Mode * Interocular Distance * Convergence Distance * Pivot Mode Viewport * Cameras * Plane * Volume Compositor * View Switch Node * Image Node Multi-View OpenEXR support Sequencer * Image/Movie Strips 'Use Multiview' UV/Image Editor * Option to see Multi-View images in Stereo-3D or its individual images * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images I/O * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images Scene Render Views * Ability to have an arbitrary number of views in the scene Missing Bits ============ First rule of Multi-View bug report: If something is not working as it should *when Views is off* this is a severe bug, do mention this in the report. Second rule is, if something works *when Views is off* but doesn't (or crashes) when *Views is on*, this is a important bug. Do mention this in the report. Everything else is likely small todos, and may wait until we are sure none of the above is happening. Apart from that there are those known issues: * Compositor Image Node poorly working for Multi-View OpenEXR (this was working prefectly before the 'Use Multi-View' functionality) * Selecting camera from Multi-View when looking from camera is problematic * Animation Playback (ctrl+F11) doesn't support stereo formats * Wrong filepath when trying to play back animated scene * Viewport Rendering doesn't support Multi-View * Overscan Rendering * Fullscreen display modes need to warn the user * Object copy should be aware of views suffix Acknowledgments =============== * Francesco Siddi for the help with the original feature specs and design * Brecht Van Lommel for the original review of the code and design early on * Blender Foundation for the Development Fund to support the project wrap up Final patch reviewers: * Antony Riakiotakis (psy-fi) * Campbell Barton (ideasman42) * Julian Eisel (Severin) * Sergey Sharybin (nazgul) * Thomas Dinged (dingto) Code contributors of the original branch in github: * Alexey Akishin * Gabriel Caraballo
2015-04-06 10:40:12 -03:00
{
/* When using spherical stereo, get model matrix without multiview,
* leaving stereo to be handled by the engine. */
Render *re = engine->re;
if (use_spherical_stereo || re == nullptr) {
BKE_camera_multiview_model_matrix(nullptr, camera, nullptr, (float(*)[4])r_modelmat);
}
else {
BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, (float(*)[4])r_modelmat);
2019-04-22 09:08:06 +10:00
}
Multi-View and Stereo 3D Official Documentation: http://www.blender.org/manual/render/workflows/multiview.html Implemented Features ==================== Builtin Stereo Camera * Convergence Mode * Interocular Distance * Convergence Distance * Pivot Mode Viewport * Cameras * Plane * Volume Compositor * View Switch Node * Image Node Multi-View OpenEXR support Sequencer * Image/Movie Strips 'Use Multiview' UV/Image Editor * Option to see Multi-View images in Stereo-3D or its individual images * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images I/O * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images Scene Render Views * Ability to have an arbitrary number of views in the scene Missing Bits ============ First rule of Multi-View bug report: If something is not working as it should *when Views is off* this is a severe bug, do mention this in the report. Second rule is, if something works *when Views is off* but doesn't (or crashes) when *Views is on*, this is a important bug. Do mention this in the report. Everything else is likely small todos, and may wait until we are sure none of the above is happening. Apart from that there are those known issues: * Compositor Image Node poorly working for Multi-View OpenEXR (this was working prefectly before the 'Use Multi-View' functionality) * Selecting camera from Multi-View when looking from camera is problematic * Animation Playback (ctrl+F11) doesn't support stereo formats * Wrong filepath when trying to play back animated scene * Viewport Rendering doesn't support Multi-View * Overscan Rendering * Fullscreen display modes need to warn the user * Object copy should be aware of views suffix Acknowledgments =============== * Francesco Siddi for the help with the original feature specs and design * Brecht Van Lommel for the original review of the code and design early on * Blender Foundation for the Development Fund to support the project wrap up Final patch reviewers: * Antony Riakiotakis (psy-fi) * Campbell Barton (ideasman42) * Julian Eisel (Severin) * Sergey Sharybin (nazgul) * Thomas Dinged (dingto) Code contributors of the original branch in github: * Alexey Akishin * Gabriel Caraballo
2015-04-06 10:40:12 -03:00
}
bool RE_engine_get_spherical_stereo(RenderEngine *engine, Object *camera)
Multi-View: Cycles - Spherical Stereo support (VR Panoramas) This is a new option for panorama cameras to render stereo that can be used in virtual reality devices The option is available under the camera panel when Multi-View is enabled (Views option in the Render Layers panel) Known limitations: ------------------ * Parallel convergence is not supported (you need to set a convergence distance really high to simulate this effect). * Pivot was not supposed to affect the render but it does, this has to be looked at, but for now set it to CENTER * Derivatives in perspective camera need to be pre-computed or we shuld get rid of kcam->dx/dy (Sergey words, I don't fully grasp the implication shere) * This works in perspective mode and in panorama mode. However, for fully benefit from this effect in perspective mode you need to render a cube map. (there is an addon for this, developed separately, perhaps we could include it in master). * We have no support for "neck distance" at the moment. This is supposed to help with objects at short distances. * We have no support to rotate the "Up Axis" of the stereo plane. Meaning, we hardcode 0,0,1 as UP, and create the stereo pair related to that. (although we could take the camera local UP when rendering panoramas, this wouldn't work for perspective cameras. * We have no support for interocular distance attenuation based on the proximity of the poles (which helps to reduce the pole rotation effect/artifact). THIS NEEDS DOCS - both in 2.78 release log and the Blender manual. Meanwhile you can read about it here: http://code.blender.org/2015/03/1451 This patch specifically dates from March 2015, as you can see in the code.blender.org post. Many thanks to all the reviewers, testers and minor sponsors who helped me maintain spherical-stereo for 1 year. All that said, have fun with this. This feature was what got me started with Multi-View development (at the time what I was looking for was Fulldome stereo support, but the implementation is the same). In order to make this into Blender I had to make it aiming at a less-specic user-case Thus Multi-View started. (this was December 2012, during Siggraph Asia and a chat I had with Paul Bourke during the conference). I don't have the original patch anymore, but you can find a re-based version of it from March 2013, right before I start with the Multi-View project https://developer.blender.org/P332 Reviewers: sergey, dingto Subscribers: #cycles Differential Revision: https://developer.blender.org/D1223
2016-03-10 09:28:29 -03:00
{
Render *re = engine->re;
return BKE_camera_multiview_spherical_stereo(re ? &re->r : nullptr, camera) ? true : false;
Multi-View: Cycles - Spherical Stereo support (VR Panoramas) This is a new option for panorama cameras to render stereo that can be used in virtual reality devices The option is available under the camera panel when Multi-View is enabled (Views option in the Render Layers panel) Known limitations: ------------------ * Parallel convergence is not supported (you need to set a convergence distance really high to simulate this effect). * Pivot was not supposed to affect the render but it does, this has to be looked at, but for now set it to CENTER * Derivatives in perspective camera need to be pre-computed or we shuld get rid of kcam->dx/dy (Sergey words, I don't fully grasp the implication shere) * This works in perspective mode and in panorama mode. However, for fully benefit from this effect in perspective mode you need to render a cube map. (there is an addon for this, developed separately, perhaps we could include it in master). * We have no support for "neck distance" at the moment. This is supposed to help with objects at short distances. * We have no support to rotate the "Up Axis" of the stereo plane. Meaning, we hardcode 0,0,1 as UP, and create the stereo pair related to that. (although we could take the camera local UP when rendering panoramas, this wouldn't work for perspective cameras. * We have no support for interocular distance attenuation based on the proximity of the poles (which helps to reduce the pole rotation effect/artifact). THIS NEEDS DOCS - both in 2.78 release log and the Blender manual. Meanwhile you can read about it here: http://code.blender.org/2015/03/1451 This patch specifically dates from March 2015, as you can see in the code.blender.org post. Many thanks to all the reviewers, testers and minor sponsors who helped me maintain spherical-stereo for 1 year. All that said, have fun with this. This feature was what got me started with Multi-View development (at the time what I was looking for was Fulldome stereo support, but the implementation is the same). In order to make this into Blender I had to make it aiming at a less-specic user-case Thus Multi-View started. (this was December 2012, during Siggraph Asia and a chat I had with Paul Bourke during the conference). I don't have the original patch anymore, but you can find a re-based version of it from March 2013, right before I start with the Multi-View project https://developer.blender.org/P332 Reviewers: sergey, dingto Subscribers: #cycles Differential Revision: https://developer.blender.org/D1223
2016-03-10 09:28:29 -03:00
}
const rcti *RE_engine_get_current_tiles(Render *re, int *r_total_tiles)
{
blender::render::TilesHighlight *tiles_highlight = re->get_tile_highlight();
if (!tiles_highlight) {
2015-03-24 19:20:33 +05:00
*r_total_tiles = 0;
return nullptr;
};
blender::Span<rcti> highlighted_tiles = tiles_highlight->get_all_highlighted_tiles();
*r_total_tiles = highlighted_tiles.size();
return highlighted_tiles.data();
}
RenderData *RE_engine_get_render_data(Render *re)
{
return &re->r;
}
bool RE_engine_use_persistent_data(RenderEngine *engine)
{
/* Re-rendering is not supported with GPU contexts, since the GPU context
* is destroyed when the render thread exists. */
return (engine->re->r.mode & R_PERSISTENT_DATA) && !(engine->type->flag & RE_USE_GPU_CONTEXT);
}
static bool engine_keep_depsgraph(RenderEngine *engine)
{
/* For persistent data or GPU engines like Eevee, reuse the depsgraph between
* view layers and animation frames. For renderers like Cycles that create
* their own copy of the scene, persistent data must be explicitly enabled to
* keep memory usage low by default. */
return (engine->re->r.mode & R_PERSISTENT_DATA) || (engine->type->flag & RE_USE_GPU_CONTEXT);
}
/* Depsgraph */
static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
{
Main *bmain = engine->re->main;
Scene *scene = engine->re->scene;
bool reuse_depsgraph = false;
/* Reuse depsgraph from persistent data if possible. */
if (engine->depsgraph) {
if (DEG_get_bmain(engine->depsgraph) != bmain ||
DEG_get_input_scene(engine->depsgraph) != scene)
{
/* If bmain or scene changes, we need a completely new graph. */
engine_depsgraph_free(engine);
}
else if (DEG_get_input_view_layer(engine->depsgraph) != view_layer) {
/* If only view layer changed, reuse depsgraph in the hope of reusing
* objects shared between view layers. */
DEG_graph_replace_owners(engine->depsgraph, bmain, scene, view_layer);
DEG_graph_tag_relations_update(engine->depsgraph);
}
reuse_depsgraph = true;
}
if (!engine->depsgraph) {
/* Ensure we only use persistent data for one scene / view layer at a time,
* to avoid excessive memory usage. */
RE_FreePersistentData(nullptr);
/* Create new depsgraph if not cached with persistent data. */
engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
DEG_debug_name_set(engine->depsgraph, "RENDER");
}
if (engine->re->r.scemode & R_BUTS_PREVIEW) {
/* Update for preview render. */
Depsgraph *depsgraph = engine->depsgraph;
DEG_graph_relations_update(depsgraph);
/* Need GPU context since this might free GPU buffers. */
const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT) && reuse_depsgraph;
if (use_gpu_context) {
DRW_render_context_enable(engine->re);
}
DEG_evaluate_on_framechange(depsgraph, BKE_scene_frame_get(scene));
if (use_gpu_context) {
DRW_render_context_disable(engine->re);
}
}
else {
/* Go through update with full Python callbacks for regular render. */
BKE_scene_graph_update_for_newframe_ex(engine->depsgraph, false);
}
engine->has_grease_pencil = DRW_render_check_grease_pencil(engine->depsgraph);
}
static void engine_depsgraph_exit(RenderEngine *engine)
{
if (engine->depsgraph) {
if (engine_keep_depsgraph(engine)) {
/* Clear recalc flags since the engine should have handled the updates for the currently
* rendered framed by now. */
DEG_ids_clear_recalc(engine->depsgraph, false);
}
else {
/* Free immediately to save memory. */
engine_depsgraph_free(engine);
}
}
}
void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
{
2019-03-25 11:55:36 +11:00
if (!engine->depsgraph) {
return;
}
/* Clear recalc flags before update so engine can detect what changed. */
DEG_ids_clear_recalc(engine->depsgraph, false);
Render *re = engine->re;
double cfra = double(frame) + double(subframe);
CLAMP(cfra, MINAFRAME, MAXFRAME);
BKE_scene_frame_set(re->scene, cfra);
BKE_scene_graph_update_for_newframe_ex(engine->depsgraph, false);
2018-06-04 16:51:27 +02:00
BKE_scene_camera_switch_update(re->scene);
}
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
/* Bake */
void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
{
re->scene = scene;
re->main = bmain;
render_copy_renderdata(&re->r, &scene->r);
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
}
bool RE_bake_has_engine(const Render *re)
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
{
const RenderEngineType *type = RE_engines_find(re->r.engine);
return (type->bake != nullptr);
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
}
bool RE_bake_engine(Render *re,
Depsgraph *depsgraph,
Object *object,
const int object_id,
const BakePixel pixel_array[],
const BakeTargets *targets,
const eScenePassType pass_type,
const int pass_filter,
float result[])
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
{
RenderEngineType *type = RE_engines_find(re->r.engine);
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
RenderEngine *engine;
/* set render info */
re->i.cfra = re->scene->r.cfra;
BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name) - 2);
/* render */
engine = re->engine;
if (!engine) {
engine = RE_engine_create(type);
re->engine = engine;
}
engine->flag |= RE_ENGINE_RENDERING;
/* TODO: actually link to a parent which shouldn't happen */
engine->re = re;
engine->resolution_x = re->winx;
engine->resolution_y = re->winy;
2017-04-24 12:41:54 +02:00
if (type->bake) {
engine->depsgraph = depsgraph;
/* update is only called so we create the engine.session */
2019-04-22 09:08:06 +10:00
if (type->update) {
type->update(engine, re->main, engine->depsgraph);
2019-04-22 09:08:06 +10:00
}
/* Bake all images. */
engine->bake.targets = targets;
engine->bake.pixels = pixel_array;
engine->bake.result = result;
engine->bake.object_id = object_id;
for (int i = 0; i < targets->images_num; i++) {
const BakeImage *image = &targets->images[i];
engine->bake.image_id = i;
type->bake(
engine, engine->depsgraph, object, pass_type, pass_filter, image->width, image->height);
}
/* Optionally let render images read bake images from disk delayed. */
if (type->render_frame_finish) {
engine->bake.image_id = 0;
type->render_frame_finish(engine);
}
memset(&engine->bake, 0, sizeof(engine->bake));
engine->depsgraph = nullptr;
2017-04-24 12:41:54 +02:00
}
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
engine->flag &= ~RE_ENGINE_RENDERING;
engine_depsgraph_free(engine);
RE_engine_free(engine);
re->engine = nullptr;
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
2019-04-22 09:08:06 +10:00
if (BKE_reports_contain(re->reports, RPT_ERROR)) {
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
G.is_break = true;
2019-04-22 09:08:06 +10:00
}
Bake API - bpy.ops.object.bake() New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api. The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result. The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit Python Operator: ---------------- The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False) Note: external save mode is currently disabled. Supported Features: ------------------ * Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture. * Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object. * Cage Extrusion - distance to use for the inward ray cast when using selected to active * Custom Cage - object to use as cage (instead of the lowpoly object). * Normal swizzle - change the axis that gets mapped to RGB * Normal space - save as tangent or object normal spaces Supported Passes: ----------------- Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled" Development Notes for External Engines: --------------------------------------- (read them in bake_api.c) * For a complete implementation example look at the Cycles Bake commit (next). Review: D421 Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge Normal map pipeline "consulting" by Andy Davies (metalliandy) Original design by Brecht van Lommel. The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
return true;
}
/* Render */
static bool possibly_using_gpu_compositor(const Render *re)
{
if (re->r.compositor_device != SCE_COMPOSITOR_DEVICE_GPU) {
return false;
}
const Scene *scene = re->pipeline_scene_eval;
return (scene->nodetree && scene->use_nodes && (scene->r.scemode & R_DOCOMP));
}
static void engine_render_view_layer(Render *re,
RenderEngine *engine,
ViewLayer *view_layer_iter,
const bool use_engine,
const bool use_grease_pencil)
{
/* Lock UI so scene can't be edited while we read from it in this render thread. */
re->draw_lock();
/* Create depsgraph with scene evaluated at render resolution. */
ViewLayer *view_layer = static_cast<ViewLayer *>(
BLI_findstring(&re->scene->view_layers, view_layer_iter->name, offsetof(ViewLayer, name)));
if (!re->prepare_viewlayer(view_layer, engine->depsgraph)) {
re->draw_unlock();
return;
Nodes: experimental node previews in the shader editor First implementation of node previews in the shader node editor. Using the same user interface as compositor node previews, most shader nodes can now be previewed (except group in/output and material output). This is currently still an experimental feature, as polishing of the user experience and performance improvements are planned. These will be easier to do as incremental changes on this implementation. See #110353 for details on the work that remains to be done and known limitations. Implementation notes: We take advantage of the `RenderResult` available as `ImBuf` images to store a `Render` for every viewed nested node tree present in a `SpaceNode`. The computation is initiated at the moment of drawing nodes overlays. One render is started for the current nodetree, having a `ViewLayer` associated with each previewed node. We separate the previewed nodes in two categories: the shader ones and the non-shader ones. - For non-shader nodes, we use AOVs which highly speed up the rendering process by rendering every non-shader nodes at the same time. They are rendered in the first `ViewLayer`. - For shader nodes, we render them each in a different `ViewLayer`, by rerouting the node to the output of the material in the preview scene. The preview scene takes the same aspect as the Material preview scene, and the same preview object is used. At the moment of drawing the node overlay, we take the `Render` of the viewed node tree and extract the `ImBuf` of the wanted viewlayer/pass for each previewed node. Pull Request: https://projects.blender.org/blender/blender/pulls/110065
2023-08-08 17:36:06 +02:00
}
engine_depsgraph_init(engine, view_layer);
/* Sync data to engine, within draw lock so scene data can be accessed safely. */
if (use_engine) {
const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT);
if (use_gpu_context) {
DRW_render_context_enable(engine->re);
}
else if (G.background && ((engine->has_grease_pencil && use_grease_pencil) ||
possibly_using_gpu_compositor(re)))
{
/* Workaround for specific NVidia drivers which crash on Linux when OptiX context is
* initialized prior to OpenGL context. This affects driver versions 545.29.06, 550.54.14,
* and 550.67 running on kernel 6.8.
*
* The idea here is to initialize GPU context before giving control to the render engine in
* cases when we know that the GPU context will definitely be needed later on.
*
* Only do it for background renders to avoid possible extra global locking during the
* context initialization. For the non-background renders the GPU context is already
* initialized for the Blender interface and no workaround is needed.
*
* Technically it is enough to only call WM_init_gpu() here, but it expects to only be called
* once, and from here it is not possible to know whether GPU sub-system is initialized or
* not. So instead temporarily enable the render context, which will take care of the GPU
* context initialization.
*
* For demo file and tracking progress of possible fixes on driver side refer to #120007. */
DRW_render_context_enable(engine->re);
DRW_render_context_disable(engine->re);
}
if (engine->type->update) {
engine->type->update(engine, re->main, engine->depsgraph);
}
if (use_gpu_context) {
DRW_render_context_disable(engine->re);
}
}
re->draw_unlock();
/* Perform render with engine. */
if (use_engine) {
const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT);
if (use_gpu_context) {
DRW_render_context_enable(engine->re);
}
BLI_mutex_lock(&engine->re->engine_draw_mutex);
re->engine->flag |= RE_ENGINE_CAN_DRAW;
BLI_mutex_unlock(&engine->re->engine_draw_mutex);
engine->type->render(engine, engine->depsgraph);
BLI_mutex_lock(&engine->re->engine_draw_mutex);
re->engine->flag &= ~RE_ENGINE_CAN_DRAW;
BLI_mutex_unlock(&engine->re->engine_draw_mutex);
if (use_gpu_context) {
DRW_render_context_disable(engine->re);
}
}
/* Optionally composite grease pencil over render result.
* Only do it if the passes are allocated (and the engine will not override the grease pencil
* when reading its result from EXR file and writing to the Blender side. */
if (engine->has_grease_pencil && use_grease_pencil && re->result->passes_allocated) {
/* NOTE: External engine might have been requested to free its
* dependency graph, which is only allowed if there is no grease
* pencil (pipeline is taking care of that). */
if (!RE_engine_test_break(engine) && engine->depsgraph != nullptr) {
DRW_render_gpencil(engine, engine->depsgraph);
}
}
/* Free dependency graph, if engine has not done it already. */
engine_depsgraph_exit(engine);
}
/* Callback function for engine_render_create_result to add all render passes to the result. */
static void engine_render_add_result_pass_cb(void *user_data,
Scene * /*scene*/,
ViewLayer *view_layer,
const char *name,
int channels,
const char *chanid,
eNodeSocketDatatype /*type*/)
{
RenderResult *rr = (RenderResult *)user_data;
RE_create_render_pass(rr, name, channels, chanid, view_layer->name, RR_ALL_VIEWS, false);
}
static RenderResult *engine_render_create_result(Render *re)
{
RenderResult *rr = render_result_new(re, &re->disprect, RR_ALL_LAYERS, RR_ALL_VIEWS);
if (rr == nullptr) {
return nullptr;
}
FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer) {
RE_engine_update_render_passes(
re->engine, re->scene, view_layer, engine_render_add_result_pass_cb, rr);
}
FOREACH_VIEW_LAYER_TO_RENDER_END;
/* Preview does not support deferred render result allocation. */
if (re->r.scemode & R_BUTS_PREVIEW) {
render_result_passes_allocated_ensure(rr);
}
return rr;
}
bool RE_engine_render(Render *re, bool do_all)
{
RenderEngineType *type = RE_engines_find(re->r.engine);
/* verify if we can render */
2019-04-22 09:08:06 +10:00
if (!type->render) {
return false;
2019-04-22 09:08:06 +10:00
}
if ((re->r.scemode & R_BUTS_PREVIEW) && !(type->flag & RE_USE_PREVIEW)) {
return false;
2019-04-22 09:08:06 +10:00
}
if (do_all && !(type->flag & RE_USE_POSTPROCESS)) {
return false;
2019-04-22 09:08:06 +10:00
}
if (!do_all && (type->flag & RE_USE_POSTPROCESS)) {
return false;
2019-04-22 09:08:06 +10:00
}
/* Lock drawing in UI during data phase. */
re->draw_lock();
if ((type->flag & RE_USE_GPU_CONTEXT) && !GPU_backend_supported()) {
/* Clear UI drawing locks. */
re->draw_unlock();
BKE_report(re->reports, RPT_ERROR, "Cannot initialize the GPU");
G.is_break = true;
return true;
}
/* Create engine. */
RenderEngine *engine = re->engine;
if (!engine) {
engine = RE_engine_create(type);
re->engine = engine;
}
/* Create render result. Do this before acquiring lock, to avoid lock
* inversion as this calls python to get the render passes, while python UI
* code can also hold a lock on the render result. */
const bool create_new_result = (re->result == nullptr || !(re->r.scemode & R_BUTS_PREVIEW));
RenderResult *new_result = (create_new_result) ? engine_render_create_result(re) : nullptr;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if (create_new_result) {
2019-04-22 09:08:06 +10:00
if (re->result) {
render_result_free(re->result);
2019-04-22 09:08:06 +10:00
}
re->result = new_result;
}
BLI_rw_mutex_unlock(&re->resultmutex);
if (re->result == nullptr) {
/* Clear UI drawing locks. */
re->draw_unlock();
/* Free engine. */
RE_engine_free(engine);
re->engine = nullptr;
/* Too small image is handled earlier, here it could only happen if
* there was no sufficient memory to allocate all passes.
*/
BKE_report(re->reports, RPT_ERROR, "Failed allocate render result, out of memory");
G.is_break = true;
return true;
}
/* set render info */
2012-06-16 16:57:16 +00:00
re->i.cfra = re->scene->r.cfra;
2023-05-09 12:50:37 +10:00
STRNCPY(re->i.scene_name, re->scene->id.name + 2);
engine->flag |= RE_ENGINE_RENDERING;
/* TODO: actually link to a parent which shouldn't happen */
2012-06-16 16:57:16 +00:00
engine->re = re;
2019-04-22 09:08:06 +10:00
if (re->flag & R_ANIMATION) {
engine->flag |= RE_ENGINE_ANIMATION;
2019-04-22 09:08:06 +10:00
}
if (re->r.scemode & R_BUTS_PREVIEW) {
engine->flag |= RE_ENGINE_PREVIEW;
2019-04-22 09:08:06 +10:00
}
engine->camera_override = re->camera_override;
engine->resolution_x = re->winx;
engine->resolution_y = re->winy;
/* Clear UI drawing locks. */
re->draw_unlock();
/* Render view layers. */
bool delay_grease_pencil = false;
if (type->render) {
FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
const bool use_grease_pencil = (view_layer_iter->layflag & SCE_LAY_GREASE_PENCIL) != 0;
engine_render_view_layer(re, engine, view_layer_iter, true, use_grease_pencil);
/* If render passes are not allocated the render engine deferred final pixels write for
* later. Need to defer the grease pencil for until after the engine has written the
* render result to Blender. */
delay_grease_pencil = use_grease_pencil && engine->has_grease_pencil &&
!re->result->passes_allocated;
if (RE_engine_test_break(engine)) {
break;
}
}
FOREACH_VIEW_LAYER_TO_RENDER_END;
}
if (type->render_frame_finish) {
type->render_frame_finish(engine);
}
/* Perform delayed grease pencil rendering. */
if (delay_grease_pencil) {
FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
const bool use_grease_pencil = (view_layer_iter->layflag & SCE_LAY_GREASE_PENCIL) != 0;
if (!use_grease_pencil) {
continue;
}
engine_render_view_layer(re, engine, view_layer_iter, false, true);
if (RE_engine_test_break(engine)) {
break;
}
}
FOREACH_VIEW_LAYER_TO_RENDER_END;
}
/* Clear tile data */
engine->flag &= ~RE_ENGINE_RENDERING;
render_result_free_list(&engine->fullresult,
static_cast<RenderResult *>(engine->fullresult.first));
/* re->engine becomes zero if user changed active render engine during render */
if (!engine_keep_depsgraph(engine) || !re->engine) {
engine_depsgraph_free(engine);
RE_engine_free(engine);
re->engine = nullptr;
}
if (re->r.scemode & R_EXR_CACHE_FILE) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
render_result_exr_file_cache_write(re);
BLI_rw_mutex_unlock(&re->resultmutex);
}
2019-04-22 09:08:06 +10:00
if (BKE_reports_contain(re->reports, RPT_ERROR)) {
G.is_break = true;
2019-04-22 09:08:06 +10:00
}
2014-06-27 14:56:21 +09:00
#ifdef WITH_FREESTYLE
2019-04-22 09:08:06 +10:00
if (re->r.mode & R_EDGE_FRS) {
2014-06-27 14:56:21 +09:00
RE_RenderFreestyleExternal(re);
2019-04-22 09:08:06 +10:00
}
2014-06-27 14:56:21 +09:00
#endif
return true;
}
void RE_engine_update_render_passes(RenderEngine *engine,
Scene *scene,
ViewLayer *view_layer,
update_render_passes_cb_t callback,
void *callback_data)
{
2019-01-18 01:47:32 +01:00
if (!(scene && view_layer && engine && callback && engine->type->update_render_passes)) {
return;
}
BLI_mutex_lock(&engine->update_render_passes_mutex);
engine->update_render_passes_cb = callback;
engine->update_render_passes_data = callback_data;
2019-01-18 01:47:32 +01:00
engine->type->update_render_passes(engine, scene, view_layer);
engine->update_render_passes_cb = nullptr;
engine->update_render_passes_data = nullptr;
BLI_mutex_unlock(&engine->update_render_passes_mutex);
}
void RE_engine_register_pass(RenderEngine *engine,
Scene *scene,
ViewLayer *view_layer,
const char *name,
int channels,
const char *chanid,
EEVEE: Render Passes This patch adds new render passes to EEVEE. These passes include: * Emission * Diffuse Light * Diffuse Color * Glossy Light * Glossy Color * Environment * Volume Scattering * Volume Transmission * Bloom * Shadow With these passes it will be possible to use EEVEE effectively for compositing. During development we kept a close eye on how to get similar results compared to cycles render passes there are some differences that are related to how EEVEE works. For EEVEE we combined the passes to `Diffuse` and `Specular`. There are no transmittance or sss passes anymore. Cycles will be changed accordingly. Cycles volume transmittance is added to multiple surface col passes. For EEVEE we left the volume transmittance as a separate pass. Known Limitations * All materials that use alpha blending will not be rendered in the render passes. Other transparency modes are supported. * More GPU memory is required to store the render passes. When rendering a HD image with all render passes enabled at max extra 570MB GPU memory is required. Implementation Details An overview of render passes have been described in https://wiki.blender.org/wiki/Source/Render/EEVEE/RenderPasses Future Developments * In this implementation the materials are re-rendered for Diffuse/Glossy and Emission passes. We could use multi target rendering to improve the render speed. * Other passes can be added later * Don't render material based passes when only requesting AO or Shadow. * Add more passes to the system. These could include Cryptomatte, AOV's, Vector, ObjectID, MaterialID, UV. Reviewed By: Clément Foucault Differential Revision: https://developer.blender.org/D6331
2020-02-20 14:53:53 +01:00
eNodeSocketDatatype type)
{
2019-01-18 01:47:32 +01:00
if (!(scene && view_layer && engine && engine->update_render_passes_cb)) {
return;
}
2019-03-01 19:29:26 +01:00
engine->update_render_passes_cb(
engine->update_render_passes_data, scene, view_layer, name, channels, chanid, type);
}
void RE_engine_free_blender_memory(RenderEngine *engine)
{
/* Weak way to save memory, but not crash grease pencil.
*
* TODO(sergey): Find better solution for this.
*/
if (engine->has_grease_pencil || engine_keep_depsgraph(engine)) {
return;
}
engine_depsgraph_free(engine);
}
RenderEngine *RE_engine_get(const Render *re)
{
return re->engine;
}
RenderEngine *RE_view_engine_get(const ViewRender *view_render)
{
return view_render->engine;
}
bool RE_engine_draw_acquire(Render *re)
{
RenderEngine *engine = re->engine;
if (!engine) {
2023-07-22 11:46:41 +10:00
/* No engine-side drawing if the engine does not exist. */
return false;
}
if (!engine->type->draw) {
/* Required callbacks are not implemented on the engine side. */
return false;
}
/* Lock before checking the flag, to avoid possible conflicts with the render thread. */
BLI_mutex_lock(&re->engine_draw_mutex);
if ((engine->flag & RE_ENGINE_CAN_DRAW) == 0) {
/* The rendering is not started yet, or has finished.
*
* In the former case there will nothing to be drawn, so can simply use RenderResult drawing
* pipeline. In the latter case the engine has destroyed its display-only resources (textures,
2023-10-13 10:21:06 +11:00
* graphics interops, etc..) so need to use the #RenderResult drawing pipeline. */
BLI_mutex_unlock(&re->engine_draw_mutex);
return false;
}
return true;
}
void RE_engine_draw_release(Render *re)
{
BLI_mutex_unlock(&re->engine_draw_mutex);
}
void RE_engine_tile_highlight_set(
RenderEngine *engine, int x, int y, int width, int height, bool highlight)
{
if (!engine->re) {
/* No render on the engine, so nowhere to store the highlighted tiles information. */
return;
}
if ((engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
/* Engine reported it does not support tiles highlight, but attempted to set the highlight.
* Technically it is a logic error, but there is no good way to inform an external engine about
* it. */
return;
}
blender::render::TilesHighlight *tile_highlight = engine->re->get_tile_highlight();
if (!tile_highlight) {
/* The renderer itself does not support tiles highlight. */
return;
}
if (highlight) {
tile_highlight->highlight_tile(x, y, width, height);
}
else {
tile_highlight->unhighlight_tile(x, y, width, height);
}
}
void RE_engine_tile_highlight_clear_all(RenderEngine *engine)
{
if (!engine->re) {
/* No render on the engine, so nowhere to store the highlighted tiles information. */
return;
}
if ((engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
/* Engine reported it does not support tiles highlight, but attempted to set the highlight.
* Technically it is a logic error, but there is no good way to inform an external engine about
* it. */
return;
}
blender::render::TilesHighlight *tile_highlight = engine->re->get_tile_highlight();
if (!tile_highlight) {
/* The renderer itself does not support tiles highlight. */
return;
}
tile_highlight->clear();
}
/* -------------------------------------------------------------------- */
/** \name GPU context manipulation.
*
* GPU context for engine to create and update GPU resources in its own thread,
* without blocking the main thread. Used by Cycles' display driver to create
* display textures.
*
* \{ */
bool RE_engine_gpu_context_create(RenderEngine *engine)
{
/* If the there already is a draw manager render context available, reuse it. */
engine->use_drw_render_context = (engine->re && RE_system_gpu_context_get(engine->re));
if (engine->use_drw_render_context) {
return true;
}
/* Viewport render case where no render context is available. We are expected to be on
* the main thread here to safely create a context. */
BLI_assert(BLI_thread_is_main());
const bool drw_state = DRW_gpu_context_release();
engine->system_gpu_context = WM_system_gpu_context_create();
if (engine->system_gpu_context) {
/* Activate new GPU Context for GPUContext creation. */
WM_system_gpu_context_activate(engine->system_gpu_context);
/* Requires GPUContext for usage of GPU Module for displaying results. */
engine->blender_gpu_context = GPU_context_create(nullptr, engine->system_gpu_context);
GPU_context_active_set(nullptr);
/* Deactivate newly created GPU Context, as it is not needed until
* `RE_engine_gpu_context_enable` is called. */
WM_system_gpu_context_release(engine->system_gpu_context);
}
else {
engine->blender_gpu_context = nullptr;
}
DRW_gpu_context_activate(drw_state);
return engine->system_gpu_context != nullptr;
}
void RE_engine_gpu_context_destroy(RenderEngine *engine)
{
if (!engine->system_gpu_context) {
return;
}
const bool drw_state = DRW_gpu_context_release();
WM_system_gpu_context_activate(engine->system_gpu_context);
if (engine->blender_gpu_context) {
GPUContext *restore_context = GPU_context_active_get();
GPU_context_active_set(engine->blender_gpu_context);
GPU_context_discard(engine->blender_gpu_context);
if (restore_context != engine->blender_gpu_context) {
GPU_context_active_set(restore_context);
}
engine->blender_gpu_context = nullptr;
}
WM_system_gpu_context_dispose(engine->system_gpu_context);
engine->system_gpu_context = nullptr;
DRW_gpu_context_activate(drw_state);
}
bool RE_engine_gpu_context_enable(RenderEngine *engine)
{
engine->gpu_restore_context = false;
if (engine->use_drw_render_context) {
DRW_render_context_enable(engine->re);
return true;
}
if (engine->system_gpu_context) {
BLI_mutex_lock(&engine->blender_gpu_context_mutex);
/* If a previous GPU/GPUContext was active (DST.blender_gpu_context), we should later
* restore this when disabling the RenderEngine context. */
engine->gpu_restore_context = DRW_gpu_context_release();
/* Activate RenderEngine System and Blender GPU Context. */
WM_system_gpu_context_activate(engine->system_gpu_context);
if (engine->blender_gpu_context) {
GPU_render_begin();
GPU_context_active_set(engine->blender_gpu_context);
}
return true;
}
return false;
}
void RE_engine_gpu_context_disable(RenderEngine *engine)
{
if (engine->use_drw_render_context) {
DRW_render_context_disable(engine->re);
}
else {
if (engine->system_gpu_context) {
if (engine->blender_gpu_context) {
GPU_context_active_set(nullptr);
GPU_render_end();
}
WM_system_gpu_context_release(engine->system_gpu_context);
/* Restore DRW state context if previously active. */
DRW_gpu_context_activate(engine->gpu_restore_context);
BLI_mutex_unlock(&engine->blender_gpu_context_mutex);
}
}
}
void RE_engine_gpu_context_lock(RenderEngine *engine)
{
if (engine->use_drw_render_context) {
/* Locking already handled by the draw manager. */
}
else {
if (engine->system_gpu_context) {
BLI_mutex_lock(&engine->blender_gpu_context_mutex);
}
}
}
void RE_engine_gpu_context_unlock(RenderEngine *engine)
{
if (engine->use_drw_render_context) {
/* Locking already handled by the draw manager. */
}
else {
if (engine->system_gpu_context) {
BLI_mutex_unlock(&engine->blender_gpu_context_mutex);
}
}
}
/** \} */