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:
authorTon Roosendaal <ton@blender.org>2006-11-19 17:12:56 +0300
committerTon Roosendaal <ton@blender.org>2006-11-19 17:12:56 +0300
commitc47fa4d0ecefea3f32448cb89610a4cc28aac2bb (patch)
treeba3f59c3bfd5415de4480138fd383d651a56f13f /source/blender/render/intern
parent204f6066a9c9355aea28bd3092a74d12a52c7869 (diff)
Long waited feature: Render Baking
Here's the full release log with example file. http://www.blender3d.org/cms/Render_Baking.827.0.html For people who don't read docs; just press ALT+CTRL+B on a Mesh with texture faces! Todos: - maybe some filter options extra? - Make normal maps in Tangent space
Diffstat (limited to 'source/blender/render/intern')
-rw-r--r--source/blender/render/intern/include/zbuf.h3
-rw-r--r--source/blender/render/intern/source/convertblender.c79
-rw-r--r--source/blender/render/intern/source/ray.c4
-rw-r--r--source/blender/render/intern/source/rendercore.c247
-rw-r--r--source/blender/render/intern/source/zbuf.c90
5 files changed, 397 insertions, 26 deletions
diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h
index cd8ad8626db..993ca711a18 100644
--- a/source/blender/render/intern/include/zbuf.h
+++ b/source/blender/render/intern/include/zbuf.h
@@ -95,6 +95,9 @@ typedef struct ZSpan {
void zbufclip4(struct ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, float *f4, int c1, int c2, int c3, int c4);
void zbuf_free_span(struct ZSpan *zspan);
+/* to rendercore.c */
+void zspan_scanconvert(struct ZSpan *zpan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float) );
+
/* exported to edge render... */
void zbufclip(struct ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, int c2, int c3);
void zbuf_alloc_span(struct ZSpan *zspan, int rectx, int recty);
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index c294eea4896..42eb3c47155 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -3892,17 +3892,38 @@ void RE_DataBase_ApplyWindow(Render *re)
project_renderdata(re, projectverto, 0, 0);
}
-/* setup for shaded view, so only lamps and materials are initialized */
-void RE_Database_Shaded(Render *re, Scene *scene)
+/* setup for shaded view or bake, so only lamps and materials are initialized */
+/* type:
+ RE_BAKE_LIGHT: for shaded view, only add lamps
+ RE_BAKE_ALL: for baking, all lamps and objects
+ RE_BAKE_NORMALS:for baking, no lamps and only selected objects
+ RE_BAKE_AO: for baking, no lamps, but all objects
+*/
+void RE_Database_Baking(Render *re, Scene *scene, int type)
{
Base *base;
Object *ob;
Scene *sce;
+ GroupObject *go;
float mat[4][4];
unsigned int lay;
re->scene= scene;
+ /* renderdata setup and exceptions */
+ re->r= scene->r;
+ re->r.mode &= ~R_OSA;
+
+ if( ELEM(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS) ) {
+ re->r.mode &= ~R_SHADOW;
+ re->r.mode &= ~R_RAYTRACE;
+ }
+
+ /* setup render stuff */
+ if(type!=RE_BAKE_LIGHT)
+ re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+
+ re->totvlak=re->totvert=re->totlamp=re->tothalo= 0;
re->lights.first= re->lights.last= NULL;
/* in localview, lamps are using normal layers, objects only local bits */
@@ -3920,9 +3941,18 @@ void RE_Database_Shaded(Render *re, Scene *scene)
RE_SetView(re, mat);
}
- /* initializes global */
+ init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
+ if( (re->wrld.mode & WO_AMB_OCC) && (re->r.mode & R_RAYTRACE) ) {
+ re->wrld.aosphere= MEM_mallocN(2*3*re->wrld.aosamp*re->wrld.aosamp*sizeof(float), "AO sphere");
+ /* we make twice the amount of samples, because only a hemisphere is used */
+ init_ao_sphere(re->wrld.aosphere, 2*re->wrld.aosamp*re->wrld.aosamp, 16);
+ }
+
+ /* still bad... doing all */
+ init_render_textures(re);
+ init_render_materials(re->osa, &re->wrld.ambr);
set_node_shader_lamp_loop(shade_material_loop);
-
+
for(SETLOOPER(re->scene, base)) {
ob= base->object;
/* imat objects has to be done here, since displace can have texture using Object map-input */
@@ -3938,13 +3968,46 @@ void RE_Database_Shaded(Render *re, Scene *scene)
/* OB_DONE means the object itself got duplicated, so was already converted */
if(ob->flag & OB_DONE);
- else if(ob->type==OB_LAMP) {
- if( (base->lay & lay) || ((base->lay & re->scene->lay)) ) {
- init_render_object(re, ob, NULL, 0, 0);
+ else if( (base->lay & lay) || ((base->lay & re->scene->lay)) ) {
+ if(ob->type==OB_LAMP) {
+ if(type!=RE_BAKE_NORMALS && type!=RE_BAKE_AO)
+ init_render_object(re, ob, NULL, 0, 0);
+ }
+ else if(type!=RE_BAKE_LIGHT) {
+ if(type!=RE_BAKE_NORMALS || (ob->flag & SELECT))
+ init_render_object(re, ob, NULL, 0, 0);
+ }
+ }
+ }
+ set_material_lightgroups(re);
+
+ check_non_flat_quads(re);
+ /* don't call set_normalflags(), no flipping */
+
+ if(type!=RE_BAKE_LIGHT) {
+ if(re->r.mode & R_SHADOW) {
+ /* SHADOW BUFFER */
+ for(go=re->lights.first; go; go= go->next) {
+ LampRen *lar= go->lampren;
+
+ if(re->test_break()) break;
+ if(lar->shb) {
+ /* if type is irregular, this only sets the perspective matrix and autoclips */
+ /* but, that's not supported for bake... */
+ makeshadowbuf(re, lar);
+ }
+ }
+ }
+ }
+
+ if(type!=RE_BAKE_LIGHT) {
+ /* octree */
+ if(!re->test_break()) {
+ if(re->r.mode & R_RAYTRACE) {
+ makeoctree(re);
}
}
}
- set_material_lightgroups(re);
}
void RE_DataBase_GetView(Render *re, float mat[][4])
diff --git a/source/blender/render/intern/source/ray.c b/source/blender/render/intern/source/ray.c
index cb2004e901d..ca24f04a580 100644
--- a/source/blender/render/intern/source/ray.c
+++ b/source/blender/render/intern/source/ray.c
@@ -667,6 +667,10 @@ static int intersection2(VlakRen *vlr, float r0, float r1, float r2, float rx1,
float m0, m1, m2, divdet, det, det1;
float u1, v, u2;
+ /* happens for baking with non existing face */
+ if(vlr->v1==NULL)
+ return 1;
+
v1= vlr->v1;
v2= vlr->v2;
if(vlr->v4) {
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index ab74f4bfb84..b6da7a3ecb7 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -56,9 +56,13 @@
#include "BKE_global.h"
#include "BKE_material.h"
+#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_texture.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
/* local include */
#include "renderpipeline.h"
#include "render_types.h"
@@ -1934,6 +1938,28 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
}
+static void vlr_set_uv_indices(VlakRen *vlr, int *i1, int *i2, int *i3)
+{
+ /* to prevent storing new tfaces or vcols, we check a split runtime */
+ /* 4---3 4---3 */
+ /* |\ 1| or |1 /| */
+ /* |0\ | |/ 0| */
+ /* 1---2 1---2 0 = orig face, 1 = new face */
+
+ /* Update vert nums to point to correct verts of original face */
+ if(vlr->flag & R_DIVIDE_24) {
+ if(vlr->flag & R_FACE_SPLIT) {
+ (*i1)++; (*i2)++; (*i3)++;
+ }
+ else {
+ (*i3)++;
+ }
+ }
+ else if(vlr->flag & R_FACE_SPLIT) {
+ (*i2)++; (*i3)++;
+ }
+}
+
/* this function sets all coords for render (shared with raytracer) */
/* warning; exception for ortho render is here, can be done better! */
void shade_input_set_coords(ShadeInput *shi, float u, float v, int i1, int i2, int i3)
@@ -2202,24 +2228,8 @@ void shade_input_set_coords(ShadeInput *shi, float u, float v, int i1, int i2, i
if((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE))) {
int j1=i1, j2=i2, j3=i3;
- /* to prevent storing new tfaces or vcols, we check a split runtime */
- /* 4---3 4---3 */
- /* |\ 1| or |1 /| */
- /* |0\ | |/ 0| */
- /* 1---2 1---2 0 = orig face, 1 = new face */
-
- /* Update vert nums to point to correct verts of original face */
- if(vlr->flag & R_DIVIDE_24) {
- if(vlr->flag & R_FACE_SPLIT) {
- j1++; j2++; j3++;
- }
- else {
- j3++;
- }
- }
- else if(vlr->flag & R_FACE_SPLIT) {
- j2++; j3++;
- }
+ /* uv and vcols are not copied on split, so set them according vlr divide flag */
+ vlr_set_uv_indices(vlr, &j1, &j2, &j3);
if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) {
@@ -3653,5 +3663,206 @@ void RE_shade_external(Render *re, ShadeInput *shi, ShadeResult *shr)
shade_material_loop(shi, shr);
}
}
+/* ************************* bake ************************ */
+
+#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
+
+typedef struct BakeShade {
+ ShadeInput shi;
+ VlakRen *vlr;
+
+ int rectx, recty, quad, type;
+ unsigned int *rect;
+ float *rect_float;
+} BakeShade;
+static void do_bake_shade(void *handle, int x, int y, float u, float v)
+{
+ BakeShade *bs= handle;
+ ShadeInput *shi= &bs->shi;
+ ShadeResult shr;
+ VlakRen *vlr= bs->vlr;
+ float l, *v1, *v2, *v3;
+
+ shi->xs= x;
+ shi->ys= y;
+
+ /* setup render coordinates, it's a copy of shade_ray mostly, but different.
+ like for shadepixel, useful to restructure once. */
+ if(bs->quad) {
+ v1= vlr->v1->co;
+ v2= vlr->v3->co;
+ v3= vlr->v4->co;
+ }
+ else {
+ v1= vlr->v1->co;
+ v2= vlr->v2->co;
+ v3= vlr->v3->co;
+ }
+
+ /* renderco */
+ l= 1.0-u-v;
+
+ shi->co[0]= l*v3[0]+u*v1[0]+v*v2[0];
+ shi->co[1]= l*v3[1]+u*v1[1]+v*v2[1];
+ shi->co[2]= l*v3[2]+u*v1[2]+v*v2[2];
+
+ /* set up view vector */
+ VECCOPY(shi->view, shi->co);
+ Normalise(shi->view);
+
+ shi->vlr= vlr;
+ shi->mat= vlr->mat;
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h
+ shi->har= shi->mat->har;
+
+ /* no face normal flip */
+ VECCOPY(shi->facenor, vlr->n);
+ shi->puno= vlr->puno;
+ if(bs->quad)
+ shade_input_set_coords(shi, -u, -v, 0, 3, 4);
+ else
+ shade_input_set_coords(shi, -u, -v, 0, 1, 2);
+
+ if(bs->type==RE_BAKE_AO) {
+ shr.ao[0]= shr.ao[1]= shr.ao[2]= 0.0f;
+ ambient_occlusion(shi, &shr);
+ VECCOPY(shr.diff, shr.ao);
+ }
+ else {
+ if(shi->mat->nodetree && shi->mat->use_nodes) {
+ ntreeShaderExecTree(shi->mat->nodetree, shi, &shr);
+ shi->mat= vlr->mat; /* shi->mat is being set in nodetree */
+ }
+ else
+ shade_material_loop(shi, &shr);
+
+ if(bs->type==RE_BAKE_NORMALS) {
+ shr.diff[0]= shi->vn[0]/2.0f + 0.5f;
+ shr.diff[1]= 0.5f - shi->vn[1]/2.0f;
+ shr.diff[2]= shi->vn[2]/2.0f + 0.5f;
+ }
+ }
+
+ if(bs->rect) {
+ char *col= (char *)(bs->rect + bs->rectx*y + x);
+ col[0]= FTOCHAR(shr.diff[0]);
+ col[1]= FTOCHAR(shr.diff[1]);
+ col[2]= FTOCHAR(shr.diff[2]);
+ col[3]= 255;
+ }
+ else {
+ float *col= bs->rect_float + 4*(bs->rectx*y + x);
+ VECCOPY(col, shr.diff);
+ col[3]= 1.0f;
+ }
+}
+
+/* already have tested for tface and ima */
+static void shade_tface(BakeShade *bs, VlakRen *vlr)
+{
+ TFace *tface= vlr->tface;
+ Image *ima= tface->tpage;
+ ZSpan *zspan= (ZSpan *)ima->id.newid;
+ float vec[4][2];
+ int a, i1, i2, i3;
+
+ if(ima->ibuf==NULL)
+ return;
+
+ /* signal we find this image for the first time */
+ if(zspan==NULL) {
+ if(ima->ibuf->rect==NULL && ima->ibuf->rect_float==NULL)
+ return;
+ /* we either fill in float or char, this ensures things go fine */
+ if(ima->ibuf->rect_float)
+ imb_freerectImBuf(ima->ibuf);
+
+ zspan= MEM_mallocN(sizeof(ZSpan), "zspan for bake");
+ zbuf_alloc_span(zspan, ima->ibuf->x, ima->ibuf->y);
+ ima->id.newid= (ID *)zspan;
+
+ memset(vec, 0, sizeof(vec));
+ IMB_rectfill(ima->ibuf, vec[0]);
+ }
+
+ bs->vlr= vlr;
+ bs->rectx= ima->ibuf->x;
+ bs->recty= ima->ibuf->y;
+ bs->rect= ima->ibuf->rect;
+ bs->rect_float= ima->ibuf->rect_float;
+ bs->quad= 0;
+
+ /* get pixel level vertex coordinates */
+ for(a=0; a<4; a++) {
+ vec[a][0]= tface->uv[a][0]*(float)bs->rectx - 0.5f;
+ vec[a][1]= tface->uv[a][1]*(float)bs->recty - 0.5f;
+ }
+
+ /* UV indices have to be corrected for possible quad->tria splits */
+ i1= 0; i2= 1; i3= 2;
+ vlr_set_uv_indices(vlr, &i1, &i2, &i3);
+ zspan_scanconvert(zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade);
+
+ if(vlr->v4) {
+ bs->quad= 1;
+ zspan_scanconvert(zspan, bs, vec[0], vec[2], vec[3], do_bake_shade);
+ }
+}
+
+/* using object selection tags, the faces with UV maps get baked */
+/* render should have been setup */
+void RE_bake_shade_all_selected(Render *re, int type)
+{
+ BakeShade handle;
+ Image *ima;
+ VlakRen *vlr= NULL;
+ int v, vdone=0;
+
+ /* initialize render global */
+ R= *re;
+
+ /* set defaults in handle */
+ memset(&handle, 0, sizeof(BakeShade));
+ handle.shi.lay= re->scene->lay;
+ handle.type= type;
+
+ /* baker abuses newid for zspans */
+ for(ima= G.main->image.first; ima; ima= ima->id.next)
+ ima->id.newid= NULL;
+
+ for(v=0; v<R.totvlak; v++) {
+ if((v & 255)==0)
+ vlr= R.blovl[v>>8];
+ else vlr++;
+
+ if(vlr->ob->flag & SELECT) {
+ if(vlr->tface && vlr->tface->tpage) {
+ shade_tface(&handle, vlr);
+ vdone++;
+
+ if((vdone & 1023)==1)
+ R.timecursor(vdone>>10);
+
+ if(R.test_break()) break;
+ }
+ }
+ }
+
+ /* free zspans, filter images */
+ for(ima= G.main->image.first; ima; ima= ima->id.next) {
+ if(ima->id.newid) {
+ extern void free_realtime_image(Image *ima); /* bad level call */
+
+ zbuf_free_span((ZSpan *)ima->id.newid);
+ MEM_freeN(ima->id.newid);
+ ima->id.newid= NULL;
+
+ IMB_filter_extend(ima->ibuf);
+ ima->ibuf->userflags |= IB_BITMAPDIRTY;
+ free_realtime_image(ima); /* force OpenGL reload */
+ }
+ }
+
+}
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 1b8a658e827..737f4884ddd 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -1308,6 +1308,96 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int zvlnr, float *v1, float *v2, floa
}
}
+/* 2d scanconvert for tria, calls func for each x,y coordinate and gives UV barycentrics */
+/* zspan should be initialized, has rect size and span buffers */
+
+void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float) )
+{
+ float x0, y0, x1, y1, x2, y2, z0, z1, z2;
+ float u, v, uxd, uyd, vxd, vyd, uy0, vy0, xx1;
+ float *span1, *span2;
+ int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
+
+ /* init */
+ zbuf_init_span(zspan);
+
+ /* set spans */
+ zbuf_add_to_span(zspan, v1, v2);
+ zbuf_add_to_span(zspan, v2, v3);
+ zbuf_add_to_span(zspan, v3, v1);
+
+ /* clipped */
+ if(zspan->minp2==NULL || zspan->maxp2==NULL) return;
+
+ if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
+ if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+
+ // printf("my %d %d\n", my0, my2);
+ if(my2<my0) return;
+
+ /* ZBUF DX DY, in floats still */
+ x1= v1[0]- v2[0];
+ x2= v2[0]- v3[0];
+ y1= v1[1]- v2[1];
+ y2= v2[1]- v3[1];
+
+ z1= 1.0f; // (u1 - u2)
+ z2= 0.0f; // (u2 - u3)
+
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+ z0= x1*y2-y1*x2;
+
+ if(z0==0.0f) return;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0 + 1.0f;
+ uxd= -(double)x0/(double)z0;
+ uyd= -(double)y0/(double)z0;
+ uy0= ((double)my2)*uyd + (double)xx1;
+
+ z1= -1.0f; // (v1 - v2)
+ z2= 1.0f; // (v2 - v3)
+
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0;
+ vxd= -(double)x0/(double)z0;
+ vyd= -(double)y0/(double)z0;
+ vy0= ((double)my2)*vyd + (double)xx1;
+
+ /* correct span */
+ sn1= (my0 + my2)/2;
+ if(zspan->span1[sn1] < zspan->span2[sn1]) {
+ span1= zspan->span1+my2;
+ span2= zspan->span2+my2;
+ }
+ else {
+ span1= zspan->span2+my2;
+ span2= zspan->span1+my2;
+ }
+
+ for(y=my2; y>=my0; y--, span1--, span2--) {
+
+ sn1= floor(*span1);
+ sn2= floor(*span2);
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+
+ u= (double)sn1*uxd + uy0;
+ v= (double)sn1*vxd + vy0;
+
+ for(x= sn1; x<=sn2; x++, u+=uxd, v+=vxd)
+ func(handle, x, y, u, v);
+
+ uy0 -= uyd;
+ vy0 -= vyd;
+ }
+}
+
+
/**
* (clip pyramid)