static void render_tile(unsigned char *img, int comps, float *fimg, int w, int h, int nsubsamples, int tilex, int tiley, int tilew, int tileh) { int endx = tilex + min_i(tilew, w - tilex); int endy = tiley + min_i(tileh, h - tiley); int x, y; int u, v; for (y = tiley; y < endy; y++) { for (x = tilex; x < endx; x++) { for (v = 0; v < nsubsamples; v++) { for (u = 0; u < nsubsamples; u++) { float px = (x + (u / (float)nsubsamples) - (w / 2.0)) / (w / 2.0); float py = -(y + (v / (float)nsubsamples) - (h / 2.0)) / (h / 2.0); Ray ray; ray.org.x = 0.0; ray.org.y = 0.0; ray.org.z = 0.0; ray.dir.x = px; ray.dir.y = py; ray.dir.z = -1.0; vnormalize(&(ray.dir)); Isect isect; isect.t = 1.0e+17; isect.hit = 0; ray_sphere_intersect(&isect, &ray, &spheres[0]); ray_sphere_intersect(&isect, &ray, &spheres[1]); ray_sphere_intersect(&isect, &ray, &spheres[2]); ray_plane_intersect (&isect, &ray, &plane); if (isect.hit) { vec col; ambient_occlusion(&col, &isect); fimg[3 * (y * w + x) + 0] += col.x; fimg[3 * (y * w + x) + 1] += col.y; fimg[3 * (y * w + x) + 2] += col.z; } } } fimg[3 * (y * w + x) + 0] /= (float)(nsubsamples * nsubsamples); fimg[3 * (y * w + x) + 1] /= (float)(nsubsamples * nsubsamples); fimg[3 * (y * w + x) + 2] /= (float)(nsubsamples * nsubsamples); img[comps * (y * w + x) + 0] = clamp(fimg[3 *(y * w + x) + 0]); img[comps * (y * w + x) + 1] = clamp(fimg[3 *(y * w + x) + 1]); img[comps * (y * w + x) + 2] = clamp(fimg[3 *(y * w + x) + 2]); } } }
/* Compute the image for the scanlines from [y0,y1), for an overall image of width w and height h. */ static void ao_scanlines(int y0, int y1, int w, int h, int nsubsamples, float image[]) { static Plane plane = { vec(0.0f, -0.5f, 0.0f), vec(0.f, 1.f, 0.f) }; static Sphere spheres[3] = { { vec(-2.0f, 0.0f, -3.5f), 0.5f }, { vec(-0.5f, 0.0f, -3.0f), 0.5f }, { vec(1.0f, 0.0f, -2.2f), 0.5f } }; srand48(y0); for (int y = y0; y < y1; ++y) { for (int x = 0; x < w; ++x) { int offset = 3 * (y * w + x); for (int u = 0; u < nsubsamples; ++u) { for (int v = 0; v < nsubsamples; ++v) { float px = (x + (u / (float)nsubsamples) - (w / 2.0f)) / (w / 2.0f); float py = -(y + (v / (float)nsubsamples) - (h / 2.0f)) / (h / 2.0f); // Scale NDC based on width/height ratio, supporting non-square image output px *= (float)w / (float)h; float ret = 0.f; Ray ray; Isect isect; ray.org = vec(0.f, 0.f, 0.f); ray.dir.x = px; ray.dir.y = py; ray.dir.z = -1.0f; vnormalize(ray.dir); isect.t = 1.0e+17f; isect.hit = 0; for (int snum = 0; snum < 3; ++snum) ray_sphere_intersect(isect, ray, spheres[snum]); ray_plane_intersect(isect, ray, plane); if (isect.hit) ret = ambient_occlusion(isect, plane, spheres); // Update image for AO for this ray image[offset+0] += ret; image[offset+1] += ret; image[offset+2] += ret; } } // Normalize image pixels by number of samples taken per pixel image[offset+0] /= nsubsamples * nsubsamples; image[offset+1] /= nsubsamples * nsubsamples; image[offset+2] /= nsubsamples * nsubsamples; } } }
// modified to only render one row (specified by parameter y) per function call void aobench_render(unsigned char *img, int w, int h, int nsubsamples, int y) { int x, u, v; for (x = 0; x < w; x++) { aobfloat r = 0.0, g = 0.0, b = 0.0; for (v = 0; v < nsubsamples; v++) { for (u = 0; u < nsubsamples; u++) { aobfloat px = (x + (u / (aobfloat)nsubsamples) - (w / 2.0)) / (w / 2.0); aobfloat py = -(y + (v / (aobfloat)nsubsamples) - (h / 2.0)) / (h / 2.0); Ray ray; ray.org.x = 0.0; ray.org.y = 0.0; ray.org.z = 0.0; ray.dir.x = px; ray.dir.y = py; ray.dir.z = -1.0; vnormalize(&(ray.dir)); Isect isect; isect.t = 1.0e+17; isect.hit = 0; ray_sphere_intersect(&isect, &ray, &spheres[0]); ray_sphere_intersect(&isect, &ray, &spheres[1]); ray_sphere_intersect(&isect, &ray, &spheres[2]); ray_plane_intersect (&isect, &ray, &plane); if (isect.hit) { vec col; ambient_occlusion(&col, &isect); r += col.x; g += col.y; b += col.z; } } } r /= (aobfloat)(nsubsamples * nsubsamples); g /= (aobfloat)(nsubsamples * nsubsamples); b /= (aobfloat)(nsubsamples * nsubsamples); img[3 * (y * w + x) + 0] = clamp(r); img[3 * (y * w + x) + 1] = clamp(g); img[3 * (y * w + x) + 2] = clamp(b); } }
static void render(unsigned char *img, int comps, int w, int h, int nsubsamples) { int x, y; int u, v; //float *fimg = (float *)malloc(sizeof(float) * w * h * 3); vec *fimg = (vec *)malloc(sizeof(vec) * w * h); memset((void *)fimg, 0, sizeof(vec) * w * h); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { for (v = 0; v < nsubsamples; v++) { for (u = 0; u < nsubsamples; u++) { float px = (x + (u / (float)nsubsamples) - (w / 2.0)) / (w / 2.0); float py = -(y + (v / (float)nsubsamples) - (h / 2.0)) / (h / 2.0); Ray ray; ray.org.x = 0.0; ray.org.y = 0.0; ray.org.z = 0.0; ray.dir.x = px; ray.dir.y = py; ray.dir.z = -1.0; vnormalize(&(ray.dir)); Isect isect; isect.t = 1.0e+17; isect.hit = 0; ray_sphere_intersect(&isect, &ray, &spheres[0]); ray_sphere_intersect(&isect, &ray, &spheres[1]); ray_sphere_intersect(&isect, &ray, &spheres[2]); ray_plane_intersect (&isect, &ray, &plane); if (isect.hit) { vec col; ambient_occlusion(&col, &isect); vadd(&fimg[y * w + x], fimg[y * w + x], col); /* fimg[y * w + x].x += col.x; fimg[y * w + x].y += col.y; fimg[y * w + x].z += col.z; */ } } } vdivs(&fimg[y * w + x], fimg[y * w + x], (float)(nsubsamples * nsubsamples)); /* fimg[y * w + x].x /= (float)(nsubsamples * nsubsamples); fimg[y * w + x].y /= (float)(nsubsamples * nsubsamples); fimg[y * w + x].z /= (float)(nsubsamples * nsubsamples); */ img[comps * (y * w + x) + 0] = clamp(fimg[y * w + x].x); img[comps * (y * w + x) + 1] = clamp(fimg[y * w + x].y); img[comps * (y * w + x) + 2] = clamp(fimg[y * w + x].z); } } }
static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(quad), int x, int y, float UNUSED(u), float UNUSED(v), float *tvn, float *ttang) { BakeShade *bs = handle; ShadeSample *ssamp = &bs->ssamp; ShadeResult shr; VlakRen *vlr = shi->vlr; shade_input_init_material(shi); if (bs->type == RE_BAKE_AO) { ambient_occlusion(shi); if (R.r.bake_flag & R_BAKE_NORMALIZE) { copy_v3_v3(shr.combined, shi->ao); } else { zero_v3(shr.combined); environment_lighting_apply(shi, &shr); } } else { if (bs->type == RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */ shi->r = shi->g = shi->b = 1.0f; shade_input_set_shade_texco(shi); /* only do AO for a full bake (and obviously AO bakes) * AO for light bakes is a leftover and might not be needed */ if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) shade_samples_do_AO(ssamp); 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) { float nor[3]; copy_v3_v3(nor, shi->vn); if (R.r.bake_normal_space == R_BAKE_SPACE_CAMERA) { /* pass */ } else if (R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) { float mat[3][3], imat[3][3]; /* bitangent */ if (tvn && ttang) { copy_v3_v3(mat[0], ttang); cross_v3_v3v3(mat[1], tvn, ttang); mul_v3_fl(mat[1], ttang[3]); copy_v3_v3(mat[2], tvn); } else { copy_v3_v3(mat[0], shi->nmaptang); cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang); mul_v3_fl(mat[1], shi->nmaptang[3]); copy_v3_v3(mat[2], shi->nmapnorm); } invert_m3_m3(imat, mat); mul_m3_v3(imat, nor); } else if (R.r.bake_normal_space == R_BAKE_SPACE_OBJECT) mul_mat3_m4_v3(ob->imat_ren, nor); /* ob->imat_ren includes viewinv! */ else if (R.r.bake_normal_space == R_BAKE_SPACE_WORLD) mul_mat3_m4_v3(R.viewinv, nor); normalize_v3(nor); /* in case object has scaling */ /* The invert of the red channel is to make * the normal map compliant with the outside world. * It needs to be done because in Blender * the normal used in the renderer points inward. It is generated * this way in calc_vertexnormals(). Should this ever change * this negate must be removed. */ shr.combined[0] = (-nor[0]) / 2.0f + 0.5f; shr.combined[1] = nor[1] / 2.0f + 0.5f; shr.combined[2] = nor[2] / 2.0f + 0.5f; } else if (bs->type == RE_BAKE_TEXTURE) { copy_v3_v3(shr.combined, &shi->r); shr.alpha = shi->alpha; } else if (bs->type == RE_BAKE_SHADOW) { copy_v3_v3(shr.combined, shr.shad); shr.alpha = shi->alpha; } else if (bs->type == RE_BAKE_SPEC_COLOR) { copy_v3_v3(shr.combined, &shi->specr); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_SPEC_INTENSITY) { copy_v3_fl(shr.combined, shi->spec); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_MIRROR_COLOR) { copy_v3_v3(shr.combined, &shi->mirr); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_MIRROR_INTENSITY) { copy_v3_fl(shr.combined, shi->ray_mirror); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_ALPHA) { copy_v3_fl(shr.combined, shi->alpha); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_EMIT) { copy_v3_fl(shr.combined, shi->emit); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_VERTEX_COLORS) { copy_v3_v3(shr.combined, shi->vcol); shr.alpha = shi->vcol[3]; } } if (bs->rect_float && !bs->vcol) { float *col = bs->rect_float + 4 * (bs->rectx * y + x); copy_v3_v3(col, shr.combined); if (bs->type == RE_BAKE_ALL || bs->type == RE_BAKE_TEXTURE || bs->type == RE_BAKE_VERTEX_COLORS) { col[3] = shr.alpha; } else { col[3] = 1.0; } } else { /* Target is char (LDR). */ unsigned char col[4]; if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { float rgb[3]; copy_v3_v3(rgb, shr.combined); if (R.scene_color_manage) { /* Vertex colors have no way to specify color space, so they * default to sRGB. */ if (!bs->vcol) IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, bs->rect_colorspace); else linearrgb_to_srgb_v3_v3(rgb, rgb); } rgb_float_to_uchar(col, rgb); } else { rgb_float_to_uchar(col, shr.combined); } if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) { col[3] = FTOCHAR(shr.alpha); } else { col[3] = 255; } if (bs->vcol) { /* Vertex color baking. Vcol has no useful alpha channel (it exists * but is used only for vertex painting). */ bs->vcol->r = col[0]; bs->vcol->g = col[1]; bs->vcol->b = col[2]; } else { unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x); copy_v4_v4_char((char *)imcol, (char *)col); } } if (bs->rect_mask) { bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED; } if (bs->do_update) { *bs->do_update = true; } }