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
This commit is contained in:
Dalai Felinto 2014-01-02 19:05:07 -02:00
parent 3312b20ac8
commit 97641a0ec9
Notes: blender-bot 2023-04-04 07:45:26 +02:00
Referenced by issue #57143, Can't bake to external textures (Python)
21 changed files with 2743 additions and 280 deletions

View File

@ -127,6 +127,9 @@ bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const cha
float (*BKE_mesh_vertexCos_get(struct Mesh *me, int *r_numVerts))[3];
struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Scene *sce, struct Object *ob,
int apply_modifiers, int settings, int calc_tessface, int calc_undeformed);
/* vertex level transformations & checks (no derived mesh) */
bool BKE_mesh_minmax(struct Mesh *me, float r_min[3], float r_max[3]);

View File

@ -53,6 +53,8 @@
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_key.h"
#include "BKE_mball.h"
#include "BKE_depsgraph.h"
/* these 2 are only used by conversion functions */
#include "BKE_curve.h"
/* -- */
@ -2085,3 +2087,220 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
BLI_assert((me->mselect[me->totselect - 1].index == index) &&
(me->mselect[me->totselect - 1].type == type));
}
/* settings: 1 - preview, 2 - render */
Mesh *BKE_mesh_new_from_object(
Main *bmain, Scene *sce, Object *ob,
int apply_modifiers, int settings, int calc_tessface, int calc_undeformed)
{
Mesh *tmpmesh;
Curve *tmpcu = NULL, *copycu;
Object *tmpobj = NULL;
int render = settings == eModifierMode_Render, i;
int cage = !apply_modifiers;
/* perform the mesh extraction based on type */
switch (ob->type) {
case OB_FONT:
case OB_CURVE:
case OB_SURF:
{
ListBase dispbase = {NULL, NULL};
DerivedMesh *derivedFinal = NULL;
int uv_from_orco;
/* copies object and modifiers (but not the data) */
tmpobj = BKE_object_copy_ex(bmain, ob, true);
tmpcu = (Curve *)tmpobj->data;
tmpcu->id.us--;
/* if getting the original caged mesh, delete object modifiers */
if (cage)
BKE_object_free_modifiers(tmpobj);
/* copies the data */
copycu = tmpobj->data = BKE_curve_copy((Curve *) ob->data);
/* temporarily set edit so we get updates from edit mode, but
* also because for text datablocks copying it while in edit
* mode gives invalid data structures */
copycu->editfont = tmpcu->editfont;
copycu->editnurb = tmpcu->editnurb;
/* get updated display list, and convert to a mesh */
BKE_displist_make_curveTypes_forRender(sce, tmpobj, &dispbase, &derivedFinal, false, render);
copycu->editfont = NULL;
copycu->editnurb = NULL;
tmpobj->derivedFinal = derivedFinal;
/* convert object type to mesh */
uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
BKE_mesh_from_nurbs_displist(tmpobj, &dispbase, uv_from_orco);
tmpmesh = tmpobj->data;
BKE_displist_free(&dispbase);
/* BKE_mesh_from_nurbs changes the type to a mesh, check it worked.
* if it didn't the curve did not have any segments or otherwise
* would have generated an empty mesh */
if (tmpobj->type != OB_MESH) {
BKE_libblock_free_us(G.main, tmpobj);
return NULL;
}
BKE_mesh_texspace_copy_from_object(tmpmesh, ob);
BKE_libblock_free_us(bmain, tmpobj);
break;
}
case OB_MBALL:
{
/* metaballs don't have modifiers, so just convert to mesh */
Object *basis_ob = BKE_mball_basis_find(sce, ob);
/* todo, re-generatre for render-res */
/* metaball_polygonize(scene, ob) */
if (ob != basis_ob)
return NULL; /* only do basis metaball */
tmpmesh = BKE_mesh_add(bmain, "Mesh");
/* BKE_mesh_add gives us a user count we don't need */
tmpmesh->id.us--;
if (render) {
ListBase disp = {NULL, NULL};
/* TODO(sergey): This is gonna to work for until EvaluationContext
* only contains for_render flag. As soon as CoW is
* implemented, this is to be rethinked.
*/
EvaluationContext eval_ctx = {0};
eval_ctx.for_render = render;
BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
}
else {
ListBase disp = {NULL, NULL};
if (ob->curve_cache) {
disp = ob->curve_cache->disp;
}
BKE_mesh_from_metaball(&disp, tmpmesh);
}
BKE_mesh_texspace_copy_from_object(tmpmesh, ob);
break;
}
case OB_MESH:
/* copies object and modifiers (but not the data) */
if (cage) {
/* copies the data */
tmpmesh = BKE_mesh_copy_ex(bmain, ob->data);
/* if not getting the original caged mesh, get final derived mesh */
}
else {
/* Make a dummy mesh, saves copying */
DerivedMesh *dm;
/* CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; */
CustomDataMask mask = CD_MASK_MESH; /* this seems more suitable, exporter,
* for example, needs CD_MASK_MDEFORMVERT */
if (calc_undeformed)
mask |= CD_MASK_ORCO;
/* Write the display mesh into the dummy mesh */
if (render)
dm = mesh_create_derived_render(sce, ob, mask);
else
dm = mesh_create_derived_view(sce, ob, mask);
tmpmesh = BKE_mesh_add(bmain, "Mesh");
DM_to_mesh(dm, tmpmesh, ob, mask);
dm->release(dm);
}
/* BKE_mesh_add/copy gives us a user count we don't need */
tmpmesh->id.us--;
break;
default:
/* "Object does not have geometry data") */
return NULL;
}
/* Copy materials to new mesh */
switch (ob->type) {
case OB_SURF:
case OB_FONT:
case OB_CURVE:
tmpmesh->totcol = tmpcu->totcol;
/* free old material list (if it exists) and adjust user counts */
if (tmpcu->mat) {
for (i = tmpcu->totcol; i-- > 0; ) {
/* are we an object material or data based? */
tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpcu->mat[i];
if (tmpmesh->mat[i]) {
tmpmesh->mat[i]->id.us++;
}
}
}
break;
#if 0
/* Crashes when assigning the new material, not sure why */
case OB_MBALL:
tmpmb = (MetaBall *)ob->data;
tmpmesh->totcol = tmpmb->totcol;
/* free old material list (if it exists) and adjust user counts */
if (tmpmb->mat) {
for (i = tmpmb->totcol; i-- > 0; ) {
tmpmesh->mat[i] = tmpmb->mat[i]; /* CRASH HERE ??? */
if (tmpmesh->mat[i]) {
tmpmb->mat[i]->id.us++;
}
}
}
break;
#endif
case OB_MESH:
if (!cage) {
Mesh *origmesh = ob->data;
tmpmesh->flag = origmesh->flag;
tmpmesh->mat = MEM_dupallocN(origmesh->mat);
tmpmesh->totcol = origmesh->totcol;
tmpmesh->smoothresh = origmesh->smoothresh;
if (origmesh->mat) {
for (i = origmesh->totcol; i-- > 0; ) {
/* are we an object material or data based? */
tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i];
if (tmpmesh->mat[i]) {
tmpmesh->mat[i]->id.us++;
}
}
}
}
break;
} /* end copy materials */
if (calc_tessface) {
/* cycles and exporters rely on this still */
BKE_mesh_tessface_ensure(tmpmesh);
}
/* make sure materials get updated in objects */
test_object_materials(bmain, &tmpmesh->id);
return tmpmesh;
}

View File

@ -469,6 +469,23 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->r.bake_normal_space = R_BAKE_SPACE_TANGENT;
sce->r.bake_samples = 256;
sce->r.bake_biasdist = 0.001;
sce->r.bake.flag = R_BAKE_CLEAR;
sce->r.bake.width = 512;
sce->r.bake.height = 512;
sce->r.bake.margin = 16;
sce->r.bake.normal_space = R_BAKE_SPACE_TANGENT;
sce->r.bake.normal_swizzle[0] = R_BAKE_POSX;
sce->r.bake.normal_swizzle[1] = R_BAKE_POSY;
sce->r.bake.normal_swizzle[2] = R_BAKE_POSZ;
BLI_strncpy(sce->r.bake.filepath, U.renderdir, sizeof(sce->r.bake.filepath));
sce->r.bake.im_format.planes = R_IMF_PLANES_RGBA;
sce->r.bake.im_format.imtype = R_IMF_IMTYPE_PNG;
sce->r.bake.im_format.depth = R_IMF_CHAN_DEPTH_8;
sce->r.bake.im_format.quality = 90;
sce->r.bake.im_format.compress = 15;
sce->r.scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION;
sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME;
sce->r.stamp_font_id = 12;

View File

