* Displacement map baking

This is an extension on the work Brecht already did to implement normal map baking. I've updated the release notes page here with info and pics:

http://www.blender.org/development/current-projects/changes-since-244/render-baking/
This commit is contained in:
Matt Ebb
2007-12-29 05:17:19 +00:00
parent 02b00e2fd7
commit 3c1ad6a295
13 changed files with 197 additions and 54 deletions

View File

@@ -114,7 +114,7 @@ struct ImBuf *BKE_image_get_ibuf(struct Image *ima, struct ImageUser *iuser);
struct Image *BKE_add_image_file(const char *name);
/* adds image, adds ibuf, generates color or pattern */
struct Image *BKE_add_image_size(int width, int height, char *name, short uvtestgrid, float color[4]);
struct Image *BKE_add_image_size(int width, int height, char *name, int floatbuf, short uvtestgrid, float color[4]);
/* for reload, refresh, pack */
void BKE_image_signal(struct Image *ima, struct ImageUser *iuser, int signal);

View File

@@ -378,20 +378,27 @@ Image *BKE_add_image_file(const char *name)
return ima;
}
static ImBuf *add_ibuf_size(int width, int height, char *name, short uvtestgrid, float color[4])
static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, short uvtestgrid, float color[4])
{
ImBuf *ibuf;
float h=0.0, hoffs=0.0, hue=0.0, s=0.9, v=0.9, r, g, b;
unsigned char *rect;
float *rect_float;
int x, y;
int checkerwidth=21, dark=1;
ibuf= IMB_allocImBuf(width, height, 24, IB_rect, 0);
if (floatbuf) {
ibuf= IMB_allocImBuf(width, height, 24, IB_rectfloat, 0);
rect_float= (float*)ibuf->rect_float;
}
else {
ibuf= IMB_allocImBuf(width, height, 24, IB_rect, 0);
rect= (unsigned char*)ibuf->rect;
}
strcpy(ibuf->name, "Untitled");
ibuf->userflags |= IB_BITMAPDIRTY;
rect= (unsigned char*)ibuf->rect;
if (uvtestgrid) {
/* these two passes could be combined into one, but it's more readable and
* easy to tweak like this, speed isn't really that much of an issue in this situation... */
@@ -400,26 +407,40 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, short uvtestgrid,
for(y=0; y<ibuf->y; y++) {
dark = pow(-1, floor(y / checkerwidth));
for(x=0; x<ibuf->x; x++, rect+=4) {
for(x=0; x<ibuf->x; x++) {
if (x % checkerwidth == 0) dark *= -1;
if (dark > 0) {
rect[0] = rect[1] = rect[2] = 64;
rect[3] = 255;
} else {
rect[0] = rect[1] = rect[2] = 150;
rect[3] = 255;
if (floatbuf) {
if (dark > 0) {
rect_float[0] = rect_float[1] = rect_float[2] = 0.25;
rect_float[3] = 1.0;
} else {
rect_float[0] = rect_float[1] = rect_float[2] = 0.58;
rect_float[3] = 1.0;
}
rect_float+=4;
}
else {
if (dark > 0) {
rect[0] = rect[1] = rect[2] = 64;
rect[3] = 255;
} else {
rect[0] = rect[1] = rect[2] = 150;
rect[3] = 255;
}
rect += 4;
}
}
}
/* 2nd pass, colored + */
rect= (unsigned char*)ibuf->rect;
if (floatbuf) rect_float= (float*)ibuf->rect_float;
else rect= (unsigned char*)ibuf->rect;
for(y=0; y<ibuf->y; y++) {
hoffs = 0.125 * floor(y / checkerwidth);
for(x=0; x<ibuf->x; x++, rect+=4) {
for(x=0; x<ibuf->x; x++) {
h = 0.125 * floor(x / checkerwidth);
if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
@@ -431,10 +452,20 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, short uvtestgrid,
hue = fmod(fabs(h-hoffs), 1.0);
hsv_to_rgb(hue, s, v, &r, &g, &b);
rect[0]= (char)(r * 255.0);
rect[1]= (char)(g * 255.0);
rect[2]= (char)(b * 255.0);
rect[3]= 255;
if (floatbuf) {
rect_float[0]= r;
rect_float[1]= g;
rect_float[2]= b;
rect_float[3]= 1.0;
rect_float+=4;
}
else {
rect[0]= (char)(r * 255.0);
rect[1]= (char)(g * 255.0);
rect[2]= (char)(b * 255.0);
rect[3]= 255;
rect+=4;
}
}
}
@@ -442,11 +473,21 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, short uvtestgrid,
}
} else { /* blank image */
for(y=0; y<ibuf->y; y++) {
for(x=0; x<ibuf->x; x++, rect+=4) {
rect[0]= (char)(color[0] * 255.0);
rect[1]= (char)(color[1] * 255.0);
rect[2]= (char)(color[2] * 255.0);
rect[3]= (char)(color[3] * 255.0);
for(x=0; x<ibuf->x; x++) {
if (floatbuf) {
rect_float[0]= color[0];
rect_float[1]= color[1];
rect_float[2]= color[2];
rect_float[3]= color[3];
rect_float+=4;
}
else {
rect[0]= (char)(color[0] * 255.0);
rect[1]= (char)(color[1] * 255.0);
rect[2]= (char)(color[2] * 255.0);
rect[3]= (char)(color[3] * 255.0);
rect+=4;
}
}
}
}
@@ -454,7 +495,7 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, short uvtestgrid,
}
/* adds new image block, creates ImBuf and initializes color */
Image *BKE_add_image_size(int width, int height, char *name, short uvtestgrid, float color[4])
Image *BKE_add_image_size(int width, int height, char *name, int floatbuf, short uvtestgrid, float color[4])
{
Image *ima;
@@ -469,7 +510,7 @@ Image *BKE_add_image_size(int width, int height, char *name, short uvtestgrid, f
ima->gen_y= height;
ima->gen_type= uvtestgrid;
ibuf= add_ibuf_size(width, height, name, uvtestgrid, color);
ibuf= add_ibuf_size(width, height, name, floatbuf, uvtestgrid, color);
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
ima->ok= IMA_OK_LOADED;
@@ -1678,6 +1719,7 @@ ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser)
{
ImBuf *ibuf= NULL;
float color[] = {0, 0, 0, 1};
int floatbuf;
/* quick reject tests */
if(ima==NULL)
@@ -1755,7 +1797,7 @@ ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser)
/* UV testgrid or black or solid etc */
if(ima->gen_x==0) ima->gen_x= 256;
if(ima->gen_y==0) ima->gen_y= 256;
ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, ima->gen_type, color);
ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, floatbuf, ima->gen_type, color);
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
ima->ok= IMA_OK_LOADED;
}

View File

@@ -242,7 +242,7 @@ void IMB_filter(struct ImBuf *ibuf)
#define EXTEND_PIXEL(a, w) if((a)[3]) {r+= w*(a)[0]; g+= w*(a)[1]; b+= w*(a)[2]; tot+=w;}
/* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 255 */
/* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0 */
void IMB_filter_extend(struct ImBuf *ibuf)
{
register char *row1, *row2, *row3;
@@ -251,7 +251,57 @@ void IMB_filter_extend(struct ImBuf *ibuf)
rowlen= ibuf->x;
if(ibuf->rect) {
if (ibuf->rect_float) {
float *temprect;
float *row1f, *row2f, *row3f;
float *fp;
int pixlen = 4;
temprect= MEM_dupallocN(ibuf->rect_float);
for(y=1; y<=ibuf->y; y++) {
/* setup rows */
row1f= (float *)(temprect + (y-2)*rowlen*4);
row2f= row1f + 4*rowlen;
row3f= row2f + 4*rowlen;
if(y==1)
row1f= row2f;
else if(y==ibuf->y)
row3f= row2f;
fp= (float *)(ibuf->rect_float + (y-1)*rowlen*4);
for(x=0; x<rowlen; x++) {
if(fp[3]==0.0f) {
int tot= 0;
float r=0.0f, g=0.0f, b=0.0f;
EXTEND_PIXEL(row1f, 1);
EXTEND_PIXEL(row2f, 2);
EXTEND_PIXEL(row3f, 1);
EXTEND_PIXEL(row1f+4, 2);
EXTEND_PIXEL(row3f+4, 2);
if(x!=rowlen-1) {
EXTEND_PIXEL(row1f+8, 1);
EXTEND_PIXEL(row2f+8, 2);
EXTEND_PIXEL(row3f+8, 1);
}
if(tot) {
fp[0]= r/tot;
fp[1]= g/tot;
fp[2]= b/tot;
fp[3]= 1.0;
}
}
fp+=4;
if(x!=0) {
row1f+=4; row2f+=4; row3f+=4;
}
}
}
}
else if(ibuf->rect) {
int *temprect;
/* make a copy, to prevent flooding */

View File

@@ -1,5 +1,5 @@
/*
* $Id: Image.c 11241 2007-07-12 11:51:21Z campbellbarton $
* $Id$
*
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
*
@@ -243,7 +243,7 @@ static PyObject *M_Image_New( PyObject * self, PyObject * args)
if (width > 5000 || height > 5000 || width < 1 || height < 1)
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"Image width and height must be between 1 and 5000" ) );
image = BKE_add_image_size(width, height, name, 0, color);
image = BKE_add_image_size(width, height, name, 0, 0, color);
if( !image )
return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
"couldn't create PyObject Image_Type" ) );

View File

@@ -1,5 +1,5 @@
/*
* $Id: bpy_data.c 12056 2007-09-17 06:11:06Z aligorith $
* $Id$
*
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
*
@@ -538,7 +538,7 @@ PyObject *LibBlockSeq_new(BPy_LibBlockSeq *self, PyObject * args, PyObject *kwd)
break;
case ID_IM:
{
id = (ID *)BKE_add_image_size(img_width, img_height, name?name:"Image", 0, color);
id = (ID *)BKE_add_image_size(img_width, img_height, name?name:"Image", 0, 0, color);
if( !id )
return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
"couldn't create PyObject Image_Type" ) );

View File

@@ -206,11 +206,12 @@ float RE_filter_value(int type, float x);
void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect);
/* shaded view or baking options */
#define RE_BAKE_LIGHT 0
#define RE_BAKE_ALL 1
#define RE_BAKE_AO 2
#define RE_BAKE_NORMALS 3
#define RE_BAKE_TEXTURE 4
#define RE_BAKE_LIGHT 0
#define RE_BAKE_ALL 1
#define RE_BAKE_AO 2
#define RE_BAKE_NORMALS 3
#define RE_BAKE_TEXTURE 4
#define RE_BAKE_DISPLACEMENT 5
void RE_Database_Baking(struct Render *re, struct Scene *scene, int type, struct Object *actob);
void RE_DataBase_GetView(struct Render *re, float mat[][4]);

View File

@@ -4706,6 +4706,7 @@ void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
RE_BAKE_NORMALS:for baking, no lamps and only selected objects
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
*/
void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
{
@@ -4724,7 +4725,7 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
if(type==RE_BAKE_NORMALS && re->r.bake_normal_space==R_BAKE_SPACE_TANGENT)
re->flag |= R_NEED_TANGENT;
if(!actob && ELEM3(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE)) {
if(!actob && ELEM4(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT)) {
re->r.mode &= ~R_SHADOW;
re->r.mode &= ~R_RAYTRACE;
}
@@ -4767,7 +4768,7 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
/* MAKE RENDER DATA */
nolamps= !ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL);
onlyselected= ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE);
onlyselected= ELEM3(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT);
database_init_objects(re, lay, nolamps, onlyselected, actob, 0);

View File

@@ -1870,6 +1870,26 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int quad, int
}
}
static void bake_displacement(void *handle, ShadeInput *shi, Isect *isec, int dir, int x, int y)
{
BakeShade *bs= handle;
float disp;
disp = 0.5 + (isec->labda*VecLength(isec->vec) * -dir);
if(bs->rect_float) {
float *col= bs->rect_float + 4*(bs->rectx*y + x);
col[0] = col[1] = col[2] = disp;
col[3]= 1.0f;
} else {
char *col= (char *)(bs->rect + bs->rectx*y + x);
col[0]= FTOCHAR(disp);
col[1]= FTOCHAR(disp);
col[2]= FTOCHAR(disp);
col[3]= 255;
}
}
static int bake_check_intersect(Isect *is, RayFace *face)
{
VlakRen *vlr = (VlakRen*)face;
@@ -1956,7 +1976,7 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
if(bs->actob) {
Isect isec, minisec;
float co[3], minco[3];
int hit, sign;
int hit, sign, dir;
/* intersect with ray going forward and backward*/
hit= 0;
@@ -1978,10 +1998,16 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
minisec= isec;
VECCOPY(minco, co);
hit= 1;
dir = sign;
}
}
}
if (hit && bs->type==RE_BAKE_DISPLACEMENT) {;
bake_displacement(handle, shi, &minisec, dir, x, y);
return;
}
/* if hit, we shade from the new point, otherwise from point one starting face */
if(hit) {
vlr= (VlakRen*)minisec.face;
@@ -1993,6 +2019,8 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
v= -minisec.v;
bake_set_shade_input(obi, vlr, shi, quad, 1, x, y, u, v);
}
}
if(bs->type==RE_BAKE_NORMALS && R.r.bake_normal_space==R_BAKE_SPACE_TANGENT)
@@ -2184,13 +2212,15 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob)
break;
}
/* filter images */
/* filter and refresh images */
for(ima= G.main->image.first; ima; ima= ima->id.next) {
if((ima->id.flag & LIB_DOIT)==0) {
ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
for(a=0; a<re->r.bake_filter; a++)
IMB_filter_extend(ibuf);
ibuf->userflags |= IB_BITMAPDIRTY;
if (ibuf->rect_float) IMB_rect_from_float(ibuf);
}
}

