Index: source/blender/render/intern/source/occlusion.c =================================================================== --- source/blender/render/intern/source/occlusion.c (revision 14978) +++ source/blender/render/intern/source/occlusion.c (working copy) @@ -1341,7 +1341,7 @@ skycol[2]= (1.0f-fac)*re->wrld.horb + fac*re->wrld.zenb; } #if 0 - else { /* WO_AOSKYTEX */ + else if (aocolor == WO_AOSKYTEX) { float dxyview[3]; bn[0]= -bn[0]; bn[1]= -bn[1]; @@ -1350,8 +1350,15 @@ dxyview[1]= 1.0f; dxyview[2]= 0.0f; shadeSkyView(skycol, co, bn, dxyview); +#endif + else { /* WO_AODIFFUSESH */ + float bentnor[3]; + + VECCOPY(bentnor, bn); + Mat4Mul3Vecfl(re->viewinv, bentnor); + + IBL_diffusesh_getcolor(skycol, (float *)re->ibl_sh_coeffs, bentnor); } -#endif VecMulf(skycol, occlusion); } Index: source/blender/render/intern/source/rayshade.c =================================================================== --- source/blender/render/intern/source/rayshade.c (revision 14978) +++ source/blender/render/intern/source/rayshade.c (working copy) @@ -1536,6 +1536,9 @@ float dxyview[3], skyadded=0, div; int aocolor; + float bentnor[3]; + int noradded=0; + isec.faceorig= (RayFace*)shi->vlr; isec.oborig= RAY_OBJECT_SET(&R, shi->obi); isec.face_last= NULL; @@ -1544,6 +1547,7 @@ isec.lay= -1; shadfac[0]= shadfac[1]= shadfac[2]= 0.0f; + bentnor[0]= bentnor[1]= bentnor[2]= 0.0f; /* prevent sky colors to be added for only shadow (shadow becomes alpha) */ aocolor= R.wrld.aocolor; @@ -1604,29 +1608,35 @@ if(RE_ray_tree_intersect(R.raytree, &isec)) { if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.labda*R.wrld.aodistfac); else fac+= 1.0f; - } - else if(aocolor!=WO_AOPLAIN) { - float skycol[4]; - float skyfac, view[3]; + } else { - view[0]= -dir[0]; - view[1]= -dir[1]; - view[2]= -dir[2]; - Normalize(view); - - if(aocolor==WO_AOSKYCOL) { - skyfac= 0.5*(1.0f+view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2]); - shadfac[0]+= (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr; - shadfac[1]+= (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng; - shadfac[2]+= (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb; + + if(aocolor!=WO_AOPLAIN) { + float skycol[4]; + float skyfac, view[3]; + + view[0]= -dir[0]; + view[1]= -dir[1]; + view[2]= -dir[2]; + Normalize(view); + + VecAddf(bentnor, bentnor, view); + noradded++; + + if(aocolor==WO_AOSKYCOL) { + skyfac= 0.5*(1.0f+view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2]); + shadfac[0]+= (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr; + shadfac[1]+= (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng; + shadfac[2]+= (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb; + } + else if (aocolor==WO_AOSKYTEX) { + shadeSkyView(skycol, isec.start, view, dxyview); + shadfac[0]+= skycol[0]; + shadfac[1]+= skycol[1]; + shadfac[2]+= skycol[2]; + } + skyadded++; } - else { /* WO_AOSKYTEX */ - shadeSkyView(skycol, isec.start, view, dxyview); - shadfac[0]+= skycol[0]; - shadfac[1]+= skycol[1]; - shadfac[2]+= skycol[2]; - } - skyadded++; } samples++; @@ -1642,9 +1652,22 @@ } } - if(aocolor!=WO_AOPLAIN && skyadded) { - div= (1.0f - fac/(float)samples)/((float)skyadded); + if (aocolor == WO_AODIFFUSESH && G.rt!=1 && noradded > 0) { + VecMulf(bentnor, (1.0f / (float)noradded)); + Mat4Mul3Vecfl(R.viewinv, bentnor); + + IBL_diffusesh_getcolor(shadfac, (float *)R.ibl_sh_coeffs, bentnor); + + /* multiply by inverse proportion of geom hits, so rays that hit more other faces are darker */ + div = (float)noradded / (float)samples * exp(R.wrld.aodistfac); + + VecMulf(shadfac, div); + + } + else if(aocolor!=WO_AOPLAIN && skyadded) { + div= (1.0f - fac/(float)noradded)/(float)samples; + shadfac[0]*= div; // average color times distances/hits formula shadfac[1]*= div; // average color times distances/hits formula shadfac[2]*= div; // average color times distances/hits formula Index: source/blender/render/intern/source/texture.c =================================================================== --- source/blender/render/intern/source/texture.c (revision 14978) +++ source/blender/render/intern/source/texture.c (working copy) @@ -1862,6 +1862,11 @@ shi->vn[0]+= dot*nor[0]; shi->vn[1]+= dot*nor[1]; shi->vn[2]+= dot*nor[2]; + + /* make worldspace copy */ + VECCOPY(nor, shi->vn); + Mat4Mul3Vecfl(R.viewinv, nor); + VECCOPY(shi->worldnor, nor); } Normalize(shi->vn); Index: source/blender/render/intern/source/shadeinput.c =================================================================== --- source/blender/render/intern/source/shadeinput.c (revision 14978) +++ source/blender/render/intern/source/shadeinput.c (working copy) @@ -764,6 +764,11 @@ else VECCOPY(shi->vn, shi->facenor); + /* normal in worldspace, used in Diffuse SH IBL, and nodes */ + VECCOPY(shi->worldnor, shi->vn); + Mat4Mul3Vecfl(R.viewinv, shi->worldnor); + VecMulf(shi->worldnor, -1.0f); + /* used in nodes */ VECCOPY(shi->vno, shi->vn); Index: source/blender/render/intern/source/shadeoutput.c =================================================================== --- source/blender/render/intern/source/shadeoutput.c (revision 14978) +++ source/blender/render/intern/source/shadeoutput.c (working copy) @@ -1004,6 +1004,29 @@ } } + +void image_based_lighting(ShadeInput *shi, ShadeResult *shr) +{ + float iblcol[3], worldnor[3]; + + VECCOPY(worldnor, shi->vn); + Mat4Mul3Vecfl(R.viewinv, worldnor); + VecMulf(worldnor, -1.0f); + + + if (R.wrld.ibl_method == WO_IBL_DIFFUSESH) { + IBL_diffusesh_getcolor(iblcol, (float *)R.ibl_sh_coeffs, worldnor); + } + else if (R.wrld.ibl_method == WO_IBL_IMPORTANCE) { + IBL_getcolor_importance(iblcol, &R, worldnor); + } + + VecMulf(iblcol, R.wrld.ibl_multiplier); + + add_to_diffuse(shr->shad, shi, 1.0f, iblcol[0], iblcol[1], iblcol[2]); +} + + /* pure AO, check for raytrace and world should have been done */ void ambient_occlusion(ShadeInput *shi) { @@ -1607,6 +1630,9 @@ } } + if(R.wrld.mode & WO_IMAGE_BASED_LIGHTING) + image_based_lighting(shi, shr); + /* lighting pass */ if(passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) { GroupObject *go; Index: source/blender/render/intern/source/ibl.c =================================================================== --- source/blender/render/intern/source/ibl.c (revision 0) +++ source/blender/render/intern/source/ibl.c (revision 0) @@ -0,0 +1,444 @@ +/** +* $Id: + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributors: Matt Ebb + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "IMB_imbuf_types.h" + +#include "DNA_image_types.h" +#include "DNA_texture_types.h" +#include "DNA_world_types.h" + +#include "BKE_image.h" +#include "BKE_global.h" + +/* local include */ +#include "render_types.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; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +float sinc(float x) { + if (fabs(x) < 1.0e-4) return 1.0 ; + else return(sin(x)/x) ; +} + + +/* Converts UV coordinates from an environment map to the equivalent 3D vector + * Incoming UV coordinates are considered to be in [-1,1] + * domega = the solid angle that pixel represents in the unit sphere + * returns 1 if the pixel actually represents anything in the env map + * eg. pixels within the unit circle of an angmap */ +static int uv_to_xyz(int mapping, float *uv, float *xyz, float dtheta_dphi, float *domega) +{ + float phi, theta, sinphi, sintheta; + float radius_sq=1.0f; + + float u = uv[0]; + float v = uv[1]; + + switch(mapping) + { + case WO_IBL_MAP_SPHERE: + phi = (v*0.5f+0.5f)*M_PI; // pi < phi < 0 + theta = -u*M_PI; // pi < theta < -pi + + /* transform u,v to cartesian components */ + sinphi = sin(phi); + xyz[0] = -sinphi * sin(theta); + xyz[1] = sinphi * cos(theta); + xyz[2] = -cos(phi); + + /* solid angle */ + if (domega) *domega = sinphi*dtheta_dphi; + break; + + case WO_IBL_MAP_ANGMAP: + default: + /* for angmap, only consider points inside the unit circle */ + radius_sq = u*u + v*v; + if(radius_sq>1.0f) return 0; + + theta = M_PI*sqrt(radius_sq); + phi = atan2(v,u); + + /* transform u,v to cartesian components */ + sintheta = sin(theta); + xyz[0] = sintheta*cos(phi); + xyz[1] = cos(theta); + xyz[2] = sintheta*sin(phi); + + /* solid angle */ + if (domega) *domega = sinc(theta)*dtheta_dphi; + break; + } + + return 1; +} + +typedef struct ImpHistogram +{ + float dir[3]; + float col[3]; + double sumintensity; + float domega; +} ImpHistogram; + +/* RGB -> YCbCr(use Y only) */ +static double rgb_to_intensity(float r, float g, float b) +{ + return (0.2989 * r + 0.5866 * g + 0.1145 * b); +} + +void free_ibl_importance(Render *re) +{ + if (re->wrld.importance_col) MEM_freeN(re->wrld.importance_col); + if (re->wrld.importance_vec) MEM_freeN(re->wrld.importance_vec); +} + +static void importance_get_sample(float *vec, float *col, double *importance_vec, float *importance_col, int num) +{ + vec[0] = (float)importance_vec[3*num+0]; + vec[1] = (float)importance_vec[3*num+1]; + vec[2] = (float)importance_vec[3*num+2]; + + col[0] = importance_col[3*num+0]; + col[1] = importance_col[3*num+1]; + col[2] = importance_col[3*num+2]; +} + +static void importance_print_samples(Render *re) +{ + int i; + + float vec[3], col[3]; + + for (i=0; i < re->wrld.ibl_importance_samples; i++) { + importance_get_sample(vec, col, re->wrld.importance_vec, re->wrld.importance_col, i); + + printf("col %d - [%f,%f,%f] , ", i, col[0], col[1], col[2]); + printf("vec %d - [%f,%f,%f] , ", i, vec[0], vec[1], vec[2]); + } +} + + +void init_ibl_importance(Render *re) +{ + ImBuf *ibuf; + Image *ima; + ImpHistogram *hist; + float *rect_float; + float col[4], rnd; + int w, h, i, j; + double sumintensity=0.0, maxintensity, intensity, highest_intensity=0.0; + int index; + float dtheta_dphi, domega=0.f; + + + double *vec_table; + float *col_table; + + float uv[2], xyz[3]; + + float falloff; + + int nsamples = re->wrld.ibl_importance_samples; + + ima = re->wrld.ibl_image; + if (!ima) return; + ibuf = BKE_image_get_ibuf(ima, NULL); + + w = ibuf->x; + h = ibuf->y; + rect_float = ibuf->rect_float; + if (!rect_float) return; + + dtheta_dphi= (M_PI/(float)h) * (M_PI_2/(float)w); + if (re->wrld.ibl_mapping == WO_IBL_MAP_SPHERE) dtheta_dphi /= 2.0f; + + hist = (ImpHistogram *)MEM_mallocN(sizeof(ImpHistogram)*w*h, "importance sampling histogram"); + re->wrld.importance_vec = MEM_mallocN(3*sizeof(double)*nsamples, "importance sampling vectors"); + re->wrld.importance_col = MEM_mallocN(3*sizeof(float)*nsamples, "importance sampling colours"); + + vec_table = re->wrld.importance_vec; + col_table = re->wrld.importance_col; + + re->i.infostr= "Calculating Importance Histogram"; + + /* build a histogram with summed pixel intensities */ + for(j=0;jwrld.ibl_mapping, uv, hist[index].dir, dtheta_dphi, &domega); + + falloff = cos(M_PI * ((float)j/(float)h)); + + hist[index].col[0] = rect_float[4 * index + 0]; + hist[index].col[1] = rect_float[4 * index + 1]; + hist[index].col[2] = rect_float[4 * index + 2]; + + hist[index].domega = domega; + + // printf("col - [%f,%f,%f] , ", j, hist[i].col[0], hist[i].col[1], hist[i].col[2]); + + intensity = rgb_to_intensity(hist[index].col[0], hist[index].col[1], hist[index].col[2]); + sumintensity += intensity; + hist[index].sumintensity = sumintensity; + + } + } + +/* for (j = 0; j < h; j++) { + for (i = 0; i < w; i++) { + + if (!inunitsphere(i, j, w, h)) continue; + + index = j * w + i; + + xy_to_vec(hist[index].dir, i, j, w, h); + + hist[index].col[0] = rect_float[4 * index + 0]; + hist[index].col[1] = rect_float[4 * index + 1]; + hist[index].col[2] = rect_float[4 * index + 2]; + hist[index].col[3] = 1.0; + + hist[index].xy[0] = i; + hist[index].xy[1] = j; + intensity = rgb_to_intensity(hist[index].col[0], hist[index].col[1], hist[index].col[2]); + + sumintensity += intensity; + hist[index].sumintensity = sumintensity; + } + } +*/ + + printf("IBL:importance: sumintensity = %f\n", sumintensity); + + maxintensity = sumintensity; + + R.i.infostr= "Generating Importance Sampling Points"; + printf("colours ["); + for (j = 0; j < nsamples; j++) { + // printf("col %d - [%f,%f,%f] , ", j, hist[i].col[0], hist[i].col[1], hist[i].col[2]); + // printf("dir %d - [%f,%f,%f] , ", j, hist[i].dir[0], hist[i].dir[1], hist[i].dir[2]); + + /* generate random number in [0, maxintensity) */ + rnd = BLI_frand() * maxintensity; + + /* + if (samp_type == SAMP_TYPE_IMPORTANCE) { + rnd = BLI_frand() * maxintensity; // no thread_frand, since we're calculating in a non-threaded prepass + } else if (samp_type == SAMP_TYPE_IMPORTANCESTRATIFIED) { + // stratified + // printf("stratified \n"); + rnd = (((double)j + BLI_frand()) / (double)nsamples) * maxintensity; + } + */ + + for (i = 0; i < w*h; i++) { + if (rnd < hist[i].sumintensity) { + break; + } + } + + vec_table[3*j + 0] = hist[i].dir[0]; + vec_table[3*j + 1] = hist[i].dir[1]; + vec_table[3*j + 2] = hist[i].dir[2]; + + col_table[3*j + 0] = hist[i].col[0]; + col_table[3*j + 1] = hist[i].col[1]; + col_table[3*j + 2] = hist[i].col[2]; + + printf("[%f,%f, %f] , ", col_table[3*j + 0], col_table[3*j + 1], col_table[3*j + 2]); + } + printf("]\n"); + MEM_freeN(hist); + + importance_print_samples(re); +} + + + +/* expects normal in world space */ +void IBL_getcolor_importance(float *col, Render *re, float *n) +{ + int s, nsamples = re->wrld.ibl_importance_samples; + float vec[3], dot, sampcol[3], accumcol[3]; + int samplesadded=0; + + for (s=0; swrld.importance_vec, re->wrld.importance_col, s); + + /* only use samples in same hemisphere */ + dot = Inpf(n, vec); + if (dot > 0.0f) { + + VecMulf(sampcol, dot); + VecAddf(accumcol, accumcol, sampcol); + + } + samplesadded++; + } + + VecMulf(accumcol, 1.0f/(float)samplesadded); + VECCOPY(col, accumcol); +} + + + +/* *** Diffuse irradiance: Spherical Harmonics *** */ +/* +* Based on the paper and sample code of: +* "An Efficient Representation for Irradiance Environment Maps" +* by Ravi Ramamoorthi and Pat Hanrahan +* http://graphics.stanford.edu/papers/envmap/ +* +* Also thanks to some example code by Francesco Banterle +* http://www.banterle.com/francesco/ +* +* This calculates RGB values for lighting coefficients L_{lm} with +* 0 <= l <= 2 and -l <= m <= l. There are 9 coefficients in all. +*/ + + +void init_ibl_diffusesh(struct Render *re) +{ + ImBuf *ibuf; + Image *ima; + float uv[2], xyz[3], x, y, z; + float dtheta_dphi, c, domega=0.f; + int w, h, i, j, k; + float *rect_float, pix[3]; + int index, col; + + ima = re->wrld.ibl_image; + if (!ima) return; + ibuf = BKE_image_get_ibuf(ima, NULL); + + w = ibuf->x; + h = ibuf->y; + rect_float = ibuf->rect_float; + if (!rect_float) return; + + dtheta_dphi= (M_PI/(float)h) * (M_PI_2/(float)w); + if (re->wrld.ibl_mapping == WO_IBL_MAP_SPHERE) dtheta_dphi /= 2.0f; + + memset(re->ibl_sh_coeffs, 0, sizeof(re->ibl_sh_coeffs)); + + for(j=0;jwrld.ibl_mapping, uv, xyz, dtheta_dphi, &domega); + + x = xyz[0]; y = xyz[1]; z = xyz[2]; + index = j*w+i; + + pix[0] = rect_float[4 * index + 0]; + pix[1] = rect_float[4 * index + 1]; + pix[2] = rect_float[4 * index + 2]; + + /* add the light per pixel to the coefficients per term, + * based on a constant, the differential solid angle and + * cartesian components of surface normal x,y,z */ + for (col = 0 ; col < 3 ; col++) { + + /* L_{00}. Note that Y_{00} = 0.282095 */ + c=0.282095f*domega; + re->ibl_sh_coeffs[0][col] += pix[col]*c; + + /* L_{1m}. -1 <= m <= 1. The linear terms */ + c=0.488603f*domega; + re->ibl_sh_coeffs[1][col]+=pix[col]*c*y; + re->ibl_sh_coeffs[2][col]+=pix[col]*c*z; + re->ibl_sh_coeffs[3][col]+=pix[col]*c*x; + + /* The Quadratic terms, L_{2m} -2 <= m <= 2 */ + /* First, L_{2-2}, L_{2-1}, L_{21} corresponding to xy,yz,xz */ + c=1.092548f*domega; + re->ibl_sh_coeffs[4][col]+=pix[col]*c*x*y; + re->ibl_sh_coeffs[5][col]+=pix[col]*c*y*z; + re->ibl_sh_coeffs[7][col]+=pix[col]*c*x*z; + + /* L_{20}. Note that Y_{20} = 0.315392 (3z^2 - 1) */ + c=0.315392f*domega*(3.0f*z*z-1.0f); + re->ibl_sh_coeffs[6][col]+=pix[col]*c; + + c=0.546274f*domega*(x*x-y*y); + re->ibl_sh_coeffs[8][col]+=pix[col]*c; + } + } + } +}; + + +/* expects normal in world space */ +void IBL_diffusesh_getcolor( float *col, float *coeffs, float *n) +{ + float x, y, z; + static const float c1 = 0.429043, c2 = 0.511664, c3 = 0.743125, c4 = 0.886227, c5 = 0.247708; + int rgb; + float *L00, *L1_1, *L10, *L11, *L2_2, *L2_1, *L20, *L21, *L22; + + L00 = coeffs + 0*3; + L1_1 = coeffs + 1*3; + L10 = coeffs + 2*3; + L11 = coeffs + 3*3; + L2_2 = coeffs + 4*3; + L2_1 = coeffs + 5*3; + L20 = coeffs + 6*3; + L21 = coeffs + 7*3; + L22 = coeffs + 8*3; + + x = n[0] ; y = n[1] ; z = n[2]; + + for (rgb = 0; rgb < 3; rgb++) { + col[rgb] = c1*L22[rgb]*(x*x - y*y); + col[rgb] += c3*L20[rgb]*z*z; + col[rgb] += c4*L00[rgb]; + col[rgb] += -c5*L20[rgb]; + col[rgb] += 2.0f*c1*(L2_2[rgb]*x*y + L21[rgb]*x*z + L2_1[rgb]*y*z); + col[rgb] += 2.0f*c2*(L11[rgb]*x + L1_1[rgb]*y + L10[rgb]*z); + } +} \ No newline at end of file Index: source/blender/render/intern/source/convertblender.c =================================================================== --- source/blender/render/intern/source/convertblender.c (revision 14978) +++ source/blender/render/intern/source/convertblender.c (working copy) @@ -4429,6 +4429,11 @@ if(re->r.mode & R_RAYTRACE) free_render_qmcsampler(re); + if (re->wrld.mode & WO_IMAGE_BASED_LIGHTING) { + if (re->wrld.ibl_method == WO_IBL_IMPORTANCE) + free_ibl_importance(re); + } + if(re->r.mode & R_RAYTRACE) freeraytree(re); free_sss(re); @@ -4807,8 +4812,19 @@ if(re->wrld.mode & WO_AMB_OCC) if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT) init_ao_sphere(&re->wrld); + + if (re->wrld.aocolor == WO_AODIFFUSESH) + init_ibl_diffusesh(re); } + if(re->wrld.mode & WO_IMAGE_BASED_LIGHTING) { + if (re->wrld.ibl_method == WO_IBL_DIFFUSESH) { + init_ibl_diffusesh(re); + } else if (re->wrld.ibl_method == WO_IBL_IMPORTANCE) { + init_ibl_importance(re); + } + } + /* still bad... doing all */ init_render_textures(re); init_render_materials(re->r.mode, &re->wrld.ambr); Index: source/blender/render/intern/include/render_types.h =================================================================== --- source/blender/render/intern/include/render_types.h (revision 14978) +++ source/blender/render/intern/include/render_types.h (working copy) @@ -33,6 +33,7 @@ /* ------------------------------------------------------------------------- */ #include "DNA_color_types.h" +#include "DNA_image_types.h" #include "DNA_scene_types.h" #include "DNA_world_types.h" #include "DNA_object_types.h" @@ -199,6 +200,14 @@ struct Object *excludeob; + /* Image Based Lighting */ + /* spherical harmonics coefficients diffuse prefiltered */ + float ibl_sh_coeffs[9][3]; + /* importance sampling directions and colours */ + float *importance_col; + double *importance_vec; + + /* arena for allocating data for use during render, for * example dynamic TFaces to go in the VlakRen structure. */ Index: source/blender/render/intern/include/rendercore.h =================================================================== --- source/blender/render/intern/include/rendercore.h (revision 14978) +++ source/blender/render/intern/include/rendercore.h (working copy) @@ -104,5 +104,13 @@ extern void init_render_qmcsampler(Render *re); extern void free_render_qmcsampler(Render *re); +/* -------- ibl.c ------- */ + +void init_ibl_diffusesh(Render *re); +void init_ibl_importance(Render *re); +void free_ibl_importance(Render *re); + +void image_based_lighting(struct ShadeInput *shi, struct ShadeResult *shr); +void IBL_diffusesh_getcolor( float *col, float *coeffs, float *n); #endif /* RENDER_EXT_H */ Index: source/blender/render/extern/include/RE_shader_ext.h =================================================================== --- source/blender/render/extern/include/RE_shader_ext.h (revision 14978) +++ source/blender/render/extern/include/RE_shader_ext.h (working copy) @@ -136,6 +136,7 @@ float refcol[4], displace[3]; float strandco, tang[3], nmaptang[3], stress, winspeed[4]; float duplilo[3], dupliuv[3]; + float worldnor[3]; ShadeInputUV uv[8]; /* 8 = MAX_MTFACE */ ShadeInputCol col[8]; /* 8 = MAX_MCOL */ Index: source/blender/python/api2_2x/World.h =================================================================== --- source/blender/python/api2_2x/World.h (revision 14978) +++ source/blender/python/api2_2x/World.h (working copy) @@ -31,6 +31,7 @@ #define EXPP_WORLD_H #include +#include "DNA_image_types.h" #include "DNA_world_types.h" #define BPy_World_Check(v) ((v)->ob_type==&World_Type) Index: source/blender/blenkernel/intern/world.c =================================================================== --- source/blender/blenkernel/intern/world.c (revision 14978) +++ source/blender/blenkernel/intern/world.c (working copy) @@ -34,6 +34,7 @@ #include #include "MEM_guardedalloc.h" +#include "DNA_image_types.h" #include "DNA_world_types.h" #include "DNA_texture_types.h" #include "DNA_scriptlink_types.h" @@ -83,6 +84,7 @@ World *add_world(char *name) { World *wrld; + ImageUser *iuser; wrld= alloc_libblock(&G.main->world, ID_WO, name); @@ -104,6 +106,14 @@ wrld->physicsEngine= WOPHY_BULLET;//WOPHY_SUMO; Bullet by default wrld->preview = NULL; + + iuser = &(wrld->ibl_iuser); + + iuser->sfra= 1; + iuser->fie_ima= 2; + iuser->ok= 1; + + wrld->ibl_multiplier = 1.0; return wrld; } Index: source/blender/makesdna/DNA_world_types.h =================================================================== --- source/blender/makesdna/DNA_world_types.h (revision 14978) +++ source/blender/makesdna/DNA_world_types.h (working copy) @@ -36,12 +36,18 @@ struct Ipo; struct MTex; +struct Image; +struct ImageUser; #ifndef MAX_MTEX #define MAX_MTEX 10 #endif +typedef struct Ibl { + float dsh_coeffs[9][3]; +} Ibl; + /** * World defines general modeling data such as a background fill, * gravity, color model, stars, etc. It mixes game-data, rendering @@ -106,13 +112,21 @@ float *aosphere, *aotables; + short ibl_method, ibl_mapping; + short ibl_importance_samples, pad5[3]; + float ibl_multiplier; + struct Image *ibl_image; + struct ImageUser ibl_iuser; + float *importance_col; + double *importance_vec; + struct Ipo *ipo; struct MTex *mtex[10]; /* previews */ struct PreviewImage *preview; - + ScriptLink scriptlink; } World; @@ -133,6 +147,7 @@ #define WO_DOF 4 #define WO_ACTIVITY_CULLING 8 #define WO_AMB_OCC 16 +#define WO_IMAGE_BASED_LIGHTING 32 /* aomix */ #define WO_AOADD 0 @@ -153,7 +168,16 @@ #define WO_AOPLAIN 0 #define WO_AOSKYCOL 1 #define WO_AOSKYTEX 2 +#define WO_AODIFFUSESH 3 +/* ibl_method */ +#define WO_IBL_DIFFUSESH 0 +#define WO_IBL_IMPORTANCE 1 + +/* ibl_mapping */ +#define WO_IBL_MAP_ANGMAP 0 +#define WO_IBL_MAP_SPHERE 1 + /* ao_gather_method */ #define WO_AOGATHER_RAYTRACE 0 #define WO_AOGATHER_APPROX 1 Index: source/blender/src/buttons_shading.c =================================================================== --- source/blender/src/buttons_shading.c (revision 14978) +++ source/blender/src/buttons_shading.c (working copy) @@ -2163,13 +2163,98 @@ } +static void world_panel_ibl(World *wrld) +{ + uiBlock *block; + short yco=PANEL_YMAX; + char *strp; + struct ImageUser *iuser= &(wrld->ibl_iuser); + uiBut *but; + + block= uiNewBlock(&curarea->uiblocks, "world_panel_ibl", UI_EMBOSS, UI_HELV, curarea->win); + uiNewPanelTabbed("Amb Occ", "World"); + if(uiNewPanel(curarea, block, "Image Based Lighting", "World", PANELX, PANELY, PANELW, PANELH)==0) return; + + uiDefButBitS(block, TOG, WO_IMAGE_BASED_LIGHTING, B_REDR, "Image Based Lighting", + X2CLM1, yco-=BUTH, BUTW1, BUTH, &wrld->mode, 0, 0, 0, 0, "Enables lighting from an environment image (light probe)"); + + yco -= YSPACE; + +// uiDefButS(block, MENU, B_REDR, "Calculation Method %t|Diffuse Prefiltered %x0|Importance Sampled %x1", +// X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->ibl_method, 0, 0, 0, 0, ""); + uiDefButS(block, MENU, B_REDR, "Calculation Method %t|Diffuse Prefiltered %x0", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->ibl_method, 0, 0, 0, 0, ""); + + if (wrld->ibl_method == WO_IBL_IMPORTANCE) { + uiDefButS(block, NUM, B_REDR, "Samples:", + X2CLM2, yco, BUTW2, BUTH, &wrld->ibl_importance_samples, 0.0, 512.0, 1.0, 0, "Number of times to sample the environment map"); + } + + yco -= YSPACE; + + /* Browse */ + IMAnames_to_pupstring(&strp, NULL, NULL, &(G.main->image), NULL, &iuser->menunr); + + uiBlockBeginAlign(block); + but= uiDefButS(block, MENU, B_REDR, strp, + X2CLM1, yco-=BUTH, ICONBUTW, BUTH, &iuser->menunr, 0, 0, 0, 0, "Selects an existing Image or Movie"); + uiButSetFunc(but, image_browse_cb, &(wrld->ibl_image), iuser); + + MEM_freeN(strp); + + if (wrld->ibl_image != NULL) { + char str[128]; + + if (wrld->ibl_image->source != IMA_SRC_FILE) { + uiDefBut(block, LABEL, 0, "Still images only", + X2CLM1, yco-=BUTH, BUTW2, BUTH, 0, 0, 0, 0, 0, ""); /* for align in panel */ + return; + } + uiSetButLock(wrld->ibl_image->id.lib!=NULL, ERROR_LIBDATA_MESSAGE); + but= uiDefIconBut(block, BUT, B_REDR, ICON_FILESEL, + X2CLM1+ICONBUTW, yco, X2CLM1+ICONBUTW, BUTH, 0, 0, 0, 0, 0, "Open Fileselect to load new Image"); + uiButSetFunc(but, image_load_fs_cb, &(wrld->ibl_image), iuser); + + but= uiDefBut(block, TEX, B_IDNAME, "IM:", + X2CLM1+2*ICONBUTW, yco, PANEL_XMAX-4*ICONBUTW-BUTW4, BUTH, wrld->ibl_image->id.name+2, 0.0, 21.0, 0, 0, "Current Image Datablock name."); + uiButSetFunc(but, test_idbutton_cb, wrld->ibl_image->id.name, NULL); + + but= uiDefBut(block, BUT, B_REDR, "Reload", + PANEL_XMAX-2*ICONBUTW-BUTW4, yco, BUTW4, BUTH, NULL, 0, 0, 0, 0, "Reloads Image or Movie"); + uiButSetFunc(but, image_reload_cb, &(wrld->ibl_image), iuser); + + but= uiDefIconBut(block, BUT, B_REDR, ICON_X, + PANEL_XMAX-2*ICONBUTW, yco, ICONBUTW, BUTH, 0, 0, 0, 0, 0, "Unlink Image block"); + uiButSetFunc(but, image_unlink_cb, &(wrld->ibl_image), NULL); + + sprintf(str, "%d", wrld->ibl_image->id.us); + uiDefBut(block, BUT, B_NOP, str, + PANEL_XMAX-ICONBUTW, yco, ICONBUTW, BUTH, 0, 0, 0, 0, 0, "Only displays number of users of Image block"); + + } else { + but= uiDefBut(block, BUT, B_REDR, "Load", + X2CLM1+ICONBUTW, yco, BUTW2-ICONBUTW, BUTH, NULL, 0, 0, 0, 0, "Load new Image"); + uiButSetFunc(but, image_load_fs_cb, &(wrld->ibl_image), iuser); + } + + uiBlockEndAlign(block); + + yco-= YSPACE; + + uiDefButF(block, NUM, B_REDR, "Multiplier:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->ibl_multiplier, 0.0, 100.0, 1.0, 0, "Multiply the final result to brighten or darken the lighting"); + + uiDefButS(block, MENU, B_REDR, "Image Format %t|Angular Map %x0|Sphere (LatLong) %x1", + X2CLM2, yco, BUTW2, BUTH, &wrld->ibl_mapping, 0, 0, 0, 0, ""); +} + static void world_panel_amb_occ(World *wrld) { uiBlock *block; short yco=PANEL_YMAX; + char *str; block= uiNewBlock(&curarea->uiblocks, "world_panel_amb_oc", UI_EMBOSS, UI_HELV, curarea->win); - uiNewPanelTabbed("Mist / Stars / Physics", "World"); if(uiNewPanel(curarea, block, "Amb Occ", "World", PANELX, PANELY, PANELW, PANELH)==0) return; uiSetButLock(wrld->id.lib!=0, ERROR_LIBDATA_MESSAGE); @@ -2262,19 +2347,19 @@ /* color treatment */ uiBlockBeginAlign(block); - uiDefButS(block, ROW, B_REDR, "Plain", - X3CLM1, yco-=BUTH, BUTW3, BUTH, &wrld->aocolor, 2.0, (float)WO_AOPLAIN, 0, 0, "Plain diffuse energy (white)"); - uiDefButS(block, ROW, B_REDR, "Sky Color", - X3CLM2, yco, BUTW3, BUTH, &wrld->aocolor, 2.0, (float)WO_AOSKYCOL, 0, 0, "Use horizon and zenith color for diffuse energy"); - if(wrld->ao_gather_method == WO_AOGATHER_RAYTRACE) - uiDefButS(block, ROW, B_REDR, "Sky Texture", - X3CLM3, yco, BUTW3, BUTH, &wrld->aocolor, 2.0, (float)WO_AOSKYTEX, 0, 0, "Does full Sky texture render for diffuse energy"); - uiBlockEndAlign(block); + + if(wrld->ao_gather_method == WO_AOGATHER_RAYTRACE) { + uiDefButS(block, MENU, B_REDR, "Plain %x0|Sky Color %x1|Sky Texture %x2|IBL: Diffuse Prefiltered %x3", + X3CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aocolor, 0.0, (float)WO_AOPLAIN, 0, 0, ""); + } else { + uiDefButS(block, MENU, B_REDR, "Plain %x0|Sky Color %x1|IBL: Diffuse Prefiltered %x3", + X3CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aocolor, 0.0, (float)WO_AOPLAIN, 0, 0, ""); + } yco -= YSPACE; - uiDefButF(block, NUMSLI, B_REDR, "Energy:", - X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aoenergy, 0.01, 3.0, 100, 0, "Sets global energy scale for AO"); + uiDefButF(block, NUM, B_REDR, "Energy:", + X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aoenergy, 0.01, 10.0, 100, 0, "Sets global energy scale for AO"); } static void world_panel_world(World *wrld) @@ -4371,6 +4456,7 @@ if(wrld) { world_panel_mistaph(wrld); world_panel_amb_occ(wrld); + world_panel_ibl(wrld); world_panel_texture(wrld); world_panel_mapto(wrld); } Index: source/blender/blenloader/intern/readfile.c =================================================================== --- source/blender/blenloader/intern/readfile.c (revision 14978) +++ source/blender/blenloader/intern/readfile.c (working copy) @@ -2138,6 +2138,8 @@ } } + wrld->ibl_image= newlibadr_us(fd, wrld->id.lib, wrld->ibl_image); + lib_link_scriptlink(fd, &wrld->id, &wrld->scriptlink); wrld->id.flag -= LIB_NEEDLINK; @@ -2155,6 +2157,9 @@ for(a=0; amtex[a]= newdataadr(fd, wrld->mtex[a]); } + + wrld->ibl_iuser.ok= 1; + wrld->preview = direct_link_preview_image(fd, wrld->preview); } @@ -7530,6 +7535,8 @@ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 11)) { Object *ob; bActionStrip *strip; + World *wrld; + ImageUser *iuser; /* nla-strips - scale */ for (ob= main->object.first; ob; ob= ob->id.next) { @@ -7553,6 +7560,16 @@ ob->soft->shearstiff = 1.0f; } } + + for(wrld=main->world.first; wrld; wrld= wrld->id.next) { + iuser = &(wrld->ibl_iuser); + + iuser->sfra= 1; + iuser->fie_ima= 2; + iuser->ok= 1; + wrld->ibl_multiplier = 1.0; + } + } if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 14)) { Index: source/blender/nodes/intern/SHD_util.h =================================================================== --- source/blender/nodes/intern/SHD_util.h (revision 14978) +++ source/blender/nodes/intern/SHD_util.h (working copy) @@ -109,6 +109,7 @@ #define GEOM_OUT_NORMAL 5 #define GEOM_OUT_VCOL 6 #define GEOM_OUT_FRONTBACK 7 +#define GEOM_OUT_WORLDNORMAL 8 /* input socket defines */ Index: source/blender/nodes/intern/SHD_nodes/SHD_geom.c =================================================================== --- source/blender/nodes/intern/SHD_nodes/SHD_geom.c (revision 14978) +++ source/blender/nodes/intern/SHD_nodes/SHD_geom.c (working copy) @@ -39,9 +39,10 @@ { SOCK_VECTOR, 0, "View", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, { SOCK_VECTOR, 0, "Orco", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, { SOCK_VECTOR, 0, "UV", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, - { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, + { SOCK_VECTOR, 0, "View Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, { SOCK_RGBA, 0, "Vertex Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { SOCK_VALUE, 0, "Front/Back", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { SOCK_VECTOR, 0, "World Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, { -1, 0, "" } }; @@ -73,6 +74,7 @@ VECCOPY(out[GEOM_OUT_ORCO]->vec, shi->lo); VECCOPY(out[GEOM_OUT_UV]->vec, suv->uv); VECCOPY(out[GEOM_OUT_NORMAL]->vec, shi->vno); + VECCOPY(out[GEOM_OUT_WORLDNORMAL]->vec, shi->worldnor); if (shi->totcol) { /* find vertex color layer by name */