@ -51,6 +51,9 @@
#include "BKE_main.h"
#include "BKE_node.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLO_readfile.h"
#include "readfile.h"
@ -254,4 +257,26 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
for (ma = main->mat.first; ma; ma = ma->id.next)
ma->mode2 = MA_CASTSHADOW;
}
if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "BakeData", "bake")) {
Scene *sce;
for (sce = main->scene.first; sce; sce = sce->id.next) {
sce->r.bake.flag = R_BAKE_CLEAR;
sce->r.bake.width = 512;
sce->r.bake.height = 512;
sce->r.bake.margin = 16;
sce->r.bake.normal_space = R_BAKE_SPACE_TANGENT;
sce->r.bake.normal_swizzle[0] = R_BAKE_POSX;
sce->r.bake.normal_swizzle[1] = R_BAKE_POSY;
sce->r.bake.normal_swizzle[2] = R_BAKE_POSZ;
BLI_strncpy(sce->r.bake.filepath, U.renderdir, sizeof(sce->r.bake.filepath));
sce->r.bake.im_format.planes = R_IMF_PLANES_RGBA;
sce->r.bake.im_format.imtype = R_IMF_IMTYPE_PNG;
sce->r.bake.im_format.depth = R_IMF_CHAN_DEPTH_8;
sce->r.bake.im_format.quality = 90;
sce->r.bake.im_format.compress = 15;
}
}
}

View File

@ -42,6 +42,7 @@ set(INC_SYS
set(SRC
object_add.c
object_bake.c
object_bake_api.c
object_constraint.c
object_edit.c
object_group.c

View File

@ -79,6 +79,7 @@
#include "WM_types.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "object_intern.h"
@ -893,4 +894,5 @@ void OBJECT_OT_bake_image(wmOperatorType *ot)
ot->exec = bake_image_exec;
ot->invoke = objects_bake_render_invoke;
ot->modal = objects_bake_render_modal;
ot->poll = ED_operator_object_active;
}

File diff suppressed because it is too large Load Diff

View File

@ -254,6 +254,7 @@ void OBJECT_OT_group_remove(struct wmOperatorType *ot);
/* object_bake.c */
void OBJECT_OT_bake_image(wmOperatorType *ot);
void OBJECT_OT_bake(wmOperatorType *ot);
/* object_lod.c */
void OBJECT_OT_lod_add(struct wmOperatorType *ot);

View File

@ -239,6 +239,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_hook_recenter);
WM_operatortype_append(OBJECT_OT_bake_image);
WM_operatortype_append(OBJECT_OT_bake);
WM_operatortype_append(OBJECT_OT_drop_named_material);
WM_operatortype_append(OBJECT_OT_laplaciandeform_bind);

View File