View File

@@ -1895,11 +1895,12 @@ static void render_panel_bake(void)
uiDefButS(block, ROW,B_REDR,"Ambient Occlusion",210,150,120,20,&G.scene->r.bake_mode, 1.0, RE_BAKE_AO, 0, 0, "");
uiDefButS(block, ROW,B_REDR,"Normals", 210,130,120,20,&G.scene->r.bake_mode, 1.0, RE_BAKE_NORMALS, 0, 0, "");
uiDefButS(block, ROW,B_REDR,"Textures", 210,110,120,20,&G.scene->r.bake_mode, 1.0, RE_BAKE_TEXTURE, 0, 0, "");
uiDefButS(block, ROW,B_REDR,"Displacement", 210,90,120,20,&G.scene->r.bake_mode, 1.0, RE_BAKE_DISPLACEMENT, 0, 0, "");
uiBlockEndAlign(block);
uiDefButBitS(block, TOG, R_BAKE_CLEAR, B_DIFF, "Clear", 210,80,120,20,&G.scene->r.bake_flag, 0.0, 0, 0, 0, "Clear Images before baking");
uiDefButBitS(block, TOG, R_BAKE_CLEAR, B_DIFF, "Clear", 210,60,120,20,&G.scene->r.bake_flag, 0.0, 0, 0, 0, "Clear Images before baking");
uiDefButS(block, NUM, B_DIFF,"Margin:", 210,50,120,20,&G.scene->r.bake_filter, 0.0, 32.0, 0, 0, "Amount of pixels to extend the baked result with, as post process filter");
uiDefButS(block, NUM, B_DIFF,"Margin:", 210,30,120,20,&G.scene->r.bake_filter, 0.0, 32.0, 0, 0, "Amount of pixels to extend the baked result with, as post process filter");
}
static void render_panel_render(void)

