Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2012-12-18 21:46:42 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2012-12-18 21:46:42 +0400
commit6571713ddb7e1f091c30a43b315fb37778605ed2 (patch)
tree6a5cc8bf047a0ee50701db2ace65013834383345 /source/blender
parent6b3e880311e1046ec60d8647dc4dd0eb0cd4d92c (diff)
Ambient occlusion baker from multi-resolution mesh
This implements AO baking directly from multi-resolution mesh with much less memory overhead than regular baker. Uses rays distribution implementation from Morten Mikkelsen, raycast is based on RayObject also used by Blender Internal. Works in single-thread yet, multi-threading would be implemented later.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/intern/scene.c1
-rw-r--r--source/blender/blenloader/intern/readfile.c8
-rw-r--r--source/blender/editors/object/object_bake.c46
-rw-r--r--source/blender/makesdna/DNA_scene_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_scene.c7
-rw-r--r--source/blender/render/extern/include/RE_multires_bake.h5
-rw-r--r--source/blender/render/intern/include/rayobject.h2
-rw-r--r--source/blender/render/intern/include/rendercore.h2
-rw-r--r--source/blender/render/intern/raytrace/rayobject.cpp5
-rw-r--r--source/blender/render/intern/source/multires_bake.c365
-rw-r--r--source/blender/render/intern/source/rayshade.c6
-rw-r--r--source/blender/render/intern/source/rendercore.c1
12 files changed, 410 insertions, 41 deletions
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 6a5886faa67..136f5d56af6 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -432,6 +432,7 @@ static Scene *scene_add(Main *bmain, const char *name)
sce->r.bake_osa = 5;
sce->r.bake_flag = R_BAKE_CLEAR;
sce->r.bake_normal_space = R_BAKE_SPACE_TANGENT;
+ sce->r.bake_rays_number = 256;
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;
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 98f3baa4c08..07cb3fdc687 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -8420,6 +8420,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
+ {
+ Scene *scene;
+
+ for (scene = main->scene.first; scene; scene = scene->id.next) {
+ if (scene->r.bake_rays_number == 0)
+ scene->r.bake_rays_number = 256;
+ }
+ }
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index e9b4a7e0eb7..77d31a900d4 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -96,6 +96,9 @@ typedef struct {
ListBase data;
int bake_clear, bake_filter;
short mode, use_lores_mesh;
+ int number_of_rays;
+ float bias;
+ int raytrace_structure;
} MultiresBakeJob;
static int multiresbake_check(bContext *C, wmOperator *op)
@@ -203,6 +206,9 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l
if (*lvl == 0) {
DerivedMesh *tmp_dm = CDDM_from_mesh(me, ob);
+
+ DM_set_only_copy(tmp_dm, CD_MASK_BAREMESH | CD_MASK_MTFACE);
+
dm = CDDM_copy(tmp_dm);
tmp_dm->release(tmp_dm);
}
@@ -210,6 +216,8 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l
MultiresModifierData tmp_mmd = *mmd;
DerivedMesh *cddm = CDDM_from_mesh(me, ob);
+ DM_set_only_copy(cddm, CD_MASK_BAREMESH | CD_MASK_MTFACE);
+
tmp_mmd.lvl = *lvl;
tmp_mmd.sculptlvl = *lvl;
dm = multires_make_derived_from_derived(cddm, &tmp_mmd, ob, 0);
@@ -227,6 +235,14 @@ static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *l
DerivedMesh *cddm = CDDM_from_mesh(me, ob);
DerivedMesh *dm;
+ DM_set_only_copy(cddm, CD_MASK_BAREMESH);
+
+ /* TODO: DM_set_only_copy wouldn't set mask for loop and poly data,
+ * but we really need BAREMESH only to save lots of memory
+ */
+ CustomData_set_only_copy(&cddm->loopData, CD_MASK_BAREMESH);
+ CustomData_set_only_copy(&cddm->polyData, CD_MASK_BAREMESH);
+
*lvl = mmd->totlvl;
*simple = mmd->simple;
@@ -298,14 +314,13 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
bkr.bake_filter = scene->r.bake_filter;
bkr.mode = scene->r.bake_mode;
bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
+ bkr.bias = scene->r.bake_biasdist;
+ bkr.number_of_rays = scene->r.bake_rays_number;
+ bkr.raytrace_structure = scene->r.raytrace_structure;
/* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
- bkr.lores_dm = multiresbake_create_loresdm(scene, ob, &bkr.lvl);
-
- if (!bkr.lores_dm)
- continue;
-
bkr.hires_dm = multiresbake_create_hiresdm(scene, ob, &bkr.tot_lvl, &bkr.simple);
+ bkr.lores_dm = multiresbake_create_loresdm(scene, ob, &bkr.lvl);
RE_multires_bake_images(&bkr);
@@ -335,24 +350,25 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
bkj->mode = scene->r.bake_mode;
bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR;
+ bkj->bias = scene->r.bake_biasdist;
+ bkj->number_of_rays = scene->r.bake_rays_number;
+ bkj->raytrace_structure = scene->r.raytrace_structure;
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
MultiresBakerJobData *data;
- DerivedMesh *lores_dm;
int lvl;
+
ob = base->object;
multires_force_update(ob);
- lores_dm = multiresbake_create_loresdm(scene, ob, &lvl);
- if (!lores_dm)
- continue;
-
data = MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data");
- data->lores_dm = lores_dm;
- data->lvl = lvl;
+
+ /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
data->hires_dm = multiresbake_create_hiresdm(scene, ob, &data->tot_lvl, &data->simple);
+ data->lores_dm = multiresbake_create_loresdm(scene, ob, &lvl);
+ data->lvl = lvl;
BLI_addtail(&bkj->data, data);
}
@@ -399,6 +415,10 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
bkr.do_update = do_update;
bkr.progress = progress;
+ bkr.bias = bkj->bias;
+ bkr.number_of_rays = bkj->number_of_rays;
+ bkr.raytrace_structure = bkj->raytrace_structure;
+
RE_multires_bake_images(&bkr);
BLI_freelistN(&bkr.image);
@@ -652,7 +672,7 @@ static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), wmEven
static int is_multires_bake(Scene *scene)
{
- if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT))
+ if (ELEM3(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_AO))
return scene->r.bake_flag & R_BAKE_MULTIRES;
return 0;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 988517f8ebc..b3aabf1265a 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -491,7 +491,8 @@ typedef struct RenderData {
/* Bake Render options */
short bake_osa, bake_filter, bake_mode, bake_flag;
short bake_normal_space, bake_quad_split;
- float bake_maxdist, bake_biasdist, bake_pad;
+ float bake_maxdist, bake_biasdist;
+ int bake_rays_number;
/* path to render output */
char pic[1024]; /* 1024 = FILE_MAX */
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 8f31b176a3a..fad4a2035fd 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -3881,6 +3881,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"Calculate heights against unsubdivided low resolution mesh");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "bake_rays_number", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "bake_rays_number");
+ RNA_def_property_range(prop, 64, 1024);
+ RNA_def_property_int_default(prop, 256);
+ RNA_def_property_ui_text(prop, "Number of Rays", "Number of rays used for ambient occlusion baking from multires");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
/* stamp */
prop = RNA_def_property(srna, "use_stamp_time", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/render/extern/include/RE_multires_bake.h b/source/blender/render/extern/include/RE_multires_bake.h
index bb9c9b8273c..31fe93981b3 100644
--- a/source/blender/render/extern/include/RE_multires_bake.h
+++ b/source/blender/render/extern/include/RE_multires_bake.h
@@ -40,11 +40,16 @@ typedef struct MultiresBakeRender {
int simple, lvl, tot_lvl, bake_filter;
short mode, use_lores_mesh;
+ int number_of_rays;
+ float bias;
+
int tot_obj, tot_image;
ListBase image;
int baked_objects, baked_faces;
+ int raytrace_structure;
+
short *stop;
short *do_update;
float *progress;
diff --git a/source/blender/render/intern/include/rayobject.h b/source/blender/render/intern/include/rayobject.h
index 7a9d242a2a1..e9514b8585e 100644
--- a/source/blender/render/intern/include/rayobject.h
+++ b/source/blender/render/intern/include/rayobject.h
@@ -87,6 +87,8 @@ typedef struct RayFace {
RayObject *RE_rayface_from_vlak(RayFace *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr);
+RayObject *RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4);
+
/* RayObject representing faces directly from a given VlakRen structure. Thus
* allowing to save memory, but making code triangle intersection dependent on
* render structures. */
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
index 30712250440..921f1173039 100644
--- a/source/blender/render/intern/include/rendercore.h
+++ b/source/blender/render/intern/include/rendercore.h
@@ -83,6 +83,8 @@ int get_sample_layers(struct RenderPart *pa, struct RenderLayer *rl, struct Rend
/* -------- ray.c ------- */
+struct RayObject *RE_rayobject_create(struct Render *re, int type, int size);
+
extern void freeraytree(Render *re);
extern void makeraytree(Render *re);
struct RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi);
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
index c3babf99d51..b31aff82777 100644
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ b/source/blender/render/intern/raytrace/rayobject.cpp
@@ -90,6 +90,11 @@ RayObject *RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRe
return rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0);
}
+RayObject *RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4)
+{
+ return rayface_from_coords(rayface, ob, face, v1, v2, v3, v4);
+}
+
/* VlakPrimitive */
RayObject *RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr)
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index f84fcf9dd8b..55fb8ae082d 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -55,6 +55,10 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
+#include "rayintersection.h"
+#include "rayobject.h"
+#include "rendercore.h"
+
typedef void (*MPassKnownData)(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data,
ImBuf *ibuf, const int face_index, const int lvl, const float st[2],
float tangmat[3][3], const int x, const int y);
@@ -102,6 +106,20 @@ typedef struct {
const int *orig_index_mp_to_orig;
} MNormalBakeData;
+typedef struct {
+ int number_of_rays;
+ float bias;
+
+ unsigned short *permutation_table_1;
+ unsigned short *permutation_table_2;
+
+ RayObject *raytree;
+ RayFace *rayfaces;
+
+ const int *orig_index_mf_to_mpoly;
+ const int *orig_index_mp_to_orig;
+} MAOBakeData;
+
static void multiresbake_get_normal(const MResolvePixelData *data, float norm[], const int face_num, const int vert_index)
{
unsigned int indices[] = {data->mface[face_num].v1, data->mface[face_num].v2,
@@ -169,10 +187,6 @@ static void flush_pixel(const MResolvePixelData *data, const int x, const int y)
st1 = data->mtface[data->face_index].uv[i1];
st2 = data->mtface[data->face_index].uv[i2];
- tang0 = data->pvtangent + data->face_index * 16 + i0 * 4;
- tang1 = data->pvtangent + data->face_index * 16 + i1 * 4;
- tang2 = data->pvtangent + data->face_index * 16 + i2 * 4;
-
multiresbake_get_normal(data, no0, data->face_index, i0); /* can optimize these 3 into one call */
multiresbake_get_normal(data, no1, data->face_index, i1);
multiresbake_get_normal(data, no2, data->face_index, i2);
@@ -183,21 +197,29 @@ static void flush_pixel(const MResolvePixelData *data, const int x, const int y)
v = fUV[1];
w = 1 - u - v;
- /* the sign is the same at all face vertices for any non degenerate face.
- * Just in case we clamp the interpolated value though. */
- sign = (tang0[3] * u + tang1[3] * v + tang2[3] * w) < 0 ? (-1.0f) : 1.0f;
+ if (data->pvtangent) {
+ tang0 = data->pvtangent + data->face_index * 16 + i0 * 4;
+ tang1 = data->pvtangent + data->face_index * 16 + i1 * 4;
+ tang2 = data->pvtangent + data->face_index * 16 + i2 * 4;
- /* this sequence of math is designed specifically as is with great care
- * to be compatible with our shader. Please don't change without good reason. */
- for (r = 0; r < 3; r++) {
- from_tang[0][r] = tang0[r] * u + tang1[r] * v + tang2[r] * w;
- from_tang[2][r] = no0[r] * u + no1[r] * v + no2[r] * w;
- }
+ /* the sign is the same at all face vertices for any non degenerate face.
+ * Just in case we clamp the interpolated value though. */
+ sign = (tang0[3] * u + tang1[3] * v + tang2[3] * w) < 0 ? (-1.0f) : 1.0f;
+
+ /* this sequence of math is designed specifically as is with great care
+ * to be compatible with our shader. Please don't change without good reason. */
+ for (r = 0; r < 3; r++) {
+ from_tang[0][r] = tang0[r] * u + tang1[r] * v + tang2[r] * w;
+ from_tang[2][r] = no0[r] * u + no1[r] * v + no2[r] * w;
+ }
- cross_v3_v3v3(from_tang[1], from_tang[2], from_tang[0]); /* B = sign * cross(N, T) */
- mul_v3_fl(from_tang[1], sign);
- invert_m3_m3(to_tang, from_tang);
- /* sequence end */
+ cross_v3_v3v3(from_tang[1], from_tang[2], from_tang[0]); /* B = sign * cross(N, T) */
+ mul_v3_fl(from_tang[1], sign);
+ invert_m3_m3(to_tang, from_tang);
+ }
+ else {
+ zero_m3(to_tang);
+ }
data->pass_data(data->lores_dm, data->hires_dm, data->bake_data,
data->ibuf, data->face_index, data->lvl, st, to_tang, x, y);
@@ -307,7 +329,7 @@ static int multiresbake_test_break(MultiresBakeRender *bkr)
return G.is_break;
}
-static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, MPassKnownData passKnownData,
+static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, int require_tangent, MPassKnownData passKnownData,
MInitBakeData initBakeData, MApplyBakeData applyBakeData, MFreeBakeData freeBakeData)
{
DerivedMesh *dm = bkr->lores_dm;
@@ -319,10 +341,12 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, MPassKnownData
MTFace *mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
float *pvtangent = NULL;
- if (CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1)
- DM_add_tangent_layer(dm);
+ if (require_tangent) {
+ if (CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1)
+ DM_add_tangent_layer(dm);
- pvtangent = DM_get_tessface_data_layer(dm, CD_TANGENT);
+ pvtangent = DM_get_tessface_data_layer(dm, CD_TANGENT);
+ }
if (tot_face > 0) { /* sanity check */
int f = 0;
@@ -769,6 +793,298 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm,
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
}
+/* **************** Ambient Occlusion Baker **************** */
+
+#define MAX_NUMBER_OF_AO_RAYS 1024
+
+static unsigned short ao_random_table_1[MAX_NUMBER_OF_AO_RAYS];
+static unsigned short ao_random_table_2[MAX_NUMBER_OF_AO_RAYS];
+
+static void init_ao_random(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_NUMBER_OF_AO_RAYS; i++) {
+ ao_random_table_1[i] = rand() & 0xffff;
+ ao_random_table_2[i] = rand() & 0xffff;
+ }
+}
+
+static unsigned short get_ao_random1(const int i)
+{
+ return ao_random_table_1[i & (MAX_NUMBER_OF_AO_RAYS - 1)];
+}
+
+static unsigned short get_ao_random2(const int i)
+{
+ return ao_random_table_2[i & (MAX_NUMBER_OF_AO_RAYS - 1)];
+}
+
+static void build_permutation_table(unsigned short permutation[], unsigned short temp_permutation[],
+ const int number_of_rays, const int is_first_perm_table)
+{
+ int i, k;
+
+ for (i = 0; i < number_of_rays; i++)
+ temp_permutation[i] = i;
+
+ for (i = 0; i < number_of_rays; i++) {
+ const unsigned int nr_entries_left = number_of_rays - i;
+ unsigned short rnd = is_first_perm_table != FALSE ? get_ao_random1(i) : get_ao_random2(i);
+ const unsigned short entry = rnd % nr_entries_left;
+
+ /* pull entry */
+ permutation[i] = temp_permutation[entry];
+
+ /* delete entry */
+ for(k = entry; k < nr_entries_left - 1; k++)
+ temp_permutation[k] = temp_permutation[k + 1];
+ }
+
+ /* verify permutation table
+ * every entry must appear exactly once
+ */
+#if 0
+ for(i = 0; i < number_of_rays; i++) temp_permutation[i] = 0;
+ for(i = 0; i < number_of_rays; i++) ++temp_permutation[permutation[i]];
+ for(i = 0; i < number_of_rays; i++) BLI_assert(temp_permutation[i] == 1);
+#endif
+}
+
+static void create_ao_raytree(MultiresBakeRender *bkr, MAOBakeData *ao_data)
+{
+ DerivedMesh *hidm = bkr->hires_dm;
+ RayObject *raytree;
+ RayFace *face;
+ CCGElem **grid_data;
+ CCGKey key;
+ int num_grids, grid_size, face_side, num_faces;
+ int i;
+
+ num_grids = hidm->getNumGrids(hidm);
+ grid_size = hidm->getGridSize(hidm);
+ grid_data = hidm->getGridData(hidm);
+ hidm->getGridKey(hidm, &key);
+
+ face_side = (grid_size << 1) - 1;
+ num_faces = num_grids * (grid_size - 1) * (grid_size - 1);
+
+ raytree = ao_data->raytree = RE_rayobject_create(NULL, bkr->raytrace_structure, num_faces);
+ face = ao_data->rayfaces = (RayFace *) MEM_callocN(num_faces * sizeof(RayFace), "ObjectRen faces");
+
+ for (i = 0; i < num_grids; i++) {
+ int x, y;
+ for (x = 0; x < grid_size - 1; x++) {
+ for (y = 0; y < grid_size - 1; y++) {
+ float co[4][3];
+
+ copy_v3_v3(co[0], CCG_grid_elem_co(&key, grid_data[i], x, y));
+ copy_v3_v3(co[1], CCG_grid_elem_co(&key, grid_data[i], x, y + 1));
+ copy_v3_v3(co[2], CCG_grid_elem_co(&key, grid_data[i], x + 1, y + 1));
+ copy_v3_v3(co[3], CCG_grid_elem_co(&key, grid_data[i], x + 1, y));
+
+ RE_rayface_from_coords(face, ao_data, face, co[0], co[1], co[2], co[3]);
+ RE_rayobject_add(raytree, RE_rayobject_unalignRayFace(face));
+
+ face++;
+ }
+ }
+ }
+
+ RE_rayobject_done(raytree);
+}
+
+static void *init_ao_data(MultiresBakeRender *bkr, Image *UNUSED(ima))
+{
+ MAOBakeData *ao_data;
+ DerivedMesh *lodm = bkr->lores_dm;
+ unsigned short *temp_permutation_table;
+ size_t permutation_size;
+
+ init_ao_random();
+
+ ao_data = MEM_callocN(sizeof(MAOBakeData), "MultiresBake aoData");
+
+ ao_data->number_of_rays = bkr->number_of_rays;
+ ao_data->bias = bkr->bias;
+
+ ao_data->orig_index_mf_to_mpoly = lodm->getTessFaceDataArray(lodm, CD_ORIGINDEX);
+ ao_data->orig_index_mp_to_orig = lodm->getPolyDataArray(lodm, CD_ORIGINDEX);
+
+ create_ao_raytree(bkr, ao_data);
+
+ /* initialize permutation tables */
+ permutation_size = sizeof(unsigned short) * bkr->number_of_rays;
+ ao_data->permutation_table_1 = MEM_callocN(permutation_size, "multires AO baker perm1");
+ ao_data->permutation_table_2 = MEM_callocN(permutation_size, "multires AO baker perm2");
+ temp_permutation_table = MEM_callocN(permutation_size, "multires AO baker temp perm");
+
+ build_permutation_table(ao_data->permutation_table_1, temp_permutation_table, bkr->number_of_rays, 1);
+ build_permutation_table(ao_data->permutation_table_2, temp_permutation_table, bkr->number_of_rays, 0);
+
+ MEM_freeN(temp_permutation_table);
+
+ return (void *)ao_data;
+}
+
+static void free_ao_data(void *bake_data)
+{
+ MAOBakeData *ao_data = (MAOBakeData *) bake_data;
+
+ RE_rayobject_free(ao_data->raytree);
+ MEM_freeN(ao_data->rayfaces);
+
+ MEM_freeN(ao_data->permutation_table_1);
+ MEM_freeN(ao_data->permutation_table_2);
+
+ MEM_freeN(ao_data);
+}
+
+/* builds an X and a Y axis from the given Z axis */
+static void build_coordinate_frame(float axisX[3], float axisY[3], const float axisZ[3])
+{
+ const float faX = fabsf(axisZ[0]);
+ const float faY = fabsf(axisZ[1]);
+ const float faZ = fabsf(axisZ[2]);
+
+ if (faX <= faY && faX <= faZ) {
+ const float len = sqrtf(axisZ[1] * axisZ[1] + axisZ[2] * axisZ[2]);
+ axisY[0] = 0; axisY[1] = axisZ[2] / len; axisY[2] = -axisZ[1] / len;
+ cross_v3_v3v3(axisX, axisY, axisZ);
+ }
+ else if (faY <= faZ) {
+ const float len = sqrtf(axisZ[0] * axisZ[0] + axisZ[2] * axisZ[2]);
+ axisX[0] = axisZ[2] / len; axisX[1] = 0; axisX[2] = -axisZ[0] / len;
+ cross_v3_v3v3(axisY, axisZ, axisX);
+ }
+ else {
+ const float len = sqrtf(axisZ[0] * axisZ[0] + axisZ[1] * axisZ[1]);
+ axisX[0] = axisZ[1] / len; axisX[1] = -axisZ[0] / len; axisX[2] = 0;
+ cross_v3_v3v3(axisY, axisZ, axisX);
+ }
+}
+
+/* return FALSE if nothing was hit and TRUE otherwise */
+static int trace_ao_ray(MAOBakeData *ao_data, float ray_start[3], float ray_direction[3])
+{
+ Isect isect = {{0}};
+
+ isect.dist = RE_RAYTRACE_MAXDIST;
+ copy_v3_v3(isect.start, ray_start);
+ copy_v3_v3(isect.dir, ray_direction);
+ isect.lay = -1;
+
+ normalize_v3(isect.dir);
+
+ return RE_rayobject_raycast(ao_data->raytree, &isect);
+}
+
+static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data,
+ ImBuf *ibuf, const int face_index, const int lvl, const float st[2],
+ float UNUSED(tangmat[3][3]), const int x, const int y)
+{
+ MAOBakeData *ao_data = (MAOBakeData *) bake_data;
+ MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE);
+ MFace mface;
+
+ int i, k, perm_offs;
+ float pos[3], nrm[3];
+ float cen[3];
+ float axisX[3], axisY[3], axisZ[3];
+ float shadow = 0;
+ float value;
+ int pixel = ibuf->x * y + x;
+ float uv[2], *st0, *st1, *st2, *st3;
+
+ lores_dm->getTessFace(lores_dm, face_index, &mface);
+
+ st0 = mtface[face_index].uv[0];
+ st1 = mtface[face_index].uv[1];
+ st2 = mtface[face_index].uv[2];
+
+ if (mface.v4) {
+ st3 = mtface[face_index].uv[3];
+ resolve_quad_uv(uv, st, st0, st1, st2, st3);
+ }
+ else
+ resolve_tri_uv(uv, st, st0, st1, st2);
+
+ CLAMP(uv[0], 0.0f, 1.0f);
+ CLAMP(uv[1], 0.0f, 1.0f);
+
+ get_ccgdm_data(lores_dm, hires_dm,
+ ao_data->orig_index_mf_to_mpoly, ao_data->orig_index_mp_to_orig,
+ lvl, face_index, uv[0], uv[1], pos, nrm);
+
+ /* offset ray origin by user bias along normal */
+ for (i = 0; i < 3; i++)
+ cen[i] = pos[i] + ao_data->bias * nrm[i];
+
+ /* build tangent frame */
+ for (i = 0; i < 3; i++)
+ axisZ[i] = nrm[i];
+
+ build_coordinate_frame(axisX, axisY, axisZ);
+
+ /* static noise */
+ perm_offs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1);
+
+ /* importance sample shadow rays (cosine weighted) */
+ for (i = 0; i < ao_data->number_of_rays; i++) {
+ int hit_something;
+
+ /* use N-Rooks to distribute our N ray samples across
+ * a multi-dimensional domain (2D)
+ */
+ const unsigned short I = ao_random_table_1[(i + perm_offs) % ao_data->number_of_rays];
+ const unsigned short J = ao_random_table_2[i];
+
+ const float JitPh = (get_ao_random2(I + perm_offs) & (MAX_NUMBER_OF_AO_RAYS-1))/((float) MAX_NUMBER_OF_AO_RAYS);
+ const float JitTh = (get_ao_random1(J + perm_offs) & (MAX_NUMBER_OF_AO_RAYS-1))/((float) MAX_NUMBER_OF_AO_RAYS);
+ const float SiSqPhi = (I + JitPh) / ao_data->number_of_rays;
+ const float Theta = 2 * M_PI * ((J + JitTh) / ao_data->number_of_rays);
+
+ /* this gives results identical to the so-called cosine
+ * weighted distribution relative to the north pole.
+ */
+ float SiPhi = sqrt(SiSqPhi);
+ float CoPhi = SiSqPhi < 1.0f ? sqrt(1.0f - SiSqPhi) : 1.0f - SiSqPhi;
+ float CoThe = cos(Theta);
+ float SiThe = sin(Theta);
+
+ const float dx = CoThe * CoPhi;
+ const float dy = SiThe * CoPhi;
+ const float dz = SiPhi;
+
+ /* transform ray direction out of tangent frame */
+ float dv[3];
+ for (k = 0; k < 3; k++)
+ dv[k] = axisX[k] * dx + axisY[k] * dy + axisZ[k] * dz;
+
+ hit_something = trace_ao_ray(ao_data, cen, dv);
+
+ if (hit_something != 0)
+ shadow += 1;
+ }
+
+ value = 1.0f - (shadow / ao_data->number_of_rays);
+
+ if (ibuf->rect_float) {
+ float *rrgbf = ibuf->rect_float + pixel * 4;
+ rrgbf[0] = rrgbf[1] = rrgbf[2] = value;
+ rrgbf[3] = 1.0f;
+
+ ibuf->userflags = IB_RECT_INVALID;
+ }
+ else {
+ unsigned char *rrgb = (unsigned char *) ibuf->rect + pixel * 4;
+ rrgb[0] = rrgb[1] = rrgb[2] = FTOCHAR(value);
+ rrgb[3] = 255;
+ }
+
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+}
+
/* **************** Common functions public API relates on **************** */
static void count_images(MultiresBakeRender *bkr)
@@ -812,12 +1128,15 @@ static void bake_images(MultiresBakeRender *bkr)
switch (bkr->mode) {
case RE_BAKE_NORMALS:
- do_multires_bake(bkr, ima, apply_tangmat_callback, init_normal_data, NULL, free_normal_data);
+ do_multires_bake(bkr, ima, TRUE, apply_tangmat_callback, init_normal_data, NULL, free_normal_data);
break;
case RE_BAKE_DISPLACEMENT:
- do_multires_bake(bkr, ima, apply_heights_callback, init_heights_data,
+ do_multires_bake(bkr, ima, FALSE, apply_heights_callback, init_heights_data,
apply_heights_data, free_heights_data);
break;
+ case RE_BAKE_AO:
+ do_multires_bake(bkr, ima, FALSE, apply_ao_callback, init_ao_data, NULL, free_ao_data);
+ break;
}
}
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 127e0bc07b9..1224edd5591 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -94,7 +94,7 @@ static void RE_rayobject_config_control(RayObject *r, Render *re)
}
}
-static RayObject* RE_rayobject_create(Render *re, int type, int size)
+RayObject* RE_rayobject_create(Render *re, int type, int size)
{
RayObject * res = NULL;
@@ -117,7 +117,7 @@ static RayObject* RE_rayobject_create(Render *re, int type, int size)
if (type == R_RAYSTRUCTURE_OCTREE) //TODO dynamic ocres
- res = RE_rayobject_octree_create(re->r.ocres, size);
+ res = RE_rayobject_octree_create(re ? re->r.ocres : 128, size);
else if (type == R_RAYSTRUCTURE_BLIBVH)
res = RE_rayobject_blibvh_create(size);
else if (type == R_RAYSTRUCTURE_VBVH)
@@ -130,7 +130,7 @@ static RayObject* RE_rayobject_create(Render *re, int type, int size)
res = RE_rayobject_vbvh_create(size); //Fallback
- if (res)
+ if (res && re)
RE_rayobject_config_control(res, re);
return res;
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index 3431c3ff5de..bd0061c0e68 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -2795,4 +2795,3 @@ struct Image *RE_bake_shade_get_image(void)
{
return R.bakebuf;
}
-