diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2013-10-09 19:51:14 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2013-10-09 19:51:14 +0400 |
commit | d917bdb095573161522194449fc22f6809e5b5b2 (patch) | |
tree | 515874d441bd5547480e1a4714c45c03cb23ed2e /source/blender/render | |
parent | 1255b1e82dae4db4cc6f1fab1e80e831cbee583b (diff) |
Derivative map baker
Added support for derivative map baking, which
is accessable as a dedicated baker type. Works
pretty much the same as displacement map baker,
but gives you derivative map.
In fact, inernally this baker is just a filter
which applies on the result of displacement map.
Both regular and multires baking are supported.
Patch by Morten Mikkelsen and self.
Diffstat (limited to 'source/blender/render')
6 files changed, 219 insertions, 20 deletions
diff --git a/source/blender/render/extern/include/RE_multires_bake.h b/source/blender/render/extern/include/RE_multires_bake.h index 04cfe55e3a3..c1c5fc4a04d 100644 --- a/source/blender/render/extern/include/RE_multires_bake.h +++ b/source/blender/render/extern/include/RE_multires_bake.h @@ -37,21 +37,26 @@ struct MultiresBakeRender; typedef struct MultiresBakeRender { DerivedMesh *lores_dm, *hires_dm; - int simple, lvl, tot_lvl, bake_filter; - short mode, use_lores_mesh; + bool simple; + int bake_filter; /* Bake-filter, aka margin */ + int lvl, tot_lvl; + short mode; + bool use_lores_mesh; /* Use low-resolution mesh when baking displacement maps */ - int number_of_rays; - float bias; + int number_of_rays; /* Number of rays to be cast when doing AO baking */ + float bias; /* Bias between object and start ray point when doing AO baking */ int tot_obj, tot_image; ListBase image; int baked_objects, baked_faces; - int raytrace_structure; - int octree_resolution; - int threads; - + int raytrace_structure; /* Optimization structure to be used for AO baking */ + int octree_resolution; /* Reslution of octotree when using octotree optimization structure */ + int threads; /* Number of threads to be used for baking */ + + float user_scale; /* User scale used to scale displacement when baking derivative map. */ + short *stop; short *do_update; float *progress; diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 73a89ad884f..35d971ab976 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -281,6 +281,7 @@ int RE_seq_render_active(struct Scene *scene, struct RenderData *rd); #define RE_BAKE_MIRROR_INTENSITY 10 #define RE_BAKE_ALPHA 11 #define RE_BAKE_EMIT 12 +#define RE_BAKE_DERIVATIVE 13 void RE_Database_Baking(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, const int type, struct Object *actob); diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index 19ddfb7a13d..baec1a74721 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -213,6 +213,9 @@ int RE_bake_shade_all_selected(struct Render *re, int type, struct Object *actob struct Image *RE_bake_shade_get_image(void); void RE_bake_ibuf_filter(struct ImBuf *ibuf, char *mask, const int filter); void RE_bake_ibuf_normalize_displacement(struct ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max); +float RE_bake_make_derivative(struct ImBuf *ibuf, float *heights_buffer, const char *mask, + const float height_min, const float height_max, + const float fmult); #define BAKE_RESULT_OK 0 #define BAKE_RESULT_NO_OBJECTS 1 diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c index 6e70e670ff8..f4bbdb6add8 100644 --- a/source/blender/render/intern/source/bake.c +++ b/source/blender/render/intern/source/bake.c @@ -553,7 +553,7 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v) } } - if (bs->type == RE_BAKE_DISPLACEMENT) { + if (ELEM(bs->type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) { if (hit) bake_displacement(handle, shi, (dir == -1) ? mindist : -mindist, x, y); else @@ -688,7 +688,7 @@ static int get_next_bake_face(BakeShade *bs) if (R.r.bake_flag & R_BAKE_CLEAR) { if (R.r.bake_mode == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid); - else if (R.r.bake_mode == RE_BAKE_DISPLACEMENT) + else if (ELEM(R.r.bake_mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid); else IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); @@ -984,8 +984,10 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up use_mask = true; /* do we need buffer to store displacements */ - if (type == RE_BAKE_DISPLACEMENT) { - if ((R.r.bake_flag & R_BAKE_NORMALIZE) && R.r.bake_maxdist == 0.0f) { + if (ELEM(type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) { + if (((R.r.bake_flag & R_BAKE_NORMALIZE) && R.r.bake_maxdist == 0.0f) || + (type == RE_BAKE_DERIVATIVE)) + { use_displacement_buffer = true; use_mask = true; } @@ -1089,8 +1091,15 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up userdata = (BakeImBufuserData *)ibuf->userdata; if (userdata) { if (use_displacement_buffer) { - RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer, - displacement_min, displacement_max); + if (type == RE_BAKE_DERIVATIVE) { + float user_scale = (R.r.bake_flag & R_BAKE_USERSCALE) ? R.r.bake_user_scale : -1.0f; + RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer, + displacement_min, displacement_max, user_scale); + } + else { + RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer, + displacement_min, displacement_max); + } } RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter); @@ -1124,3 +1133,176 @@ struct Image *RE_bake_shade_get_image(void) return R.bakebuf; } +/* **************** Derivative Maps Baker **************** */ + +static void add_single_heights_margin(const ImBuf *ibuf, const char *mask, float *heights_buffer) +{ + int x ,y; + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + int index = ibuf->x * y + x; + + /* If unassigned pixel, look for neighbors. */ + if (mask[index] != FILTER_MASK_USED) { + float height_acc = 0; + int denom = 0; + int i, j; + + for (j = -1; j <= 1; j++) + for (i = -1; i <= 1; i++) { + int w = (i == 0 ? 1 : 0) + (j == 0 ? 1 : 0) + 1; + + if (i != 0 || j != 0) { + int index2 = 0; + int x0 = x + i; + int y0 = y + j; + + CLAMP(x0, 0, ibuf->x - 1); + CLAMP(y0, 0, ibuf->y - 1); + + index2 = ibuf->x * y0 + x0; + + if (mask[index2] == FILTER_MASK_USED) { + height_acc += w * heights_buffer[index2]; + denom += w; + } + } + } + + /* Insert final value. */ + if (denom > 0) { + heights_buffer[index] = height_acc / denom; + } + } + } + } +} + +/* returns user-scale */ +float RE_bake_make_derivative(ImBuf *ibuf, float *heights_buffer, const char *mask, + const float height_min, const float height_max, + const float fmult) +{ + const float delta_height = height_max - height_min; + const float denom = delta_height > 0.0f ? (8 * delta_height) : 1.0f; + bool auto_range_fit = fmult <= 0.0f; + float max_num_deriv = -1.0f; + int x, y, index; + + /* Need a single margin to calculate good derivatives. */ + add_single_heights_margin(ibuf, mask, heights_buffer); + + if (auto_range_fit) { + /* If automatic range fitting is enabled. */ + for (y = 0; y < ibuf->y; y++) { + const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y+1); + const int Yc = y; + const int Yd = y == 0 ? 0 : (y - 1); + + for (x= 0; x < ibuf->x; x++) { + const int Xl = x == 0 ? 0 : (x - 1); + const int Xc = x; + const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1); + + const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl]; + const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl]; + const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl]; + + const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl]; + const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc]; + const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr]; + + /* This corresponds to using the sobel kernel on the heights buffer + * to obtain the derivative multiplied by 8. + */ + const float deriv_x = Hu + 2 * Hcy + Hd; + const float deriv_y = Hr + 2 * Hcx + Hl; + + /* early out */ + index = ibuf->x * y + x; + if (mask[index] != FILTER_MASK_USED) { + continue; + } + + /* Widen bound. */ + if (fabsf(deriv_x) > max_num_deriv) { + max_num_deriv = fabsf(deriv_x); + } + + if (fabsf(deriv_y) > max_num_deriv) { + max_num_deriv = fabsf(deriv_y); + } + } + } + } + + /* Output derivatives. */ + auto_range_fit &= (max_num_deriv > 0); + for (y = 0; y < ibuf->y; y++) { + const int Yu= y==(ibuf->y-1) ? (ibuf->y-1) : (y+1); + const int Yc= y; + const int Yd= y==0 ? 0 : (y-1); + + for(x= 0; x<ibuf->x; x++) { + const int Xl = x == 0 ? 0 : (x - 1); + const int Xc = x; + const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1); + + const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl]; + const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl]; + const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl]; + + const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl]; + const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc]; + const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr]; + + /* This corresponds to using the sobel kernel on the heights buffer + * to obtain the derivative multiplied by 8. + */ + float deriv_x = Hu + 2 * Hcy + Hd; + float deriv_y = Hr + 2 * Hcx + Hl; + + /* Early out. */ + index = ibuf->x * y + x; + if (mask[index] != FILTER_MASK_USED){ + continue; + } + + if (auto_range_fit) { + deriv_x /= max_num_deriv; + deriv_y /= max_num_deriv; + } else { + deriv_x *= (fmult / denom); + deriv_y *= (fmult / denom); + } + + deriv_x = deriv_x * 0.5f + 0.5f; + deriv_y = deriv_y * 0.5f + 0.5f; + + /* Clamp. */ + CLAMP(deriv_x, 0.0f, 1.0f); + CLAMP(deriv_y, 0.0f, 1.0f); + + /* Write out derivatives. */ + if (ibuf->rect_float) { + float *rrgbf = ibuf->rect_float + index * 4; + + rrgbf[0] = deriv_x; + rrgbf[1] = deriv_y; + rrgbf[2] = 0.0f; + rrgbf[3] = 1.0f; + } else { + char *rrgb = (char*)ibuf->rect + index * 4; + + rrgb[0] = FTOCHAR(deriv_x); + rrgb[1] = FTOCHAR(deriv_y); + rrgb[2] = 0; + rrgb[3] = 255; + } + } + } + + /* Eeturn user-scale (for rendering). */ + return auto_range_fit ? (max_num_deriv / denom) : (fmult > 0.0f ? (1.0f / fmult) : 0.0f); +} diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index a0104a30d0e..b5377a07848 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -5983,6 +5983,7 @@ void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned * RE_BAKE_AO: for baking, no lamps, but all objects * RE_BAKE_TEXTURE:for baking, no lamps, only selected objects * RE_BAKE_DISPLACEMENT:for baking, no lamps, only selected objects + * RE_BAKE_DERIVATIVE:for baking, no lamps, only selected objects * RE_BAKE_SHADOW: for baking, only shadows, but all objects */ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, const int type, Object *actob) @@ -5991,7 +5992,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, float mat[4][4]; float amb[3]; const short onlyselected= !ELEM4(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO); - const short nolamps= ELEM3(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT); + const short nolamps= ELEM4(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE); re->main= bmain; re->scene= scene; @@ -6010,7 +6011,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, if (type==RE_BAKE_NORMALS && re->r.bake_normal_space==R_BAKE_SPACE_TANGENT) re->flag |= R_NEED_TANGENT; - if (!actob && ELEM4(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT)) { + if (!actob && ELEM5(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) { re->r.mode &= ~R_SHADOW; re->r.mode &= ~R_RAYTRACE; } diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c index a2fa37fd7ea..3259608c18f 100644 --- a/source/blender/render/intern/source/multires_bake.c +++ b/source/blender/render/intern/source/multires_bake.c @@ -124,7 +124,7 @@ typedef struct { 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) +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, data->mface[face_num].v3, data->mface[face_num].v4}; @@ -1231,6 +1231,7 @@ static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result) do_multires_bake(bkr, ima, TRUE, apply_tangmat_callback, init_normal_data, free_normal_data, result); break; case RE_BAKE_DISPLACEMENT: + case RE_BAKE_DERIVATIVE: do_multires_bake(bkr, ima, FALSE, apply_heights_callback, init_heights_data, free_heights_data, result); break; case RE_BAKE_AO: @@ -1248,7 +1249,7 @@ static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result) static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result) { LinkData *link; - int use_displacement_buffer = bkr->mode == RE_BAKE_DISPLACEMENT; + bool use_displacement_buffer = ELEM(bkr->mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE); for (link = bkr->image.first; link; link = link->next) { Image *ima = (Image *)link->data; @@ -1259,8 +1260,14 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result) continue; if (use_displacement_buffer) { - RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer, - result->height_min, result->height_max); + if (bkr->mode == RE_BAKE_DERIVATIVE) { + RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer, + result->height_min, result->height_max, bkr->user_scale); + } + else { + RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer, + result->height_min, result->height_max); + } } RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, bkr->bake_filter); |