View File

@@ -2218,6 +2218,7 @@ void new_image_sima(void)
{
static int width= 1024, height= 1024;
static short uvtestgrid= 0;
static int floatbuf=0;
static float color[] = {0, 0, 0, 1};
char name[22];
Image *ima;
@@ -2230,10 +2231,11 @@ void new_image_sima(void)
add_numbut(3, COL, "", 0, 0, &color, NULL);
add_numbut(4, NUM|FLO, "Alpha:", 0.0, 1.0, &color[3], NULL);
add_numbut(5, TOG|SHO, "UV Test Grid", 0, 0, &uvtestgrid, NULL);
if (!do_clever_numbuts("New Image", 6, REDRAW))
add_numbut(6, TOG|INT, "32 bit Float", 0, 0, &floatbuf, NULL);
if (!do_clever_numbuts("New Image", 7, REDRAW))
return;
ima = BKE_add_image_size(width, height, name, uvtestgrid, color);
ima = BKE_add_image_size(width, height, name, floatbuf, uvtestgrid, color);
image_changed(G.sima, ima);
BKE_image_signal(G.sima->image, &G.sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE);
BIF_undo_push("Add image");

View File

@@ -1724,8 +1724,13 @@ static uiBlock *info_timelinemenu(void *arg_unused)
void do_info_render_bakemenu(void *arg, int event)
{
objects_bake_render(event);
switch (event) {
case R_BAKE_TO_ACTIVE:
G.scene->r.bake_flag ^= event;
break;
default:
objects_bake_render(event);
}
allqueue(REDRAWINFO, 0);
}
@@ -1733,15 +1738,24 @@ void do_info_render_bakemenu(void *arg, int event)
static uiBlock *info_render_bakemenu(void *arg_unused)
{
uiBlock *block;
short yco= 0;
short yco= 0, menuwidth=160;
block= uiNewBlock(&curarea->uiblocks, "render_bakemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
uiBlockSetButmFunc(block, do_info_render_bakemenu, NULL);
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Full Render|Ctrl Alt B, 1", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 1, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Ambient Occlusion|Ctrl Alt B, 2", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 2, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Normals|Ctrl Alt B, 3", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 3, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Texture Only|Ctrl Alt B, 4", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 4, "");
if(G.scene->r.bake_flag & R_BAKE_TO_ACTIVE) {
uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Selected to Active", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, R_BAKE_TO_ACTIVE, "");
} else {
uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Selected to Active", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, R_BAKE_TO_ACTIVE, "");
}
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Full Render|Ctrl Alt B, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Ambient Occlusion|Ctrl Alt B, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Normals|Ctrl Alt B, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Texture Only|Ctrl Alt B, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Displacement|Ctrl Alt B, 5", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
uiBlockSetDirection(block, UI_RIGHT);
uiTextBoundsBlock(block, 50);

View File

@@ -1009,7 +1009,7 @@ void objects_bake_render_menu(void)
{
short event;
event= pupmenu("Bake Selected Meshes %t|Full Render %x1|Ambient Occlusion %x2|Normals %x3|Texture Only %x4");
event= pupmenu("Bake Selected Meshes %t|Full Render %x1|Ambient Occlusion %x2|Normals %x3|Texture Only %x4|Displacement %x5");
objects_bake_render(event);
}
@@ -1043,7 +1043,8 @@ void objects_bake_render(short event)
if(event==1) event= RE_BAKE_ALL;
else if(event==2) event= RE_BAKE_AO;
else if(event==3) event= RE_BAKE_NORMALS;
else event= RE_BAKE_TEXTURE;
else if(event==4) event= RE_BAKE_TEXTURE;
else event= RE_BAKE_DISPLACEMENT;
if(event==RE_BAKE_AO) {
if(G.scene->world==NULL) {

View File

@@ -295,6 +295,7 @@ void b_verse_pop_node(VNode *vnode)
vbitmap->height,
vnode->name,
0,
0,
color);
((Image*)vbitmap->image)->vnode = (void*)vnode;
sync_blender_image_with_verse_bitmap_node(vnode);