@ -210,37 +210,39 @@ typedef struct SceneRenderLayer {
#define SCE_LAY_NEG_ZMASK 0x80000
/* srl->passflag */
#define SCE_PASS_COMBINED (1<<0)
#define SCE_PASS_Z (1<<1)
#define SCE_PASS_RGBA (1<<2)
#define SCE_PASS_DIFFUSE (1<<3)
#define SCE_PASS_SPEC (1<<4)
#define SCE_PASS_SHADOW (1<<5)
#define SCE_PASS_AO (1<<6)
#define SCE_PASS_REFLECT (1<<7)
#define SCE_PASS_NORMAL (1<<8)
#define SCE_PASS_VECTOR (1<<9)
#define SCE_PASS_REFRACT (1<<10)
#define SCE_PASS_INDEXOB (1<<11)
#define SCE_PASS_UV (1<<12)
#define SCE_PASS_INDIRECT (1<<13)
#define SCE_PASS_MIST (1<<14)
#define SCE_PASS_RAYHITS (1<<15)
#define SCE_PASS_EMIT (1<<16)
#define SCE_PASS_ENVIRONMENT (1<<17)
#define SCE_PASS_INDEXMA (1<<18)
#define SCE_PASS_DIFFUSE_DIRECT (1<<19)
#define SCE_PASS_DIFFUSE_INDIRECT (1<<20)
#define SCE_PASS_DIFFUSE_COLOR (1<<21)
#define SCE_PASS_GLOSSY_DIRECT (1<<22)
#define SCE_PASS_GLOSSY_INDIRECT (1<<23)
#define SCE_PASS_GLOSSY_COLOR (1<<24)
#define SCE_PASS_TRANSM_DIRECT (1<<25)
#define SCE_PASS_TRANSM_INDIRECT (1<<26)
#define SCE_PASS_TRANSM_COLOR (1<<27)
#define SCE_PASS_SUBSURFACE_DIRECT (1<<28)
#define SCE_PASS_SUBSURFACE_INDIRECT (1<<29)
#define SCE_PASS_SUBSURFACE_COLOR (1<<30)
typedef enum ScenePassType {
SCE_PASS_COMBINED = (1 << 0),
SCE_PASS_Z = (1 << 1),
SCE_PASS_RGBA = (1 << 2),
SCE_PASS_DIFFUSE = (1 << 3),
SCE_PASS_SPEC = (1 << 4),
SCE_PASS_SHADOW = (1 << 5),
SCE_PASS_AO = (1 << 6),
SCE_PASS_REFLECT = (1 << 7),
SCE_PASS_NORMAL = (1 << 8),
SCE_PASS_VECTOR = (1 << 9),
SCE_PASS_REFRACT = (1 << 10),
SCE_PASS_INDEXOB = (1 << 11),
SCE_PASS_UV = (1 << 12),
SCE_PASS_INDIRECT = (1 << 13),
SCE_PASS_MIST = (1 << 14),
SCE_PASS_RAYHITS = (1 << 15),
SCE_PASS_EMIT = (1 << 16),
SCE_PASS_ENVIRONMENT = (1 << 17),
SCE_PASS_INDEXMA = (1 << 18),
SCE_PASS_DIFFUSE_DIRECT = (1 << 19),
SCE_PASS_DIFFUSE_INDIRECT = (1 << 20),
SCE_PASS_DIFFUSE_COLOR = (1 << 21),
SCE_PASS_GLOSSY_DIRECT = (1 << 22),
SCE_PASS_GLOSSY_INDIRECT = (1 << 23),
SCE_PASS_GLOSSY_COLOR = (1 << 24),
SCE_PASS_TRANSM_DIRECT = (1 << 25),
SCE_PASS_TRANSM_INDIRECT = (1 << 26),
SCE_PASS_TRANSM_COLOR = (1 << 27),
SCE_PASS_SUBSURFACE_DIRECT = (1 << 28),
SCE_PASS_SUBSURFACE_INDIRECT = (1 << 29),
SCE_PASS_SUBSURFACE_COLOR = (1 << 30),
} ScenePassType;
/* note, srl->passflag is treestore element 'nr' in outliner, short still... */
@ -358,6 +360,42 @@ typedef struct ImageFormatData {
/* ImageFormatData.cineon_flag */
#define R_IMF_CINEON_FLAG_LOG (1<<0) /* was R_CINEON_LOG */
typedef struct BakeData {
struct ImageFormatData im_format;
char filepath[1024]; /* FILE_MAX */
short width, height;
short margin, flag;
float cage_extrusion;
float pad2;
char normal_swizzle[3];
char normal_space;
char save_mode;
char pad[3];
char cage[64]; /* MAX_NAME */
} BakeData;
/* (char) normal_swizzle */
typedef enum BakeNormalSwizzle {
R_BAKE_POSX = 0,
R_BAKE_POSY = 1,
R_BAKE_POSZ = 2,
R_BAKE_NEGX = 3,
R_BAKE_NEGY = 4,
R_BAKE_NEGZ = 5,
} BakeNormalSwizzle;
/* (char) save_mode */
typedef enum BakeSaveMode {
R_BAKE_SAVE_INTERNAL = 0,
R_BAKE_SAVE_EXTERNAL = 1,
} BakeSaveMode;
/* *************************************************************** */
/* Render Data */
@ -563,6 +601,9 @@ typedef struct RenderData {
/* render engine */
char engine[32];
/* Cycles baking */
struct BakeData bake;
} RenderData;
/* *************************************************************** */
@ -1401,6 +1442,8 @@ enum {
#define R_BAKE_LORES_MESH 32
#define R_BAKE_VCOL 64
#define R_BAKE_USERSCALE 128
#define R_BAKE_SPLIT_MAT 256
#define R_BAKE_AUTO_NAME 512
/* bake_normal_space */
#define R_BAKE_SPACE_CAMERA 0

View File

@ -65,9 +65,14 @@ extern EnumPropertyItem modifier_triangulate_ngon_method_items[];
extern EnumPropertyItem image_type_items[];
extern EnumPropertyItem image_color_mode_items[];
extern EnumPropertyItem image_depth_mode_items[];
extern EnumPropertyItem image_color_depth_items[];
extern EnumPropertyItem image_generated_type_items[];
extern EnumPropertyItem normal_space_items[];
extern EnumPropertyItem normal_swizzle_items[];
extern EnumPropertyItem bake_save_mode_items[];
extern EnumPropertyItem exr_codec_items[];
extern EnumPropertyItem color_sets_items[];
extern EnumPropertyItem beztriple_keyframe_type_items[];
@ -119,6 +124,8 @@ extern EnumPropertyItem object_axis_unsigned_items[];
extern EnumPropertyItem controller_type_items[];
extern EnumPropertyItem render_pass_type_items[];
extern EnumPropertyItem keymap_propvalue_items[];
extern EnumPropertyItem operator_context_items[];

View File

@ -292,216 +292,19 @@ Mesh *rna_Main_meshes_new_from_object(
Main *bmain, ReportList *reports, Scene *sce,
Object *ob, int apply_modifiers, int settings, int calc_tessface, int calc_undeformed)
{
Mesh *tmpmesh;
Curve *tmpcu = NULL, *copycu;
Object *tmpobj = NULL;
const bool use_render_resolution = (settings == eModifierMode_Render);
int i;
int cage = !apply_modifiers;
/* perform the mesh extraction based on type */
switch (ob->type) {
case OB_FONT:
case OB_CURVE:
case OB_SURF:
{
ListBase dispbase = {NULL, NULL};
DerivedMesh *derivedFinal = NULL;
int uv_from_orco;
/* copies object and modifiers (but not the data) */
tmpobj = BKE_object_copy_ex(bmain, ob, true);
tmpcu = (Curve *)tmpobj->data;
tmpcu->id.us--;
/* if getting the original caged mesh, delete object modifiers */
if (cage)
BKE_object_free_modifiers(tmpobj);
/* copies the data */
copycu = tmpobj->data = BKE_curve_copy((Curve *) ob->data);
/* temporarily set edit so we get updates from edit mode, but
* also because for text datablocks copying it while in edit
* mode gives invalid data structures */
copycu->editfont = tmpcu->editfont;
copycu->editnurb = tmpcu->editnurb;
/* get updated display list, and convert to a mesh */
BKE_displist_make_curveTypes_forRender(sce, tmpobj, &dispbase, &derivedFinal, false, use_render_resolution);
copycu->editfont = NULL;
copycu->editnurb = NULL;
tmpobj->derivedFinal = derivedFinal;
/* convert object type to mesh */
uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
BKE_mesh_from_nurbs_displist(tmpobj, &dispbase, uv_from_orco);
tmpmesh = tmpobj->data;
BKE_displist_free(&dispbase);
/* BKE_mesh_from_nurbs changes the type to a mesh, check it worked.
* if it didn't the curve did not have any segments or otherwise
* would have generated an empty mesh */
if (tmpobj->type != OB_MESH) {
BKE_libblock_free_us(G.main, tmpobj);
return NULL;
}
BKE_mesh_texspace_copy_from_object(tmpmesh, ob);
BKE_libblock_free_us(bmain, tmpobj);
break;
}
case OB_MBALL:
{
/* metaballs don't have modifiers, so just convert to mesh */
Object *basis_ob = BKE_mball_basis_find(sce, ob);
/* todo, re-generatre for render-res */
/* metaball_polygonize(scene, ob) */
if (ob != basis_ob)
return NULL; /* only do basis metaball */
tmpmesh = BKE_mesh_add(bmain, "Mesh");
/* BKE_mesh_add gives us a user count we don't need */
tmpmesh->id.us--;
if (use_render_resolution) {
ListBase disp = {NULL, NULL};
/* TODO(sergey): This is gonna to work for until EvaluationContext
* only contains for_render flag. As soon as CoW is
* implemented, this is to be rethinked.
*/
EvaluationContext eval_ctx = {0};
eval_ctx.for_render = use_render_resolution;
BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
}
else {
ListBase disp = {NULL, NULL};
if (ob->curve_cache) {
disp = ob->curve_cache->disp;
}
BKE_mesh_from_metaball(&disp, tmpmesh);
}
BKE_mesh_texspace_copy_from_object(tmpmesh, ob);
break;
}
case OB_MESH:
/* copies object and modifiers (but not the data) */
if (cage) {
/* copies the data */
tmpmesh = BKE_mesh_copy_ex(bmain, ob->data);
/* if not getting the original caged mesh, get final derived mesh */
}
else {
/* Make a dummy mesh, saves copying */
DerivedMesh *dm;
/* CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; */
CustomDataMask mask = CD_MASK_MESH; /* this seems more suitable, exporter,
* for example, needs CD_MASK_MDEFORMVERT */
if (calc_undeformed)
mask |= CD_MASK_ORCO;
/* Write the display mesh into the dummy mesh */
if (use_render_resolution)
dm = mesh_create_derived_render(sce, ob, mask);
else
dm = mesh_create_derived_view(sce, ob, mask);
tmpmesh = BKE_mesh_add(bmain, "Mesh");
DM_to_mesh(dm, tmpmesh, ob, mask);
dm->release(dm);
}
/* BKE_mesh_add/copy gives us a user count we don't need */
tmpmesh->id.us--;
break;
default:
BKE_report(reports, RPT_ERROR, "Object does not have geometry data");
return NULL;
}
/* Copy materials to new mesh */
switch (ob->type) {
case OB_SURF:
case OB_FONT:
case OB_CURVE:
tmpmesh->totcol = tmpcu->totcol;
/* free old material list (if it exists) and adjust user counts */
if (tmpcu->mat) {
for (i = tmpcu->totcol; i-- > 0; ) {
/* are we an object material or data based? */
tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpcu->mat[i];
if (tmpmesh->mat[i]) {
tmpmesh->mat[i]->id.us++;
}
}
}
break;
#if 0
/* Crashes when assigning the new material, not sure why */
case OB_MBALL:
tmpmb = (MetaBall *)ob->data;
tmpmesh->totcol = tmpmb->totcol;
/* free old material list (if it exists) and adjust user counts */
if (tmpmb->mat) {
for (i = tmpmb->totcol; i-- > 0; ) {
tmpmesh->mat[i] = tmpmb->mat[i]; /* CRASH HERE ??? */
if (tmpmesh->mat[i]) {
tmpmb->mat[i]->id.us++;
}
}
}
break;
#endif
case OB_MESH:
if (!cage) {
Mesh *origmesh = ob->data;
tmpmesh->flag = origmesh->flag;
tmpmesh->mat = MEM_dupallocN(origmesh->mat);
tmpmesh->totcol = origmesh->totcol;
tmpmesh->smoothresh = origmesh->smoothresh;
if (origmesh->mat) {
for (i = origmesh->totcol; i-- > 0; ) {
/* are we an object material or data based? */
tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i];
if (tmpmesh->mat[i]) {
tmpmesh->mat[i]->id.us++;
}
}
}
}
break;
} /* end copy materials */
if (calc_tessface) {
/* cycles and exporters rely on this still */
BKE_mesh_tessface_ensure(tmpmesh);
}
/* make sure materials get updated in objects */
test_object_materials(bmain, &tmpmesh->id);
return tmpmesh;
return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed);
}
static void rna_Main_meshes_remove(Main *bmain, ReportList *reports, PointerRNA *mesh_ptr)

View File

@ -38,8 +38,42 @@
#include "RE_engine.h"
#include "RE_pipeline.h"
#include "RE_engine.h"
EnumPropertyItem render_pass_type_items[] = {
{SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
{SCE_PASS_Z, "Z", 0, "Z", ""},
{SCE_PASS_RGBA, "COLOR", 0, "Color", ""},
{SCE_PASS_DIFFUSE, "DIFFUSE", 0, "Diffuse", ""},
{SCE_PASS_SPEC, "SPECULAR", 0, "Specular", ""},
{SCE_PASS_SHADOW, "SHADOW", 0, "Shadow", ""},
{SCE_PASS_AO, "AO", 0, "AO", ""},
{SCE_PASS_REFLECT, "REFLECTION", 0, "Reflection", ""},
{SCE_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
{SCE_PASS_VECTOR, "VECTOR", 0, "Vector", ""},
{SCE_PASS_REFRACT, "REFRACTION", 0, "Refraction", ""},
{SCE_PASS_INDEXOB, "OBJECT_INDEX", 0, "Object Index", ""},
{SCE_PASS_UV, "UV", 0, "UV", ""},
{SCE_PASS_MIST, "MIST", 0, "Mist", ""},
{SCE_PASS_EMIT, "EMIT", 0, "Emit", ""},
{SCE_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""},
{SCE_PASS_INDEXMA, "MATERIAL_INDEX", 0, "Material Index", ""},
{SCE_PASS_DIFFUSE_DIRECT, "DIFFUSE_DIRECT", 0, "Diffuse Direct", ""},
{SCE_PASS_DIFFUSE_INDIRECT, "DIFFUSE_INDIRECT", 0, "Diffuse Indirect", ""},
{SCE_PASS_DIFFUSE_COLOR, "DIFFUSE_COLOR", 0, "Diffuse Color", ""},
{SCE_PASS_GLOSSY_DIRECT, "GLOSSY_DIRECT", 0, "Glossy Direct", ""},
{SCE_PASS_GLOSSY_INDIRECT, "GLOSSY_INDIRECT", 0, "Glossy Indirect", ""},
{SCE_PASS_GLOSSY_COLOR, "GLOSSY_COLOR", 0, "Glossy Color", ""},
{SCE_PASS_TRANSM_DIRECT, "TRANSMISSION_DIRECT", 0, "Transmission Direct", ""},
{SCE_PASS_TRANSM_INDIRECT, "TRANSMISSION_INDIRECT", 0, "Transmission Indirect", ""},
{SCE_PASS_TRANSM_COLOR, "TRANSMISSION_COLOR", 0, "Transmission Color", ""},
{SCE_PASS_SUBSURFACE_DIRECT, "SUBSURFACE_DIRECT", 0, "Subsurface Direct", ""},
{SCE_PASS_SUBSURFACE_INDIRECT, "SUBSURFACE_INDIRECT", 0, "Subsurface Indirect", ""},
{SCE_PASS_SUBSURFACE_COLOR, "SUBSURFACE_COLOR", 0, "Subsurface Color", ""},
{0, NULL, 0, NULL, NULL}
};
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
@ -117,6 +151,30 @@ static void engine_render(RenderEngine *engine, struct Scene *scene)
RNA_parameter_list_free(&list);
}
static void engine_bake(RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type,
const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result)
{
extern FunctionRNA rna_RenderEngine_bake_func;
PointerRNA ptr;
ParameterList list;
FunctionRNA *func;
RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
func = &rna_RenderEngine_bake_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "scene", &scene);
RNA_parameter_set_lookup(&list, "object", &object);
RNA_parameter_set_lookup(&list, "pass_type", &pass_type);
RNA_parameter_set_lookup(&list, "pixel_array", &pixel_array);
RNA_parameter_set_lookup(&list, "num_pixels", &num_pixels);
RNA_parameter_set_lookup(&list, "depth", &depth);
RNA_parameter_set_lookup(&list, "result", &result);
engine->type->ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
static void engine_view_update(RenderEngine *engine, const struct bContext *context)
{
extern FunctionRNA rna_RenderEngine_view_update_func;
@ -189,7 +247,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
RenderEngineType *et, dummyet = {NULL};
RenderEngine dummyengine = {NULL};
PointerRNA dummyptr;
int have_function[5];
int have_function[6];
/* setup dummy engine & engine type to store static properties in */
dummyengine.type = &dummyet;
@ -226,9 +284,10 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
et->update = (have_function[0]) ? engine_update : NULL;
et->render = (have_function[1]) ? engine_render : NULL;
et->view_update = (have_function[2]) ? engine_view_update : NULL;
et->view_draw = (have_function[3]) ? engine_view_draw : NULL;
et->update_script_node = (have_function[4]) ? engine_update_script_node : NULL;
et->bake = (have_function[2]) ? engine_bake : NULL;
et->view_update = (have_function[3]) ? engine_view_update : NULL;
et->view_draw = (have_function[4]) ? engine_view_draw : NULL;
et->update_script_node = (have_function[5]) ? engine_update_script_node : NULL;
BLI_addtail(&R_engines, et);
@ -317,6 +376,12 @@ void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values)
memcpy(rpass->rect, values, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels);
}
static PointerRNA rna_BakePixel_next_get(PointerRNA *ptr)
{
BakePixel *bp = ptr->data;
return rna_pointer_inherit_refine(ptr, &RNA_BakePixel, bp + 1);
}
#else /* RNA_RUNTIME */
static void rna_def_render_engine(BlenderRNA *brna)
@ -344,6 +409,25 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
RNA_def_pointer(func, "scene", "Scene", "", "");
func = RNA_def_function(srna, "bake", NULL);
RNA_def_function_ui_description(func, "Bake passes");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
prop = RNA_def_pointer(func, "scene", "Scene", "", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_pointer(func, "object", "Object", "", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_enum(func, "pass_type", render_pass_type_items, 0, "Pass", "Pass to bake");
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_pointer(func, "pixel_array", "BakePixel", "", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_int(func, "num_pixels", 0, 0, INT_MAX, "Number of Pixels", "Size of the baking batch", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_int(func, "depth", 0, 0, INT_MAX, "Pixels depth", "Number of channels", 1, INT_MAX);
RNA_def_property_flag(prop, PROP_REQUIRED);
/* TODO, see how array size of 0 works, this shouldnt be used */
prop = RNA_def_pointer(func, "result", "AnyType", "", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
/* viewport render callbacks */
func = RNA_def_function(srna, "view_update", NULL);
RNA_def_function_ui_description(func, "Update on data changes for viewport render");
@ -588,39 +672,6 @@ static void rna_def_render_pass(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem pass_type_items[] = {
{SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
{SCE_PASS_Z, "Z", 0, "Z", ""},
{SCE_PASS_RGBA, "COLOR", 0, "Color", ""},
{SCE_PASS_DIFFUSE, "DIFFUSE", 0, "Diffuse", ""},
{SCE_PASS_SPEC, "SPECULAR", 0, "Specular", ""},
{SCE_PASS_SHADOW, "SHADOW", 0, "Shadow", ""},
{SCE_PASS_AO, "AO", 0, "AO", ""},
{SCE_PASS_REFLECT, "REFLECTION", 0, "Reflection", ""},
{SCE_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
{SCE_PASS_VECTOR, "VECTOR", 0, "Vector", ""},
{SCE_PASS_REFRACT, "REFRACTION", 0, "Refraction", ""},
{SCE_PASS_INDEXOB, "OBJECT_INDEX", 0, "Object Index", ""},
{SCE_PASS_UV, "UV", 0, "UV", ""},
{SCE_PASS_MIST, "MIST", 0, "Mist", ""},
{SCE_PASS_EMIT, "EMIT", 0, "Emit", ""},
{SCE_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""},
{SCE_PASS_INDEXMA, "MATERIAL_INDEX", 0, "Material Index", ""},
{SCE_PASS_DIFFUSE_DIRECT, "DIFFUSE_DIRECT", 0, "Diffuse Direct", ""},
{SCE_PASS_DIFFUSE_INDIRECT, "DIFFUSE_INDIRECT", 0, "Diffuse Indirect", ""},
{SCE_PASS_DIFFUSE_COLOR, "DIFFUSE_COLOR", 0, "Diffuse Color", ""},
{SCE_PASS_GLOSSY_DIRECT, "GLOSSY_DIRECT", 0, "Glossy Direct", ""},
{SCE_PASS_GLOSSY_INDIRECT, "GLOSSY_INDIRECT", 0, "Glossy Indirect", ""},
{SCE_PASS_GLOSSY_COLOR, "GLOSSY_COLOR", 0, "Glossy Color", ""},
{SCE_PASS_TRANSM_DIRECT, "TRANSMISSION_DIRECT", 0, "Transmission Direct", ""},
{SCE_PASS_TRANSM_INDIRECT, "TRANSMISSION_INDIRECT", 0, "Transmission Indirect", ""},
{SCE_PASS_TRANSM_COLOR, "TRANSMISSION_COLOR", 0, "Transmission Color", ""},
{SCE_PASS_SUBSURFACE_DIRECT, "SUBSURFACE_DIRECT", 0, "Subsurface Direct", ""},
{SCE_PASS_SUBSURFACE_INDIRECT, "SUBSURFACE_INDIRECT", 0, "Subsurface Indirect", ""},
{SCE_PASS_SUBSURFACE_COLOR, "SUBSURFACE_COLOR", 0, "Subsurface Color", ""},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "RenderPass", NULL);
RNA_def_struct_ui_text(srna, "Render Pass", "");
@ -641,7 +692,7 @@ static void rna_def_render_pass(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "passtype");
RNA_def_property_enum_items(prop, pass_type_items);
RNA_def_property_enum_items(prop, render_pass_type_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "rect", PROP_FLOAT, PROP_NONE);
@ -653,12 +704,56 @@ static void rna_def_render_pass(BlenderRNA *brna)
RNA_define_verify_sdna(1);
}
static void rna_def_render_bake_pixel(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "BakePixel", NULL);
RNA_def_struct_ui_text(srna, "Bake Pixel", "");
RNA_define_verify_sdna(0);
prop = RNA_def_property(srna, "primitive_id", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "primitive_id");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE);
RNA_def_property_array(prop, 2);
RNA_def_property_float_sdna(prop, NULL, "uv");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "du_dx", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "du_dx");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "du_dy", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "du_dy");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "dv_dx", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "dv_dx");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "dv_dy", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "dv_dy");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "next", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BakePixel");
RNA_def_property_pointer_funcs(prop, "rna_BakePixel_next_get", NULL, NULL, NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_define_verify_sdna(1);
}
void RNA_def_render(BlenderRNA *brna)
{
rna_def_render_engine(brna);
rna_def_render_result(brna);
rna_def_render_layer(brna);
rna_def_render_pass(brna);
rna_def_render_bake_pixel(brna);
}
#endif /* RNA_RUNTIME */

View File

@ -75,6 +75,17 @@
#include "BLI_threads.h"
#ifdef WITH_OPENEXR
EnumPropertyItem exr_codec_items[] = {
{R_IMF_EXR_CODEC_NONE, "NONE", 0, "None", ""},
{R_IMF_EXR_CODEC_PXR24, "PXR24", 0, "Pxr24 (lossy)", ""},
{R_IMF_EXR_CODEC_ZIP, "ZIP", 0, "ZIP (lossless)", ""},
{R_IMF_EXR_CODEC_PIZ, "PIZ", 0, "PIZ (lossless)", ""},
{R_IMF_EXR_CODEC_RLE, "RLE", 0, "RLE (lossless)", ""},
{0, NULL, 0, NULL, NULL}
};
#endif
EnumPropertyItem uv_sculpt_relaxation_items[] = {
{UV_SCULPT_TOOL_RELAX_LAPLACIAN, "LAPLACIAN", 0, "Laplacian", "Use Laplacian method for relaxation"},
{UV_SCULPT_TOOL_RELAX_HC, "HC", 0, "HC", "Use HC method for relaxation"},
@ -295,6 +306,28 @@ EnumPropertyItem image_color_depth_items[] = {
{0, NULL, 0, NULL, NULL}
};
EnumPropertyItem normal_space_items[] = {
{R_BAKE_SPACE_OBJECT, "OBJECT", 0, "Object", "Bake the normals in object space"},
{R_BAKE_SPACE_TANGENT, "TANGENT", 0, "Tangent", "Bake the normals in tangent space"},
{0, NULL, 0, NULL, NULL}
};
EnumPropertyItem normal_swizzle_items[] = {
{R_BAKE_POSX, "POS_X", 0, "+X", ""},
{R_BAKE_POSY, "POS_Y", 0, "+Y", ""},
{R_BAKE_POSZ, "POS_Z", 0, "+Z", ""},
{R_BAKE_NEGX, "NEG_X", 0, "-X", ""},
{R_BAKE_NEGY, "NEG_Y", 0, "-Y", ""},
{R_BAKE_NEGZ, "NEG_Z", 0, "-Z", ""},
{0, NULL, 0, NULL, NULL}
};
EnumPropertyItem bake_save_mode_items[] = {
{R_BAKE_SAVE_INTERNAL, "INTERNAL", 0, "Internal", "Save the baking map in an internal image datablock"},
{R_BAKE_SAVE_EXTERNAL, "EXTERNAL", 0, "External", "Save the baking map in an external file"},
{0, NULL, 0, NULL, NULL}
};
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
@ -3062,6 +3095,110 @@ static void rna_def_scene_game_recast_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE, NULL);
}
static void rna_def_bake_data(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "BakeSettings", NULL);
RNA_def_struct_sdna(srna, "BakeData");
RNA_def_struct_nested(brna, srna, "RenderSettings");
RNA_def_struct_ui_text(srna, "Bake Data", "Bake data for a Scene datablock");
prop = RNA_def_property(srna, "cage", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Cage", "Object to use as cage");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
RNA_def_property_ui_text(prop, "File Path", "Image filepath to use when saving externally");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "width", PROP_INT, PROP_PIXEL);
RNA_def_property_range(prop, 4, 10000);
RNA_def_property_ui_text(prop, "Width", "Horizontal dimension of the baking map");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "height", PROP_INT, PROP_PIXEL);
RNA_def_property_range(prop, 4, 10000);
RNA_def_property_ui_text(prop, "Height", "Vertical dimension of the baking map");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "margin", PROP_INT, PROP_PIXEL);
RNA_def_property_range(prop, 0, SHRT_MAX);
RNA_def_property_ui_range(prop, 0, 64, 1, 1);
RNA_def_property_ui_text(prop, "Margin", "Extends the baked result as a post process filter");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "cage_extrusion", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, MAXFLOAT);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3);
RNA_def_property_ui_text(prop, "Cage Extrusion",
"Distance to use for the inward ray cast when using selected to active");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "normal_space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "normal_space");
RNA_def_property_enum_items(prop, normal_space_items);
RNA_def_property_ui_text(prop, "Normal Space", "Choose normal space for baking");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "normal_r", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "normal_swizzle[0]");
RNA_def_property_enum_items(prop, normal_swizzle_items);
RNA_def_property_ui_text(prop, "Normal Space", "Axis to bake in red channel");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "normal_g", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "normal_swizzle[1]");
RNA_def_property_enum_items(prop, normal_swizzle_items);
RNA_def_property_ui_text(prop, "Normal Space", "Axis to bake in green channel");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "normal_b", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "normal_swizzle[2]");
RNA_def_property_enum_items(prop, normal_swizzle_items);
RNA_def_property_ui_text(prop, "Normal Space", "Axis to bake in blue channel");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "image_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "im_format");
RNA_def_property_struct_type(prop, "ImageFormatSettings");
RNA_def_property_ui_text(prop, "Image Format", "");
prop = RNA_def_property(srna, "save_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "save_mode");
RNA_def_property_enum_items(prop, bake_save_mode_items);
RNA_def_property_ui_text(prop, "Save Mode", "Choose how to save the baking map");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
/* flags */
prop = RNA_def_property(srna, "use_selected_to_active", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", R_BAKE_TO_ACTIVE);
RNA_def_property_ui_text(prop, "Selected to Active",
"Bake shading on the surface of selected objects to the active object");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_clear", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", R_BAKE_CLEAR);
RNA_def_property_ui_text(prop, "Clear",
"Clear Images before baking (internal only)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_split_materials", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", R_BAKE_SPLIT_MAT);
RNA_def_property_ui_text(prop, "Split Materials",
"Split external images per material (external only)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_automatic_name", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", R_BAKE_AUTO_NAME);
RNA_def_property_ui_text(prop, "Automatic Name",
"Automatically name the output file with the pass type (external only)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
}
static void rna_def_scene_game_data(BlenderRNA *brna)
{
StructRNA *srna;
@ -3591,16 +3728,6 @@ static void rna_def_render_layers(BlenderRNA *brna, PropertyRNA *cprop)
static void rna_def_scene_image_format_data(BlenderRNA *brna)
{
#ifdef WITH_OPENEXR
static EnumPropertyItem exr_codec_items[] = {
{R_IMF_EXR_CODEC_NONE, "NONE", 0, "None", ""},
{R_IMF_EXR_CODEC_PXR24, "PXR24", 0, "Pxr24 (lossy)", ""},
{R_IMF_EXR_CODEC_ZIP, "ZIP", 0, "ZIP (lossless)", ""},
{R_IMF_EXR_CODEC_PIZ, "PIZ", 0, "PIZ (lossless)", ""},
{R_IMF_EXR_CODEC_RLE, "RLE", 0, "RLE (lossless)", ""},
{0, NULL, 0, NULL, NULL}
};
#endif
#ifdef WITH_OPENJPEG
static EnumPropertyItem jp2_codec_items[] = {
@ -4872,6 +4999,21 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_range(prop, 0.f, 10000.f);
RNA_def_property_ui_text(prop, "Line Thickness", "Line thickness in pixels");
/* Bake Settings */
prop = RNA_def_property(srna, "bake", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "bake");
RNA_def_property_struct_type(prop, "BakeSettings");
RNA_def_property_ui_text(prop, "Bake Data", "");
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
rna_def_bake_data(brna);
RNA_define_animate_sdna(true);
/* *** Animated *** */
/* Scene API */
RNA_api_scene_render(srna);
}

View File

@ -53,6 +53,7 @@ set(SRC
intern/raytrace/rayobject_rtbuild.cpp
intern/raytrace/rayobject_vbvh.cpp
intern/source/bake.c
intern/source/bake_api.c
intern/source/convertblender.c
intern/source/envmap.c
intern/source/external_engine.c
@ -82,6 +83,7 @@ set(SRC
intern/source/zbuf.c
extern/include/RE_engine.h
extern/include/RE_bake.h
extern/include/RE_multires_bake.h
extern/include/RE_pipeline.h
extern/include/RE_render_ext.h

View File

@ -0,0 +1,105 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2010 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s):
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file RE_bake.h
* \ingroup render
*/
#ifndef __RE_BAKE_H__
#define __RE_BAKE_H__
struct Render;
struct Mesh;
typedef struct BakeImage {
struct Image *image;
int width;
int height;
int offset;
} BakeImage;
typedef struct BakeImages {
BakeImage *data; /* all the images of an object */
int *lookup; /* lookup table from Material to BakeImage */
int size;
} BakeImages;
typedef struct BakePixel {
int primitive_id;
float uv[2];
float du_dx, du_dy;
float dv_dx, dv_dy;
} BakePixel;
typedef struct BakeHighPolyData {
struct BakePixel *pixel_array;
struct Object *ob;
struct ModifierData *tri_mod;
struct Mesh *me;
char restrict_flag;
float mat_lowtohigh[4][4];
} BakeHighPolyData;
/* external_engine.c */
bool RE_bake_has_engine(struct Render *re);
bool RE_bake_engine(
struct Render *re, struct Object *object, const BakePixel pixel_array[],
const int num_pixels, const int depth, const ScenePassType pass_type, float result[]);
/* bake.c */
int RE_pass_depth(const ScenePassType pass_type);
bool RE_bake_internal(
struct Render *re, struct Object *object, const BakePixel pixel_array[],
const int num_pixels, const int depth, const ScenePassType pass_type, float result[]);
void RE_bake_pixels_populate_from_objects(
struct Mesh *me_low, BakePixel pixel_array_from[],
BakeHighPolyData highpoly[], const int tot_highpoly, const int num_pixels,
const float cage_extrusion);
void RE_bake_pixels_populate(
struct Mesh *me, struct BakePixel *pixel_array,
const int num_pixels, const struct BakeImages *bake_images);
void RE_bake_mask_fill(const BakePixel pixel_array[], const int num_pixels, char *mask);
void RE_bake_margin(struct ImBuf *ibuf, char *mask, const int margin);
void RE_bake_normal_world_to_object(
const BakePixel pixel_array[], const int num_pixels, const int depth, float result[],
struct Object *ob, const BakeNormalSwizzle normal_swizzle[3]);
void RE_bake_normal_world_to_tangent(
const BakePixel pixel_array[], const int num_pixels, const int depth, float result[],
struct Mesh *me, const BakeNormalSwizzle normal_swizzle[3]);
void RE_bake_normal_world_to_world(
const BakePixel pixel_array[], const int num_pixels, const int depth, float result[],
const BakeNormalSwizzle normal_swizzle[3]);
void RE_bake_ibuf_clear(struct BakeImages *bake_images, const bool is_tangent);
#endif /* __RE_BAKE_H__ */

View File

@ -35,6 +35,7 @@
#include "DNA_listBase.h"
#include "DNA_scene_types.h"
#include "RNA_types.h"
#include "RE_bake.h"
struct bNode;
struct bNodeTree;
@ -47,6 +48,7 @@ struct RenderLayer;
struct RenderResult;
struct ReportList;
struct Scene;
struct BakePixel;
/* External Engine */
@ -85,6 +87,7 @@ typedef struct RenderEngineType {
void (*update)(struct RenderEngine *engine, struct Main *bmain, struct Scene *scene);
void (*render)(struct RenderEngine *engine, struct Scene *scene);
void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type, const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result);
void (*view_update)(struct RenderEngine *engine, const struct bContext *context);
void (*view_draw)(struct RenderEngine *engine, const struct bContext *context);
@ -153,6 +156,7 @@ RenderEngineType *RE_engines_find(const char *idname);
void RE_engine_get_current_tiles(struct Render *re, int *total_tiles_r, rcti **tiles_r);
struct RenderData *RE_engine_get_render_data(struct Render *re);
void RE_bake_engine_set_engine_parameters(struct Render *re, struct Main *bmain, struct Scene *scene);
#endif /* __RE_ENGINE_H__ */

View File

@ -54,6 +54,8 @@
#include "IMB_imbuf.h"
#include "IMB_colormanagement.h"
#include "RE_bake.h"
/* local include */
#include "rayintersection.h"
#include "rayobject.h"

View File

@ -0,0 +1,829 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributors:
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/render/intern/source/bake_api.c
* \ingroup render
*
* \brief 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.
*
* \section bake_api Development Notes for External Engines
*
* The Bake API is fully implemented with Python rna functions. The operator expects/call a function:
*
* def bake(scene, object, pass_type, pixel_array, num_pixels, depth, result)
* - scene: current scene (Python object)
* - object: object to render (Python object)
* - pass_type: pass to render (string, e.g., "COMBINED", "AO", "NORMAL", ...)
* - pixel_array: list of primitive ids and barycentric coordinates to bake(Python object, see bake_pixel)
* - num_pixels: size of pixel_array, number of pixels to bake (int)
* - depth: depth of pixels to return (int, assuming always 4 now)
* - result: array to be populated by the engine (float array, PyLong_AsVoidPtr)
*
* \note Normals are expected to be in World Space and in the +X, +Y, +Z orientation.
*
* \subsection bake_pixel BakePixel data structure
*
* pixel_array is a Python object storing BakePixel elements:
* struct BakePixel {
* int primitive_id;
* float u, v;
* float dudx, dudy;
* float dvdx, dvdy;
* };
*
* In python you have access to:
* - primitive_id, u, v, du_dx, du_dy, next
* - next() is a function that returns the next BakePixel in the array.
*
* \note Pixels that should not be baked have primitive_id = -1
*
* For a complete implementation example look at the Cycles Bake commit.
*/
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "DNA_mesh_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_image.h"
#include "BKE_node.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "RE_bake.h"
/* local include */
#include "render_types.h"
#include "zbuf.h"
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
/* only to be used here in this file, it's for speed */
extern struct Render R;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
typedef struct BakeDataZSpan {
BakePixel *pixel_array;
int primitive_id;
BakeImage *bk_image;
ZSpan *zspan;
} BakeDataZSpan;
/**
* struct wrapping up tangent space data
*/
typedef struct TSpace {
float tangent[3];
float sign;
} TSpace;
typedef struct TriTessFace {
const MVert *mverts[3];
const TSpace *tspace[3];
float normal[3]; /* for flat faces */
bool is_smooth;
} TriTessFace;
static void store_bake_pixel(void *handle, int x, int y, float u, float v)
{
BakeDataZSpan *bd = (BakeDataZSpan *)handle;
BakePixel *pixel;
const int width = bd->bk_image->width;
const int offset = bd->bk_image->offset;
const int i = offset + y * width + x;
pixel = &bd->pixel_array[i];
pixel->primitive_id = bd->primitive_id;
copy_v2_fl2(pixel->uv, u, v);
pixel->du_dx =
pixel->du_dy =
pixel->dv_dx =
pixel->dv_dy =
0.0f;
}
void RE_bake_mask_fill(const BakePixel pixel_array[], const int num_pixels, char *mask)
{
int i;
if (!mask)
return;
/* only extend to pixels outside the mask area */
for (i = 0; i < num_pixels; i++) {
if (pixel_array[i].primitive_id != -1) {
mask[i] = FILTER_MASK_USED;
}
}
}
void RE_bake_margin(ImBuf *ibuf, char *mask, const int margin)
{
/* margin */
IMB_filter_extend(ibuf, mask, margin);
if (ibuf->planes != R_IMF_PLANES_RGBA)
/* clear alpha added by filtering */
IMB_rectfill_alpha(ibuf, 1.0f);
}
/**
* This function returns the coordinate and normal of a barycentric u,v for a face defined by the primitive_id index.
*/
static void calc_point_from_barycentric(
TriTessFace *triangles, int primitive_id, float u, float v, float cage_extrusion,
float r_co[3], float r_dir[3])
{
float data[3][3];
float coord[3];
float dir[3];
float cage[3];
TriTessFace *triangle = &triangles[primitive_id];
copy_v3_v3(data[0], triangle->mverts[0]->co);
copy_v3_v3(data[1], triangle->mverts[1]->co);
copy_v3_v3(data[2], triangle->mverts[2]->co);
interp_barycentric_tri_v3(data, u, v, coord);
normal_short_to_float_v3(data[0], triangle->mverts[0]->no);
normal_short_to_float_v3(data[1], triangle->mverts[1]->no);
normal_short_to_float_v3(data[2], triangle->mverts[2]->no);
interp_barycentric_tri_v3(data, u, v, dir);
normalize_v3_v3(cage, dir);
mul_v3_fl(cage, cage_extrusion);
add_v3_v3(coord, cage);
normalize_v3_v3(dir, dir);
mul_v3_fl(dir, -1.0f);
copy_v3_v3(r_co, coord);
copy_v3_v3(r_dir, dir);
}
/**
* This function returns the barycentric u,v of a face for a coordinate. The face is defined by its index.
*/
static void calc_barycentric_from_point(
TriTessFace *triangles, const int index, const float co[3],
int *r_primitive_id, float r_uv[2])
{
TriTessFace *triangle = &triangles[index];
resolve_tri_uv_v3(r_uv, co,
triangle->mverts[0]->co,
triangle->mverts[1]->co,
triangle->mverts[2]->co);
*r_primitive_id = index;
}
/**
* This function populates pixel_array and returns TRUE if things are correct
*/
static bool cast_ray_highpoly(
BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakeHighPolyData *highpoly,
float const co_low[3], const float dir[3], const int pixel_id, const int tot_highpoly)
{
int i;
int primitive_id = -1;
float uv[2];
int hit_mesh = -1;
float hit_distance = FLT_MAX;
BVHTreeRayHit *hits;
hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays");
for (i = 0; i < tot_highpoly; i++) {
float co_high[3];
hits[i].index = -1;
/* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
hits[i].dist = 10000.0f;
copy_v3_v3(co_high, co_low);
/* transform the ray from the lowpoly to the highpoly space */
mul_m4_v3(highpoly[i].mat_lowtohigh, co_high);
/* cast ray */
BLI_bvhtree_ray_cast(treeData[i].tree, co_high, dir, 0.0f, &hits[i], treeData[i].raycast_callback, &treeData[i]);
if (hits[i].index != -1) {
/* cull backface */
const float dot = dot_v3v3(dir, hits[i].no);
if (dot < 0.0f) {
if (hits[i].dist < hit_distance) {
hit_mesh = i;
hit_distance = hits[i].dist;
}
}
}
}
for (i = 0; i < tot_highpoly; i++) {
if (hit_mesh == i) {
calc_barycentric_from_point(triangles[i], hits[i].index, hits[i].co, &primitive_id, uv);
highpoly[i].pixel_array[pixel_id].primitive_id = primitive_id;
copy_v2_v2(highpoly[i].pixel_array[pixel_id].uv, uv);
}
else {
highpoly[i].pixel_array[pixel_id].primitive_id = -1;
}
}
MEM_freeN(hits);
return hit_mesh != -1;
}
/**
* This function populates an array of verts for the triangles of a mesh
* Tangent and Normals are also stored
*/
static void mesh_calc_tri_tessface(
TriTessFace *triangles, Mesh *me, bool tangent, DerivedMesh *dm)
{
int i;
int p_id;
MFace *mface;
MVert *mvert;
TSpace *tspace;
float *precomputed_normals;
bool calculate_normal;
mface = CustomData_get_layer(&me->fdata, CD_MFACE);
mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
if (tangent) {
DM_ensure_normals(dm);
DM_add_tangent_layer(dm);
precomputed_normals = dm->getTessFaceDataArray(dm, CD_NORMAL);
calculate_normal = precomputed_normals ? false : true;
//mface = dm->getTessFaceArray(dm);
//mvert = dm->getVertArray(dm);
tspace = dm->getTessFaceDataArray(dm, CD_TANGENT);
BLI_assert(tspace);
}
p_id = -1;
for (i = 0; i < me->totface; i++) {
MFace *mf = &mface[i];
TSpace *ts = &tspace[i * 4];
p_id++;
triangles[p_id].mverts[0] = &mvert[mf->v1];
triangles[p_id].mverts[1] = &mvert[mf->v2];
triangles[p_id].mverts[2] = &mvert[mf->v3];
triangles[p_id].is_smooth = (mf->flag & ME_SMOOTH) != 0;
if (tangent) {
triangles[p_id].tspace[0] = &ts[0];
triangles[p_id].tspace[1] = &ts[1];
triangles[p_id].tspace[2] = &ts[2];
if (calculate_normal) {
if (mf->v4 != 0) {
normal_quad_v3(triangles[p_id].normal,
mvert[mf->v1].co,
mvert[mf->v2].co,
mvert[mf->v3].co,
mvert[mf->v4].co);
}
else {
normal_tri_v3(triangles[p_id].normal,
triangles[p_id].mverts[0]->co,
triangles[p_id].mverts[1]->co,
triangles[p_id].mverts[2]->co);
}
}
else {
copy_v3_v3(triangles[p_id].normal, &precomputed_normals[3 * i]);
}
}
/* 4 vertices in the face */
if (mf->v4 != 0) {
p_id++;
triangles[p_id].mverts[0] = &mvert[mf->v1];
triangles[p_id].mverts[1] = &mvert[mf->v3];
triangles[p_id].mverts[2] = &mvert[mf->v4];
triangles[p_id].is_smooth = (mf->flag & ME_SMOOTH) != 0;
if (tangent) {
triangles[p_id].tspace[0] = &ts[0];
triangles[p_id].tspace[1] = &ts[2];
triangles[p_id].tspace[2] = &ts[3];
/* same normal as the other "triangle" */
copy_v3_v3(triangles[p_id].normal, triangles[p_id - 1].normal);
}
}
}
BLI_assert(p_id < me->totface * 2);
}
void RE_bake_pixels_populate_from_objects(
struct Mesh *me_low, BakePixel pixel_array_from[],
BakeHighPolyData highpoly[], const int tot_highpoly, const int num_pixels,
const float cage_extrusion)
{
int i;
int primitive_id;
float u, v;
DerivedMesh **dm_highpoly;
BVHTreeFromMesh *treeData;
/* Note: all coordinates are in local space */
TriTessFace *tris_low;
TriTessFace **tris_high;
/* assume all lowpoly tessfaces can be quads */
tris_low = MEM_callocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Lowpoly Mesh");
tris_high = MEM_callocN(sizeof(TriTessFace *) * tot_highpoly, "MVerts Highpoly Mesh Array");
/* assume all highpoly tessfaces are triangles */
dm_highpoly = MEM_callocN(sizeof(DerivedMesh *) * tot_highpoly, "Highpoly Derived Meshes");
treeData = MEM_callocN(sizeof(BVHTreeFromMesh) * tot_highpoly, "Highpoly BVH Trees");
mesh_calc_tri_tessface(tris_low, me_low, false, NULL);
for (i = 0; i < tot_highpoly; i++) {
tris_high[i] = MEM_callocN(sizeof(TriTessFace) * highpoly[i].me->totface, "MVerts Highpoly Mesh");
mesh_calc_tri_tessface(tris_high[i], highpoly[i].me, false, NULL);
dm_highpoly[i] = CDDM_from_mesh(highpoly[i].me);
/* Create a bvh-tree for each highpoly object */
bvhtree_from_mesh_faces(&treeData[i], dm_highpoly[i], 0.0, 2, 6);
if (&treeData[i].tree == NULL) {
printf("Baking: Out of memory\n");
goto cleanup;
}
}
for (i = 0; i < num_pixels; i++) {
float co[3];
float dir[3];
primitive_id = pixel_array_from[i].primitive_id;
if (primitive_id == -1) {
int j;
for (j = 0; j < tot_highpoly; j++) {
highpoly[j].pixel_array[i].primitive_id = -1;
}
continue;
}
u = pixel_array_from[i].uv[0];
v = pixel_array_from[i].uv[1];
/* calculate from low poly mesh cage */
calc_point_from_barycentric(tris_low, primitive_id, u, v, cage_extrusion, co, dir);
/* cast ray */
if (!cast_ray_highpoly(treeData, tris_high, highpoly, co, dir, i, tot_highpoly)) {
/* if it fails mask out the original pixel array */
pixel_array_from[i].primitive_id = -1;
}
}
/* garbage collection */
cleanup:
for (i = 0; i < tot_highpoly; i++) {
free_bvhtree_from_mesh(&treeData[i]);
dm_highpoly[i]->release(dm_highpoly[i]);
MEM_freeN(tris_high[i]);
}
MEM_freeN(tris_low);
MEM_freeN(tris_high);
MEM_freeN(treeData);
MEM_freeN(dm_highpoly);
}
void RE_bake_pixels_populate(
Mesh *me, BakePixel pixel_array[],
const int num_pixels, const BakeImages *bake_images)
{
BakeDataZSpan bd;
int i, a;
int p_id;
MTFace *mtface;
MFace *mface;
/* we can't bake in edit mode */
if (me->edit_btmesh)
return;
bd.pixel_array = pixel_array;
bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan");
/* initialize all pixel arrays so we know which ones are 'blank' */
for (i = 0; i < num_pixels; i++) {
pixel_array[i].primitive_id = -1;
}
for (i = 0; i < bake_images->size; i++) {
zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop);
}
mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
mface = CustomData_get_layer(&me->fdata, CD_MFACE);
if (mtface == NULL)
return;
p_id = -1;
for (i = 0; i < me->totface; i++) {
float vec[4][2];
MTFace *mtf = &mtface[i];
MFace *mf = &mface[i];
int mat_nr = mf->mat_nr;
int image_id = bake_images->lookup[mat_nr];
bd.bk_image = &bake_images->data[image_id];
bd.primitive_id = ++p_id;
for (a = 0; a < 4; a++) {
/* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests
* where a pixel gets in between 2 faces or the middle of a quad,
* camera aligned quads also have this problem but they are less common.
* Add a small offset to the UVs, fixes bug #18685 - Campbell */
vec[a][0] = mtf->uv[a][0] * (float)bd.bk_image->width - (0.5f + 0.001f);
vec[a][1] = mtf->uv[a][1] * (float)bd.bk_image->height - (0.5f + 0.002f);
}
zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel);
/* 4 vertices in the face */
if (mf->v4 != 0) {
bd.primitive_id = ++p_id;
zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[2], vec[3], store_bake_pixel);
}
}
for (i = 0; i < bake_images->size; i++) {
zbuf_free_span(&bd.zspan[i]);
}
MEM_freeN(bd.zspan);
}
/* ******************** NORMALS ************************ */
/**
* convert a normalized normal to the -1.0 1.0 range
* the input is expected to be POS_X, POS_Y, POS_Z
*/
static void normal_uncompress(float out[3], const float in[3])
{
int i;
for (i = 0; i < 3; i++)
out[i] = 2.0f * in[i] - 1.0f;
}
static void normal_compress(float out[3], const float in[3], const BakeNormalSwizzle normal_swizzle[3])
{
const int swizzle_index[6] = {
0, /* R_BAKE_POSX */
1, /* R_BAKE_POSY */
2, /* R_BAKE_POSZ */
0, /* R_BAKE_NEGX */
1, /* R_BAKE_NEGY */
2, /* R_BAKE_NEGZ */
};
const float swizzle_sign[6] = {
+1.0f, /* R_BAKE_POSX */
+1.0f, /* R_BAKE_POSY */
+1.0f, /* R_BAKE_POSZ */
-1.0f, /* R_BAKE_NEGX */
-1.0f, /* R_BAKE_NEGY */
-1.0f, /* R_BAKE_NEGZ */
};
int i;
for (i = 0; i < 3; i++) {
int index;
float sign;
sign = swizzle_sign[normal_swizzle[i]];
index = swizzle_index[normal_swizzle[i]];
/*
* There is a small 1e-5f bias for precision issues. otherwise
* we randomly get 127 or 128 for neutral colors in tangent maps.
* we choose 128 because it is the convention flat color. *
*/
out[i] = sign * in[index] / 2.0f + 0.5f + 1e-5f;
}
}
/**
* This function converts an object space normal map to a tangent space normal map for a given low poly mesh
*/
void RE_bake_normal_world_to_tangent(
const BakePixel pixel_array[], const int num_pixels, const int depth,
float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3])
{
int i;
TriTessFace *triangles;
DerivedMesh *dm = CDDM_from_mesh(me);
triangles = MEM_callocN(sizeof(TriTessFace) * (me->totface * 2), "MVerts Mesh");
mesh_calc_tri_tessface(triangles, me, true, dm);
BLI_assert(num_pixels >= 3);
for (i = 0; i < num_pixels; i++) {
TriTessFace *triangle;
float tangents[3][3];
float normals[3][3];
float signs[3];
int j;
float tangent[3];
float normal[3];
float binormal[3];
float sign;
float u, v, w;
float tsm[3][3]; /* tangent space matrix */
float itsm[3][3];
int offset;
float nor[3]; /* texture normal */
bool is_smooth;
int primitive_id = pixel_array[i].primitive_id;
offset = i * depth;
if (primitive_id == -1) {
copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f);
continue;
}
triangle = &triangles[primitive_id];
is_smooth = triangle->is_smooth;
for (j = 0; j < 3; j++) {
const TSpace *ts;
if (is_smooth)
normal_short_to_float_v3(normals[j], triangle->mverts[j]->no);
else
normal[j] = triangle->normal[j];
ts = triangle->tspace[j];
copy_v3_v3(tangents[j], ts->tangent);
signs[j] = ts->sign;
}
u = pixel_array[i].uv[0];
v = pixel_array[i].uv[1];
w = 1.0f - u - v;
/* normal */
if (is_smooth)
interp_barycentric_tri_v3(normals, u, v, normal);
/* tangent */
interp_barycentric_tri_v3(tangents, u, v, tangent);
/* sign */
/* The sign is the same at all face vertices for any non degenerate face.
* Just in case we clamp the interpolated value though. */
sign = (signs[0] * u + signs[1] * v + signs[2] * w) < 0 ? (-1.0f) : 1.0f;
/* binormal */
/* B = sign * cross(N, T) */
cross_v3_v3v3(binormal, normal, tangent);
mul_v3_fl(binormal, sign);
/* populate tangent space matrix */
copy_v3_v3(tsm[0], tangent);
copy_v3_v3(tsm[1], binormal);
copy_v3_v3(tsm[2], normal);
/* texture values */
normal_uncompress(nor, &result[offset]);
invert_m3_m3(itsm, tsm);
mul_m3_v3(itsm, nor);
normalize_v3(nor);
/* save back the values */
normal_compress(&result[offset], nor, normal_swizzle);
}
/* garbage collection */
MEM_freeN(triangles);
if (dm)
dm->release(dm);
}
void RE_bake_normal_world_to_object(
const BakePixel pixel_array[], const int num_pixels, const int depth,
float result[], struct Object *ob, const BakeNormalSwizzle normal_swizzle[3])
{
int i;
float iobmat[4][4];
invert_m4_m4(iobmat, ob->obmat);
for (i = 0; i < num_pixels; i++) {
int offset;
float nor[3];
if (pixel_array[i].primitive_id == -1)
continue;
offset = i * depth;
normal_uncompress(nor, &result[offset]);
mul_m4_v3(iobmat, nor);
normalize_v3(nor);
/* save back the values */
normal_compress(&result[offset], nor, normal_swizzle);
}
}
void RE_bake_normal_world_to_world(
const BakePixel pixel_array[], const int num_pixels, const int depth,
float result[], const BakeNormalSwizzle normal_swizzle[3])
{
int i;
for (i = 0; i < num_pixels; i++) {
int offset;
float nor[3];
if (pixel_array[i].primitive_id == -1)
continue;
offset = i * depth;
normal_uncompress(nor, &result[offset]);
/* save back the values */
normal_compress(&result[offset], nor, normal_swizzle);
}
}
void RE_bake_ibuf_clear(BakeImages *bake_images, const bool is_tangent)
{
ImBuf *ibuf;
void *lock;
Image *image;
int i;
const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f};
const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f};
const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f};
const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f};
for (i = 0; i < bake_images->size; i ++) {
image = bake_images->data[i].image;
ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
BLI_assert(ibuf);
if (is_tangent)
IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
else
IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
BKE_image_release_ibuf(image, ibuf, lock);
}
}
/* ************************************************************* */
/**
* not the real UV, but the internal per-face UV instead
* I'm using it to test if everything is correct */
static bool bake_uv(const BakePixel pixel_array[], const int num_pixels, const int depth, float result[])
{
int i;
for (i=0; i < num_pixels; i++) {
int offset = i * depth;
copy_v2_v2(&result[offset], pixel_array[i].uv);
}
return true;
}
bool RE_bake_internal(
Render *UNUSED(re), Object *UNUSED(object), const BakePixel pixel_array[],
const int num_pixels, const int depth, const ScenePassType pass_type, float result[])
{
switch (pass_type) {
case SCE_PASS_UV:
{
return bake_uv(pixel_array, num_pixels, depth, result);
break;
}
default:
break;
}
return false;
}
int RE_pass_depth(const ScenePassType pass_type)
{
/* IMB_buffer_byte_from_float assumes 4 channels
* making it work for now - XXX */
return 4;
switch (pass_type) {
case SCE_PASS_Z:
case SCE_PASS_AO:
case SCE_PASS_MIST:
{
return 1;
}
case SCE_PASS_UV:
{
return 2;
}
case SCE_PASS_RGBA:
{
return 4;
}
case SCE_PASS_COMBINED:
case SCE_PASS_DIFFUSE:
case SCE_PASS_SPEC:
case SCE_PASS_SHADOW:
case SCE_PASS_REFLECT:
case SCE_PASS_NORMAL:
case SCE_PASS_VECTOR:
case SCE_PASS_REFRACT:
case SCE_PASS_INDEXOB: /* XXX double check */
case SCE_PASS_INDIRECT:
case SCE_PASS_RAYHITS: /* XXX double check */
case SCE_PASS_EMIT:
case SCE_PASS_ENVIRONMENT:
case SCE_PASS_INDEXMA:
case SCE_PASS_DIFFUSE_DIRECT:
case SCE_PASS_DIFFUSE_INDIRECT:
case SCE_PASS_DIFFUSE_COLOR:
case SCE_PASS_GLOSSY_DIRECT:
case SCE_PASS_GLOSSY_INDIRECT:
case SCE_PASS_GLOSSY_COLOR:
case SCE_PASS_TRANSM_DIRECT:
case SCE_PASS_TRANSM_INDIRECT:
case SCE_PASS_TRANSM_COLOR:
case SCE_PASS_SUBSURFACE_DIRECT:
case SCE_PASS_SUBSURFACE_INDIRECT:
case SCE_PASS_SUBSURFACE_COLOR:
default:
{
return 3;
}
}
}

View File

@ -57,6 +57,7 @@
#include "RE_engine.h"
#include "RE_pipeline.h"
#include "RE_bake.h"
#include "initrender.h"
#include "render_types.h"
@ -67,7 +68,7 @@
static RenderEngineType internal_render_type = {
NULL, NULL,
"BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
{NULL, NULL, NULL}
};
@ -76,7 +77,7 @@ static RenderEngineType internal_render_type = {
static RenderEngineType internal_game_type = {
NULL, NULL,
"BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
{NULL, NULL, NULL}
};
@ -402,6 +403,84 @@ RenderData *RE_engine_get_render_data(Render *re)
return &re->r;
}
/* Bake */
void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
{
re->scene = scene;
re->main = bmain;
re->r = scene->r;
/* prevent crash when freeing the scene
but it potentially leaves unfreed memory blocks
not sure how to fix this yet -- dfelinto */
re->r.layers.first = re->r.layers.last = NULL;
}
bool RE_bake_has_engine(Render *re)
{
RenderEngineType *type = RE_engines_find(re->r.engine);
return (bool)(type->bake);
}
bool RE_bake_engine(
Render *re, Object *object, const BakePixel pixel_array[],
const int num_pixels, const int depth,
const ScenePassType pass_type, float result[])
{
RenderEngineType *type = RE_engines_find(re->r.engine);
RenderEngine *engine;
int persistent_data = re->r.mode & R_PERSISTENT_DATA;
/* 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);
re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0;
/* 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;
RE_parts_init(re, false);
engine->tile_x = re->partx;
engine->tile_y = re->party;
/* update is only called so we create the engine.session */
if (type->update)
type->update(engine, re->main, re->scene);
if (type->bake)
type->bake(engine, re->scene, object, pass_type, pixel_array, num_pixels, depth, result);
engine->tile_x = 0;
engine->tile_y = 0;
engine->flag &= ~RE_ENGINE_RENDERING;
/* re->engine becomes zero if user changed active render engine during render */
if (!persistent_data || !re->engine) {
RE_engine_free(engine);
re->engine = NULL;
}
RE_parts_free(re);
if (BKE_reports_contain(re->reports, RPT_ERROR))
G.is_break = true;
return true;
}
/* Render */
static bool render_layer_exclude_animated(Scene *scene, SceneRenderLayer *srl)

View File

@ -374,6 +374,7 @@ enum {
WM_JOB_TYPE_COMPOSITE,
WM_JOB_TYPE_RENDER,
WM_JOB_TYPE_RENDER_PREVIEW, /* UI preview */
WM_JOB_TYPE_RENDER_BAKE,
WM_JOB_TYPE_SCREENCAST,
WM_JOB_TYPE_OBJECT_SIM_OCEAN,
WM_JOB_TYPE_OBJECT_SIM_FLUID,