svn merge ^/trunk/blender -r55700:55776

This commit is contained in:
2013-04-04 13:37:07 +00:00
228 changed files with 4292 additions and 2194 deletions

View File

@@ -1292,18 +1292,14 @@ elseif(WIN32)
if(WITH_OPENCOLLADA) if(WITH_OPENCOLLADA)
set(OPENCOLLADA ${LIBDIR}/opencollada) set(OPENCOLLADA ${LIBDIR}/opencollada)
set(OPENCOLLADA_INCLUDE_DIRS set(OPENCOLLADA_INCLUDE_DIRS
${OPENCOLLADA}/include/COLLADAStreamWriter ${OPENCOLLADA}/include/opencollada/COLLADAStreamWriter
${OPENCOLLADA}/include/COLLADABaseUtils ${OPENCOLLADA}/include/opencollada/COLLADABaseUtils
${OPENCOLLADA}/include/COLLADAFramework ${OPENCOLLADA}/include/opencollada/COLLADAFramework
${OPENCOLLADA}/include/COLLADASaxFrameworkLoader ${OPENCOLLADA}/include/opencollada/COLLADASaxFrameworkLoader
${OPENCOLLADA}/include/GeneratedSaxParser ${OPENCOLLADA}/include/opencollada/GeneratedSaxParser
) )
set(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib/opencollada) set(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib/opencollada)
if(WITH_MINGW64) set(OPENCOLLADA_LIBRARIES OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver buffer ftoa xml)
set(OPENCOLLADA_LIBRARIES OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver pcre buffer ftoa xml)
else()
set(OPENCOLLADA_LIBRARIES OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver expat pcre buffer ftoa)
endif()
set(PCRE_LIBRARIES pcre) set(PCRE_LIBRARIES pcre)
endif() endif()
@@ -1416,8 +1412,8 @@ elseif(WIN32)
LLVMX86Disassembler LLVMX86Info LLVMX86Disassembler LLVMX86Info
LLVMX86Utils LLVMipa LLVMX86Utils LLVMipa
LLVMipo LLVMCore) LLVMipo LLVMCore)
#imagehelp is needed by LLVM 3.1 on MinGW, check lib\Support\Windows\Signals.inc #imagehelp is needed by LLVM 3.1 on MinGW, check lib\Support\Windows\Signals.inc
set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS} -limagehlp") set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS} -limagehlp")
set(LLVM_STATIC YES) set(LLVM_STATIC YES)
endif() endif()

View File

@@ -88,7 +88,7 @@ int AUD_FFMPEGReader::decode(AVPacket& packet, AUD_Buffer& buffer)
} }
} }
else else
memcpy(((data_t*)buffer.getBuffer()) + buf_pos, frame->data[1], data_size); memcpy(((data_t*)buffer.getBuffer()) + buf_pos, frame->data[0], data_size);
buf_pos += data_size; buf_pos += data_size;
} }

View File

@@ -205,6 +205,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=1, default=1,
) )
cls.subsurface_samples = IntProperty(
name="Subsurface Samples",
description="Number of subsurface scattering samples to render for each AA sample",
min=1, max=10000,
default=1,
)
cls.no_caustics = BoolProperty( cls.no_caustics = BoolProperty(
name="No Caustics", name="No Caustics",
description="Leave out caustics, resulting in a darker image with less noise", description="Leave out caustics, resulting in a darker image with less noise",

View File

@@ -83,6 +83,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
sub.prop(cscene, "transmission_samples", text="Transmission") sub.prop(cscene, "transmission_samples", text="Transmission")
sub.prop(cscene, "ao_samples", text="AO") sub.prop(cscene, "ao_samples", text="AO")
sub.prop(cscene, "mesh_light_samples", text="Mesh Light") sub.prop(cscene, "mesh_light_samples", text="Mesh Light")
sub.prop(cscene, "subsurface_samples", text="Subsurface")
class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel): class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel):

View File

@@ -252,7 +252,6 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
else if (b_node.is_a(&RNA_ShaderNodeNormal)) { else if (b_node.is_a(&RNA_ShaderNodeNormal)) {
BL::Node::outputs_iterator out_it; BL::Node::outputs_iterator out_it;
b_node.outputs.begin(out_it); b_node.outputs.begin(out_it);
BL::NodeSocket vec_sock(*out_it);
NormalNode *norm = new NormalNode(); NormalNode *norm = new NormalNode();
norm->direction = get_node_output_vector(b_node, "Normal"); norm->direction = get_node_output_vector(b_node, "Normal");
@@ -302,6 +301,9 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) { else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
node = new DiffuseBsdfNode(); node = new DiffuseBsdfNode();
} }
else if (b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) {
node = new SubsurfaceScatteringNode();
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) { else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
BL::ShaderNodeBsdfGlossy b_glossy_node(b_node); BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
GlossyBsdfNode *glossy = new GlossyBsdfNode(); GlossyBsdfNode *glossy = new GlossyBsdfNode();

View File

@@ -19,7 +19,6 @@
#include "background.h" #include "background.h"
#include "camera.h" #include "camera.h"
#include "film.h" #include "film.h"
#include "../render/filter.h"
#include "graph.h" #include "graph.h"
#include "integrator.h" #include "integrator.h"
#include "light.h" #include "light.h"
@@ -197,6 +196,7 @@ void BlenderSync::sync_integrator()
integrator->transmission_samples = get_int(cscene, "transmission_samples"); integrator->transmission_samples = get_int(cscene, "transmission_samples");
integrator->ao_samples = get_int(cscene, "ao_samples"); integrator->ao_samples = get_int(cscene, "ao_samples");
integrator->mesh_light_samples = get_int(cscene, "mesh_light_samples"); integrator->mesh_light_samples = get_int(cscene, "mesh_light_samples");
integrator->subsurface_samples = get_int(cscene, "subsurface_samples");
integrator->progressive = get_boolean(cscene, "progressive"); integrator->progressive = get_boolean(cscene, "progressive");
if(integrator->modified(previntegrator)) if(integrator->modified(previntegrator))
@@ -213,18 +213,11 @@ void BlenderSync::sync_film()
Film prevfilm = *film; Film prevfilm = *film;
film->exposure = get_float(cscene, "film_exposure"); film->exposure = get_float(cscene, "film_exposure");
film->filter_type = (FilterType)RNA_enum_get(&cscene, "filter_type");
film->filter_width = (film->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width");
if(film->modified(prevfilm)) if(film->modified(prevfilm))
film->tag_update(scene); film->tag_update(scene);
Filter *filter = scene->filter;
Filter prevfilter = *filter;
filter->filter_type = (FilterType)RNA_enum_get(&cscene, "filter_type");
filter->filter_width = (filter->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width");
if(filter->modified(prevfilter))
filter->tag_update(scene);
} }
/* Render Layer */ /* Render Layer */

View File

@@ -216,6 +216,14 @@ public:
return mem; return mem;
} }
void copy_at(T *ptr, size_t offset, size_t size)
{
if(size > 0) {
size_t mem_size = size*data_elements*datatype_size(data_type);
memcpy(&data[0] + offset, ptr, mem_size);
}
}
void reference(T *ptr, size_t width, size_t height = 0) void reference(T *ptr, size_t width, size_t height = 0)
{ {
data.clear(); data.clear();

View File

@@ -42,6 +42,7 @@ set(SRC_HEADERS
kernel_projection.h kernel_projection.h
kernel_random.h kernel_random.h
kernel_shader.h kernel_shader.h
kernel_subsurface.h
kernel_textures.h kernel_textures.h
kernel_triangle.h kernel_triangle.h
kernel_types.h kernel_types.h
@@ -62,6 +63,7 @@ set(SRC_CLOSURE_HEADERS
closure/bsdf_util.h closure/bsdf_util.h
closure/bsdf_ward.h closure/bsdf_ward.h
closure/bsdf_westin.h closure/bsdf_westin.h
closure/bssrdf.h
closure/emissive.h closure/emissive.h
closure/volume.h closure/volume.h
) )

View File

@@ -29,6 +29,7 @@
#include "../closure/bsdf_ward.h" #include "../closure/bsdf_ward.h"
#endif #endif
#include "../closure/bsdf_westin.h" #include "../closure/bsdf_westin.h"
#include "../closure/bssrdf.h"
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN

View File

@@ -0,0 +1,154 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KERNEL_BSSRDF_H__
#define __KERNEL_BSSRDF_H__
CCL_NAMESPACE_BEGIN
__device int bssrdf_setup(ShaderClosure *sc)
{
if(sc->data0 < BSSRDF_MIN_RADIUS) {
/* revert to diffuse BSDF if radius too small */
sc->data0 = 0.0f;
sc->data1 = 0.0f;
return bsdf_diffuse_setup(sc);
}
else {
/* radius + IOR params */
sc->data0 = max(sc->data0, 0.0f);
sc->data1 = max(sc->data1, 1.0f);
sc->type = CLOSURE_BSSRDF_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF;
}
}
/* Simple Cubic BSSRDF falloff */
__device float bssrdf_cubic(float ld, float r)
{
if(ld == 0.0f)
return (r == 0.0f)? 1.0f: 0.0f;
return powf(ld - min(r, ld), 3.0f) * 4.0f/powf(ld, 4.0f);
}
/* Original BSSRDF fallof function */
typedef struct BSSRDFParams {
float eta; /* index of refraction */
float sigma_t_; /* reduced extinction coefficient */
float sigma_tr; /* effective extinction coefficient */
float Fdr; /* diffuse fresnel reflectance */
float D; /* diffusion constant */
float A;
float alpha_; /* reduced albedo */
float zr; /* distance of virtual lightsource above surface */
float zv; /* distance of virtual lightsource below surface */
float ld; /* mean free path */
float ro; /* diffuse reflectance */
} BSSRDFParams;
__device float bssrdf_reduced_albedo_Rd(float alpha_, float A, float ro)
{
float sq;
sq = sqrt(3.0f*(1.0f - alpha_));
return (alpha_/2.0f)*(1.0f + expf((-4.0f/3.0f)*A*sq))*expf(-sq) - ro;
}
__device float bssrdf_compute_reduced_albedo(float A, float ro)
{
const float tolerance = 1e-8;
const int max_iteration_count = 20;
float d, fsub, xn_1 = 0.0f, xn = 1.0f, fxn, fxn_1;
int i;
/* use secant method to compute reduced albedo using Rd function inverse
* with a given reflectance */
fxn = bssrdf_reduced_albedo_Rd(xn, A, ro);
fxn_1 = bssrdf_reduced_albedo_Rd(xn_1, A, ro);
for (i= 0; i < max_iteration_count; i++) {
fsub = (fxn - fxn_1);
if (fabsf(fsub) < tolerance)
break;
d = ((xn - xn_1)/fsub)*fxn;
if (fabsf(d) < tolerance)
break;
xn_1 = xn;
fxn_1 = fxn;
xn = xn - d;
if (xn > 1.0f) xn = 1.0f;
if (xn_1 > 1.0f) xn_1 = 1.0f;
fxn = bssrdf_reduced_albedo_Rd(xn, A, ro);
}
/* avoid division by zero later */
if (xn <= 0.0f)
xn = 0.00001f;
return xn;
}
__device void bssrdf_setup_params(BSSRDFParams *ss, float refl, float radius, float ior)
{
ss->eta = ior;
ss->Fdr = -1.440f/ior*ior + 0.710f/ior + 0.668f + 0.0636f*ior;
ss->A = (1.0f + ss->Fdr)/(1.0f - ss->Fdr);
ss->ld = radius;
ss->ro = min(refl, 0.999f);
ss->alpha_ = bssrdf_compute_reduced_albedo(ss->A, ss->ro);
ss->sigma_tr = 1.0f/ss->ld;
ss->sigma_t_ = ss->sigma_tr/sqrtf(3.0f*(1.0f - ss->alpha_));
ss->D = 1.0f/(3.0f*ss->sigma_t_);
ss->zr = 1.0f/ss->sigma_t_;
ss->zv = ss->zr + 4.0f*ss->A*ss->D;
}
/* exponential falloff function */
__device float bssrdf_original(const BSSRDFParams *ss, float r)
{
if(ss->ld == 0.0f)
return (r == 0.0f)? 1.0f: 0.0f;
float rr = r*r;
float sr, sv, Rdr, Rdv;
sr = sqrt(rr + ss->zr*ss->zr);
sv = sqrt(rr + ss->zv*ss->zv);
Rdr = ss->zr*(1.0f + ss->sigma_tr*sr)*expf(-ss->sigma_tr*sr)/(sr*sr*sr);
Rdv = ss->zv*(1.0f + ss->sigma_tr*sv)*expf(-ss->sigma_tr*sv)/(sv*sv*sv);
return ss->alpha_*(1.0f/(4.0f*(float)M_PI))*(Rdr + Rdv);
}
CCL_NAMESPACE_END
#endif /* __KERNEL_BSSRDF_H__ */

View File

@@ -923,6 +923,330 @@ __device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const ui
#endif #endif
} }
/* Special ray intersection routines for subsurface scattering. In that case we
* only want to intersect with primitives in the same object, and if case of
* multiple hits we pick a single random primitive as the intersection point. */
__device_inline void bvh_triangle_intersect_subsurface(KernelGlobals *kg, Intersection *isect,
float3 P, float3 idir, int object, int triAddr, float tmax, int *num_hits, float subsurface_random)
{
/* compute and check intersection t-value */
float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
float3 dir = 1.0f/idir;
float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z);
float t = Oz * invDz;
if(t > 0.0f && t < tmax) {
/* compute and check barycentric u */
float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z;
float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z;
float u = Ox + t*Dx;
if(u >= 0.0f) {
/* compute and check barycentric v */
float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z;
float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z;
float v = Oy + t*Dy;
if(v >= 0.0f && u + v <= 1.0f) {
(*num_hits)++;
if(subsurface_random * (*num_hits) <= 1.0f) {
/* record intersection */
isect->prim = triAddr;
isect->object = object;
isect->u = u;
isect->v = v;
isect->t = t;
}
}
}
}
}
__device_inline int bvh_intersect_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, float subsurface_random)
{
/* traversal stack in CUDA thread-local memory */
int traversalStack[BVH_STACK_SIZE];
traversalStack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
int stackPtr = 0;
int nodeAddr = kernel_data.bvh.root;
/* ray parameters in registers */
const float tmax = ray->t;
float3 P = ray->P;
float3 idir = bvh_inverse_direction(ray->D);
int object = ~0;
int num_hits = 0;
isect->t = tmax;
isect->object = ~0;
isect->prim = ~0;
isect->u = 0.0f;
isect->v = 0.0f;
/* traversal loop */
do {
do
{
/* traverse internal nodes */
while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
{
bool traverseChild0, traverseChild1, closestChild1;
int nodeAddrChild1;
bvh_node_intersect(kg, &traverseChild0, &traverseChild1,
&closestChild1, &nodeAddr, &nodeAddrChild1,
P, idir, isect->t, ~0, nodeAddr);
if(traverseChild0 != traverseChild1) {
/* one child was intersected */
if(traverseChild1) {
nodeAddr = nodeAddrChild1;
}
}
else {
if(!traverseChild0) {
/* neither child was intersected */
nodeAddr = traversalStack[stackPtr];
--stackPtr;
}
else {
/* both children were intersected, push the farther one */
if(closestChild1) {
int tmp = nodeAddr;
nodeAddr = nodeAddrChild1;
nodeAddrChild1 = tmp;
}
++stackPtr;
traversalStack[stackPtr] = nodeAddrChild1;
}
}
}
/* if node is leaf, fetch triangle list */
if(nodeAddr < 0) {
float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1));
int primAddr = __float_as_int(leaf.x);
#ifdef __INSTANCING__
if(primAddr >= 0) {
#endif
int primAddr2 = __float_as_int(leaf.y);
/* pop */
nodeAddr = traversalStack[stackPtr];
--stackPtr;
/* primitive intersection */
while(primAddr < primAddr2) {
/* only primitives from the same object */
uint tri_object = (object == ~0)? kernel_tex_fetch(__prim_object, primAddr): object;
if(tri_object == subsurface_object) {
/* intersect ray against primitive */
#ifdef __HAIR__
uint segment = kernel_tex_fetch(__prim_segment, primAddr);
if(segment == ~0) /* ignore hair for sss */
#endif
bvh_triangle_intersect_subsurface(kg, isect, P, idir, object, primAddr, tmax, &num_hits, subsurface_random);
}
primAddr++;
}
#ifdef __INSTANCING__
}
else {
/* instance push */
if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) {
object = subsurface_object;
bvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax);
++stackPtr;
traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
nodeAddr = kernel_tex_fetch(__object_node, object);
}
else {
/* pop */
nodeAddr = traversalStack[stackPtr];
--stackPtr;
}
}
#endif
}
} while(nodeAddr != ENTRYPOINT_SENTINEL);
#ifdef __INSTANCING__
if(stackPtr >= 0) {
kernel_assert(object != ~0);
/* instance pop */
bvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax);
object = ~0;
nodeAddr = traversalStack[stackPtr];
--stackPtr;
}
#endif
} while(nodeAddr != ENTRYPOINT_SENTINEL);
return num_hits;
}
#ifdef __OBJECT_MOTION__
__device bool bvh_intersect_motion_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, float subsurface_random)
{
/* traversal stack in CUDA thread-local memory */
int traversalStack[BVH_STACK_SIZE];
traversalStack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
int stackPtr = 0;
int nodeAddr = kernel_data.bvh.root;
/* ray parameters in registers */
const float tmax = ray->t;
float3 P = ray->P;
float3 idir = bvh_inverse_direction(ray->D);
int object = ~0;
int num_hits = 0;
Transform ob_tfm;
isect->t = tmax;
isect->object = ~0;
isect->prim = ~0;
isect->u = 0.0f;
isect->v = 0.0f;
/* traversal loop */
do {
do
{
/* traverse internal nodes */
while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
{
bool traverseChild0, traverseChild1, closestChild1;
int nodeAddrChild1;
bvh_node_intersect(kg, &traverseChild0, &traverseChild1,
&closestChild1, &nodeAddr, &nodeAddrChild1,
P, idir, isect->t, ~0, nodeAddr);
if(traverseChild0 != traverseChild1) {
/* one child was intersected */
if(traverseChild1) {
nodeAddr = nodeAddrChild1;
}
}
else {
if(!traverseChild0) {
/* neither child was intersected */
nodeAddr = traversalStack[stackPtr];
--stackPtr;
}
else {
/* both children were intersected, push the farther one */
if(closestChild1) {
int tmp = nodeAddr;
nodeAddr = nodeAddrChild1;
nodeAddrChild1 = tmp;
}
++stackPtr;
traversalStack[stackPtr] = nodeAddrChild1;
}
}
}
/* if node is leaf, fetch triangle list */
if(nodeAddr < 0) {
float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1));
int primAddr = __float_as_int(leaf.x);
if(primAddr >= 0) {
int primAddr2 = __float_as_int(leaf.y);
/* pop */
nodeAddr = traversalStack[stackPtr];
--stackPtr;
/* primitive intersection */
while(primAddr < primAddr2) {
/* only primitives from the same object */
uint tri_object = (object == ~0)? kernel_tex_fetch(__prim_object, primAddr): object;
if(tri_object == subsurface_object) {
/* intersect ray against primitive */
#ifdef __HAIR__
uint segment = kernel_tex_fetch(__prim_segment, primAddr);
if(segment == ~0) /* ignore hair for sss */
#endif
bvh_triangle_intersect_subsurface(kg, isect, P, idir, object, primAddr, tmax, &num_hits, subsurface_random);
}
primAddr++;
}
}
else {
/* instance push */
if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) {
object = subsurface_object;
object = kernel_tex_fetch(__prim_object, -primAddr-1);
bvh_instance_motion_push(kg, object, ray, &P, &idir, &isect->t, &ob_tfm, tmax);
++stackPtr;
traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
nodeAddr = kernel_tex_fetch(__object_node, object);
}
else {
/* pop */
nodeAddr = traversalStack[stackPtr];
--stackPtr;
}
}
}
} while(nodeAddr != ENTRYPOINT_SENTINEL);
if(stackPtr >= 0) {
kernel_assert(object != ~0);
/* instance pop */
bvh_instance_motion_pop(kg, object, ray, &P, &idir, &isect->t, &ob_tfm, tmax);
object = ~0;
nodeAddr = traversalStack[stackPtr];
--stackPtr;
}
} while(nodeAddr != ENTRYPOINT_SENTINEL);
return num_hits;
}
#endif
__device_inline int scene_intersect_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, float subsurface_random)
{
#ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion)
return bvh_intersect_motion_subsurface(kg, ray, isect, subsurface_object, subsurface_random);
else
return bvh_intersect_subsurface(kg, ray, isect, subsurface_object, subsurface_random);
#else
return bvh_intersect_subsurface(kg, ray, isect, subsurface_object, subsurface_random);
#endif
}
/* Ray offset to avoid self intersection */
__device_inline float3 ray_offset(float3 P, float3 Ng) __device_inline float3 ray_offset(float3 P, float3 Ng)
{ {
#ifdef __INTERSECTION_REFINE__ #ifdef __INTERSECTION_REFINE__
@@ -971,6 +1295,10 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
#endif #endif
} }
/* Refine triangle intersection to more precise hit point. For rays that travel
* far the precision is often not so good, this reintersects the primitive from
* a closer distance. */
__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray) __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray)
{ {
float3 P = ray->P; float3 P = ray->P;

View File

@@ -53,7 +53,7 @@ __device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float
/* compute point on plane of focus */ /* compute point on plane of focus */
float ft = kernel_data.cam.focaldistance/ray->D.z; float ft = kernel_data.cam.focaldistance/ray->D.z;
float3 Pfocus = ray->P + ray->D*ft; float3 Pfocus = ray->D*ft;
/* update ray for effect of lens */ /* update ray for effect of lens */
ray->P = make_float3(lensuv.x, lensuv.y, 0.0f); ray->P = make_float3(lensuv.x, lensuv.y, 0.0f);
@@ -112,11 +112,13 @@ __device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, floa
/* compute point on plane of focus */ /* compute point on plane of focus */
float ft = kernel_data.cam.focaldistance/ray->D.z; float ft = kernel_data.cam.focaldistance/ray->D.z;
float3 Pfocus = ray->P + ray->D*ft; float3 Pfocus = ray->D*ft;
/* update ray for effect of lens */ /* update ray for effect of lens */
ray->P = make_float3(lensuv.x, lensuv.y, 0.0f); ray->P = make_float3(lensuv.x, lensuv.y, 0.0f);
ray->D = normalize(Pfocus - ray->P); ray->D = normalize(Pfocus - ray->P);
ray->P += Pcamera;
} }
/* transform ray from camera to world */ /* transform ray from camera to world */
@@ -224,8 +226,9 @@ __device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, flo
float lens_u, float lens_v, float time, Ray *ray) float lens_u, float lens_v, float time, Ray *ray)
{ {
/* pixel filter */ /* pixel filter */
float raster_x = x + kernel_tex_interp(__filter_table, filter_u, FILTER_TABLE_SIZE); int filter_table_offset = kernel_data.film.filter_table_offset;
float raster_y = y + kernel_tex_interp(__filter_table, filter_v, FILTER_TABLE_SIZE); float raster_x = x + lookup_table_read(kg, filter_u, filter_table_offset, FILTER_TABLE_SIZE);
float raster_y = y + lookup_table_read(kg, filter_v, filter_table_offset, FILTER_TABLE_SIZE);
#ifdef __CAMERA_MOTION__ #ifdef __CAMERA_MOTION__
/* motion blur */ /* motion blur */

View File

@@ -57,19 +57,6 @@ template<typename T> struct texture {
} }
#endif #endif
float interp(float x, int size)
{
kernel_assert(size == width);
x = clamp(x, 0.0f, 1.0f)*width;
int index = min((int)x, width-1);
int nindex = min(index+1, width-1);
float t = x - index;
return (1.0f - t)*data[index] + t*data[nindex];
}
T *data; T *data;
int width; int width;
}; };
@@ -157,7 +144,7 @@ typedef texture_image<uchar4> texture_image_uchar4;
#define kernel_tex_fetch(tex, index) (kg->tex.fetch(index)) #define kernel_tex_fetch(tex, index) (kg->tex.fetch(index))
#define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index)) #define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index))
#define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index)) #define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index))
#define kernel_tex_interp(tex, t, size) (kg->tex.interp(t, size)) #define kernel_tex_lookup(tex, t, offset, size) (kg->tex.lookup(t, offset, size))
#define kernel_tex_image_interp(tex, x, y) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp(x, y) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp(x, y)) #define kernel_tex_image_interp(tex, x, y) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp(x, y) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp(x, y))
#define kernel_data (kg->__data) #define kernel_data (kg->__data)

View File

@@ -58,7 +58,6 @@ typedef texture<uchar4, 2, cudaReadModeNormalizedFloat> texture_image_uchar4;
/* Macros to handle different memory storage on different devices */ /* Macros to handle different memory storage on different devices */
#define kernel_tex_fetch(t, index) tex1Dfetch(t, index) #define kernel_tex_fetch(t, index) tex1Dfetch(t, index)
#define kernel_tex_interp(t, x, size) tex1D(t, x)
#define kernel_tex_image_interp(t, x, y) tex2D(t, x, y) #define kernel_tex_image_interp(t, x, y) tex2D(t, x, y)
#define kernel_data __data #define kernel_data __data

View File

@@ -45,18 +45,6 @@
/* no assert in opencl */ /* no assert in opencl */
#define kernel_assert(cond) #define kernel_assert(cond)
/* manual implementation of interpolated 1D lookup */
__device float kernel_tex_interp_(__global float *data, int width, float x)
{
x = clamp(x, 0.0f, 1.0f)*width;
int index = min((int)x, width-1);
int nindex = min(index+1, width-1);
float t = x - index;
return (1.0f - t)*data[index] + t*data[nindex];
}
/* make_type definitions with opencl style element initializers */ /* make_type definitions with opencl style element initializers */
#ifdef make_float2 #ifdef make_float2
#undef make_float2 #undef make_float2
@@ -114,7 +102,7 @@ __device float kernel_tex_interp_(__global float *data, int width, float x)
/* data lookup defines */ /* data lookup defines */
#define kernel_data (*kg->data) #define kernel_data (*kg->data)
#define kernel_tex_interp(t, x, size) kernel_tex_interp_(kg->t, size, x) #define kernel_tex_lookup(t, x, offset, size) kernel_tex_lookup_(kg->t, offset, size, x)
#define kernel_tex_fetch(t, index) kg->t[index] #define kernel_tex_fetch(t, index) kg->t[index]
/* define NULL */ /* define NULL */

View File

@@ -66,8 +66,6 @@ __device void kernel_shader_evaluate(KernelGlobals *kg, uint4 *input, float4 *ou
out = shader_eval_background(kg, &sd, flag, SHADER_CONTEXT_MAIN); out = shader_eval_background(kg, &sd, flag, SHADER_CONTEXT_MAIN);
} }
shader_release(kg, &sd);
/* write output */ /* write output */
output[i] = make_float4(out.x, out.y, out.z, 0.0f); output[i] = make_float4(out.x, out.y, out.z, 0.0f);
} }

View File

@@ -69,8 +69,6 @@ __device_noinline float3 direct_emissive_eval(KernelGlobals *kg, float rando,
eval *= ls->eval_fac; eval *= ls->eval_fac;
shader_release(kg, &sd);
return eval; return eval;
} }
@@ -207,7 +205,6 @@ __device_noinline float3 indirect_background(KernelGlobals *kg, Ray *ray, int pa
ShaderData sd; ShaderData sd;
shader_setup_from_background(kg, &sd, ray); shader_setup_from_background(kg, &sd, ray);
float3 L = shader_eval_background(kg, &sd, path_flag, SHADER_CONTEXT_EMISSION); float3 L = shader_eval_background(kg, &sd, path_flag, SHADER_CONTEXT_EMISSION);
shader_release(kg, &sd);
#ifdef __BACKGROUND_MIS__ #ifdef __BACKGROUND_MIS__
/* check if background light exists or if we should skip pdf */ /* check if background light exists or if we should skip pdf */

View File

@@ -88,5 +88,39 @@ typedef struct KernelGlobals {
#endif #endif
/* Interpolated lookup table access */
__device float lookup_table_read(KernelGlobals *kg, float x, int offset, int size)
{
x = clamp(x, 0.0f, 1.0f)*(size-1);
int index = min((int)x, size-1);
int nindex = min(index+1, size-1);
float t = x - index;
float data0 = kernel_tex_fetch(__lookup_table, index + offset);
if(t == 0.0f)
return data0;
float data1 = kernel_tex_fetch(__lookup_table, nindex + offset);
return (1.0f - t)*data0 + t*data1;
}
__device float lookup_table_read_2D(KernelGlobals *kg, float x, float y, int offset, int xsize, int ysize)
{
y = clamp(y, 0.0f, 1.0f)*(ysize-1);
int index = min((int)y, ysize-1);
int nindex = min(index+1, ysize-1);
float t = y - index;
float data0 = lookup_table_read(kg, x, offset + xsize*index, xsize);
if(t == 0.0f)
return data0;
float data1 = lookup_table_read(kg, x, offset + xsize*nindex, xsize);
return (1.0f - t)*data0 + t*data1;
}
CCL_NAMESPACE_END CCL_NAMESPACE_END

View File

@@ -37,6 +37,10 @@
#include "kernel_random.h" #include "kernel_random.h"
#include "kernel_passes.h" #include "kernel_passes.h"
#ifdef __SUBSURFACE__
#include "kernel_subsurface.h"
#endif
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
typedef struct PathState { typedef struct PathState {
@@ -149,7 +153,7 @@ __device_inline float path_state_terminate_probability(KernelGlobals *kg, PathSt
} }
/* probalistic termination */ /* probalistic termination */
return average(throughput); return average(throughput); /* todo: try using max here */
} }
__device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, float3 *shadow) __device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, float3 *shadow)
@@ -212,8 +216,6 @@ __device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ra
if(ray->t != FLT_MAX) if(ray->t != FLT_MAX)
ray->D = normalize_len(Pend - ray->P, &ray->t); ray->D = normalize_len(Pend - ray->P, &ray->t);
shader_release(kg, &sd);
bounce++; bounce++;
} }
} }
@@ -323,10 +325,8 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
L_transparent += average(holdout_weight*throughput); L_transparent += average(holdout_weight*throughput);
} }
if(sd.flag & SD_HOLDOUT_MASK) { if(sd.flag & SD_HOLDOUT_MASK)
shader_release(kg, &sd);
break; break;
}
} }
#endif #endif
@@ -345,13 +345,29 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
float probability = path_state_terminate_probability(kg, &state, throughput); float probability = path_state_terminate_probability(kg, &state, throughput);
float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE); float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
if(terminate >= probability) { if(terminate >= probability)
shader_release(kg, &sd);
break; break;
}
throughput /= probability; throughput /= probability;
#ifdef __SUBSURFACE__
/* bssrdf scatter to a different location on the same object, replacing
* the closures with a diffuse BSDF */
if(sd.flag & SD_BSSRDF) {
float bssrdf_probability;
ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability);
/* modify throughput for picking bssrdf or bsdf */
throughput *= bssrdf_probability;
/* do bssrdf scatter step if we picked a bssrdf closure */
if(sc) {
uint lcg_state = lcg_init(rbsdf);
subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false);
}
}
#endif
#ifdef __AO__ #ifdef __AO__
/* ambient occlusion */ /* ambient occlusion */
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
@@ -415,10 +431,8 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
#endif #endif
/* no BSDF? we can stop here */ /* no BSDF? we can stop here */
if(!(sd.flag & SD_BSDF)) { if(!(sd.flag & SD_BSDF))
shader_release(kg, &sd);
break; break;
}
/* sample BSDF */ /* sample BSDF */
float bsdf_pdf; float bsdf_pdf;
@@ -432,8 +446,6 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval, label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf); &bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
shader_release(kg, &sd);
if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
break; break;
@@ -481,7 +493,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
#ifdef __NON_PROGRESSIVE__ #ifdef __NON_PROGRESSIVE__
__device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer, __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer,
float3 throughput, float throughput_normalize, float3 throughput, float num_samples_adjust,
float min_ray_pdf, float ray_pdf, PathState state, int rng_offset, PathRadiance *L) float min_ray_pdf, float ray_pdf, PathState state, int rng_offset, PathRadiance *L)
{ {
#ifdef __LAMP_MIS__ #ifdef __LAMP_MIS__
@@ -554,16 +566,32 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
/* path termination. this is a strange place to put the termination, it's /* path termination. this is a strange place to put the termination, it's
* mainly due to the mixed in MIS that we use. gives too many unneeded * mainly due to the mixed in MIS that we use. gives too many unneeded
* shader evaluations, only need emission if we are going to terminate */ * shader evaluations, only need emission if we are going to terminate */
float probability = path_state_terminate_probability(kg, &state, throughput*throughput_normalize); float probability = path_state_terminate_probability(kg, &state, throughput*num_samples_adjust);
float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE); float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
if(terminate >= probability) { if(terminate >= probability)
shader_release(kg, &sd);
break; break;
}
throughput /= probability; throughput /= probability;
#ifdef __SUBSURFACE__
/* bssrdf scatter to a different location on the same object, replacing
* the closures with a diffuse BSDF */
if(sd.flag & SD_BSSRDF) {
float bssrdf_probability;
ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability);
/* modify throughput for picking bssrdf or bsdf */
throughput *= bssrdf_probability;
/* do bssrdf scatter step if we picked a bssrdf closure */
if(sc) {
uint lcg_state = lcg_init(rbsdf);
subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false);
}
}
#endif
#ifdef __AO__ #ifdef __AO__
/* ambient occlusion */ /* ambient occlusion */
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
@@ -628,10 +656,8 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
#endif #endif
/* no BSDF? we can stop here */ /* no BSDF? we can stop here */
if(!(sd.flag & SD_BSDF)) { if(!(sd.flag & SD_BSDF))
shader_release(kg, &sd);
break; break;
}
/* sample BSDF */ /* sample BSDF */
float bsdf_pdf; float bsdf_pdf;
@@ -645,8 +671,6 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval, label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf); &bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
shader_release(kg, &sd);
if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval)) if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
break; break;
@@ -676,6 +700,193 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
} }
} }
__device_noinline void kernel_path_non_progressive_lighting(KernelGlobals *kg, RNG *rng, int sample,
ShaderData *sd, float3 throughput, float num_samples_adjust,
float min_ray_pdf, float ray_pdf, PathState state,
int rng_offset, PathRadiance *L, __global float *buffer)
{
#ifdef __AO__
/* ambient occlusion */
if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) {
int num_samples = ceil(kernel_data.integrator.ao_samples*num_samples_adjust);
float num_samples_inv = num_samples_adjust/num_samples;
float ao_factor = kernel_data.background.ao_factor;
float3 ao_N;
float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N);
for(int j = 0; j < num_samples; j++) {
/* todo: solve correlation */
float bsdf_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_U);
float bsdf_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_V);
float3 ao_D;
float ao_pdf;
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
Ray light_ray;
float3 ao_shadow;
light_ray.P = ray_offset(sd->P, sd->Ng);
light_ray.D = ao_D;
light_ray.t = kernel_data.background.ao_distance;
#ifdef __OBJECT_MOTION__
light_ray.time = sd->time;
#endif
if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow))
path_radiance_accum_ao(L, throughput*num_samples_inv, ao_bsdf, ao_shadow, state.bounce);
}
}
}
#endif
#ifdef __EMISSION__
/* sample illumination from lights to find path contribution */
if(sd->flag & SD_BSDF_HAS_EVAL) {
Ray light_ray;
BsdfEval L_light;
bool is_lamp;
#ifdef __OBJECT_MOTION__
light_ray.time = sd->time;
#endif
/* lamp sampling */
for(int i = 0; i < kernel_data.integrator.num_all_lights; i++) {
int num_samples = ceil(num_samples_adjust*light_select_num_samples(kg, i));
float num_samples_inv = num_samples_adjust/(num_samples*kernel_data.integrator.num_all_lights);
if(kernel_data.integrator.pdf_triangles != 0.0f)
num_samples_inv *= 0.5f;
for(int j = 0; j < num_samples; j++) {
float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
if(direct_emission(kg, sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state.bounce, is_lamp);
}
}
}
}
/* mesh light sampling */
if(kernel_data.integrator.pdf_triangles != 0.0f) {
int num_samples = ceil(num_samples_adjust*kernel_data.integrator.mesh_light_samples);
float num_samples_inv = num_samples_adjust/num_samples;
if(kernel_data.integrator.num_all_lights)
num_samples_inv *= 0.5f;
for(int j = 0; j < num_samples; j++) {
float light_t = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT);
float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
/* only sample triangle lights */
if(kernel_data.integrator.num_all_lights)
light_t = 0.5f*light_t;
if(direct_emission(kg, sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state.bounce, is_lamp);
}
}
}
}
}
#endif
for(int i = 0; i< sd->num_closure; i++) {
const ShaderClosure *sc = &sd->closure[i];
if(!CLOSURE_IS_BSDF(sc->type))
continue;
/* transparency is not handled here, but in outer loop */
if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID)
continue;
int num_samples;
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
num_samples = kernel_data.integrator.diffuse_samples;
else if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
num_samples = kernel_data.integrator.glossy_samples;
else
num_samples = kernel_data.integrator.transmission_samples;
num_samples = ceil(num_samples_adjust*num_samples);
float num_samples_inv = num_samples_adjust/num_samples;
for(int j = 0; j < num_samples; j++) {
/* sample BSDF */
float bsdf_pdf;
BsdfEval bsdf_eval;
float3 bsdf_omega_in;
differential3 bsdf_domega_in;
float bsdf_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_U);
float bsdf_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_V);
int label;
label = shader_bsdf_sample_closure(kg, sd, sc, bsdf_u, bsdf_v, &bsdf_eval,
&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
continue;
/* modify throughput */
float3 tp = throughput;
path_radiance_bsdf_bounce(L, &tp, &bsdf_eval, bsdf_pdf, state.bounce, label);
/* set labels */
float min_ray_pdf = FLT_MAX;
if(!(label & LABEL_TRANSPARENT))
min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
/* modify path state */
PathState ps = state;
path_state_next(kg, &ps, label);
/* setup ray */
Ray bsdf_ray;
bsdf_ray.P = ray_offset(sd->P, (label & LABEL_TRANSMIT)? -sd->Ng: sd->Ng);
bsdf_ray.D = bsdf_omega_in;
bsdf_ray.t = FLT_MAX;
#ifdef __RAY_DIFFERENTIALS__
bsdf_ray.dP = sd->dP;
bsdf_ray.dD = bsdf_domega_in;
#endif
#ifdef __OBJECT_MOTION__
bsdf_ray.time = sd->time;
#endif
kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer,
tp*num_samples_inv, num_samples,
min_ray_pdf, bsdf_pdf, ps, rng_offset+PRNG_BOUNCE_NUM, L);
/* for render passes, sum and reset indirect light pass variables
* for the next samples */
path_radiance_sum_indirect(L);
path_radiance_reset_indirect(L);
}
}
}
__device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer) __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer)
{ {
/* initialize */ /* initialize */
@@ -740,10 +951,8 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
L_transparent += average(holdout_weight*throughput); L_transparent += average(holdout_weight*throughput);
} }
if(sd.flag & SD_HOLDOUT_MASK) { if(sd.flag & SD_HOLDOUT_MASK)
shader_release(kg, &sd);
break; break;
}
} }
#endif #endif
@@ -763,195 +972,47 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
float probability = path_state_terminate_probability(kg, &state, throughput); float probability = path_state_terminate_probability(kg, &state, throughput);
float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE); float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
if(terminate >= probability) { if(terminate >= probability)
shader_release(kg, &sd);
break; break;
}
throughput /= probability; throughput /= probability;
} }
#ifdef __AO__ #ifdef __SUBSURFACE__
/* ambient occlusion */ /* bssrdf scatter to a different location on the same object */
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { if(sd.flag & SD_BSSRDF) {
int num_samples = kernel_data.integrator.ao_samples; for(int i = 0; i< sd.num_closure; i++) {
float num_samples_inv = 1.0f/num_samples; ShaderClosure *sc = &sd.closure[i];
float ao_factor = kernel_data.background.ao_factor;
float3 ao_N;
float3 ao_bsdf = shader_bsdf_ao(kg, &sd, ao_factor, &ao_N);
for(int j = 0; j < num_samples; j++) { if(!CLOSURE_IS_BSSRDF(sc->type))
/* todo: solve correlation */
float bsdf_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_U);
float bsdf_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_V);
float3 ao_D;
float ao_pdf;
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
Ray light_ray;
float3 ao_shadow;
light_ray.P = ray_offset(sd.P, sd.Ng);
light_ray.D = ao_D;
light_ray.t = kernel_data.background.ao_distance;
#ifdef __OBJECT_MOTION__
light_ray.time = sd.time;
#endif
if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow))
path_radiance_accum_ao(&L, throughput*num_samples_inv, ao_bsdf, ao_shadow, state.bounce);
}
}
}
#endif
#ifdef __EMISSION__
/* sample illumination from lights to find path contribution */
if(sd.flag & SD_BSDF_HAS_EVAL) {
Ray light_ray;
BsdfEval L_light;
bool is_lamp;
#ifdef __OBJECT_MOTION__
light_ray.time = sd.time;
#endif
/* lamp sampling */
for(int i = 0; i < kernel_data.integrator.num_all_lights; i++) {
int num_samples = light_select_num_samples(kg, i);
float num_samples_inv = 1.0f/(num_samples*kernel_data.integrator.num_all_lights);
if(kernel_data.integrator.pdf_triangles != 0.0f)
num_samples_inv *= 0.5f;
for(int j = 0; j < num_samples; j++) {
float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
if(direct_emission(kg, &sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(&L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state.bounce, is_lamp);
}
}
}
}
/* mesh light sampling */
if(kernel_data.integrator.pdf_triangles != 0.0f) {
int num_samples = kernel_data.integrator.mesh_light_samples;
float num_samples_inv = 1.0f/num_samples;
if(kernel_data.integrator.num_all_lights)
num_samples_inv *= 0.5f;
for(int j = 0; j < num_samples; j++) {
float light_t = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT);
float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
/* only sample triangle lights */
if(kernel_data.integrator.num_all_lights)
light_t = 0.5f*light_t;
if(direct_emission(kg, &sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(&L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state.bounce, is_lamp);
}
}
}
}
}
#endif
for(int i = 0; i< sd.num_closure; i++) {
const ShaderClosure *sc = &sd.closure[i];
if(!CLOSURE_IS_BSDF(sc->type))
continue;
/* transparency is not handled here, but in outer loop */
if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID)
continue;
int num_samples;
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
num_samples = kernel_data.integrator.diffuse_samples;
else if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
num_samples = kernel_data.integrator.glossy_samples;
else
num_samples = kernel_data.integrator.transmission_samples;
float num_samples_inv = 1.0f/num_samples;
for(int j = 0; j < num_samples; j++) {
/* sample BSDF */
float bsdf_pdf;
BsdfEval bsdf_eval;
float3 bsdf_omega_in;
differential3 bsdf_domega_in;
float bsdf_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_U);
float bsdf_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_V);
int label;
label = shader_bsdf_sample_closure(kg, &sd, sc, bsdf_u, bsdf_v, &bsdf_eval,
&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
continue; continue;
/* modify throughput */ /* set up random number generator */
float3 tp = throughput; uint lcg_state = lcg_init(rbsdf);
path_radiance_bsdf_bounce(&L, &tp, &bsdf_eval, bsdf_pdf, state.bounce, label); int num_samples = kernel_data.integrator.subsurface_samples;
float num_samples_inv = 1.0f/num_samples;
/* set labels */ /* do subsurface scatter step with copy of shader data, this will
float min_ray_pdf = FLT_MAX; * replace the BSSRDF with a diffuse BSDF closure */
for(int j = 0; j < num_samples; j++) {
ShaderData bssrdf_sd = sd;
subsurface_scatter_step(kg, &bssrdf_sd, state.flag, sc, &lcg_state, true);
if(!(label & LABEL_TRANSPARENT)) /* compute lighting with the BSDF closure */
min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf); kernel_path_non_progressive_lighting(kg, rng, sample*num_samples + j,
&bssrdf_sd, throughput, num_samples_inv,
/* modify path state */ ray_pdf, ray_pdf, state, rng_offset, &L, buffer);
PathState ps = state; }
path_state_next(kg, &ps, label);
/* setup ray */
Ray bsdf_ray;
bsdf_ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
bsdf_ray.D = bsdf_omega_in;
bsdf_ray.t = FLT_MAX;
#ifdef __RAY_DIFFERENTIALS__
bsdf_ray.dP = sd.dP;
bsdf_ray.dD = bsdf_domega_in;
#endif
#ifdef __OBJECT_MOTION__
bsdf_ray.time = sd.time;
#endif
kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer,
tp*num_samples_inv, num_samples,
min_ray_pdf, bsdf_pdf, ps, rng_offset+PRNG_BOUNCE_NUM, &L);
/* for render passes, sum and reset indirect light pass variables
* for the next samples */
path_radiance_sum_indirect(&L);
path_radiance_reset_indirect(&L);
} }
} }
#endif
/* lighting */
kernel_path_non_progressive_lighting(kg, rng, sample, &sd, throughput,
1.0f, ray_pdf, ray_pdf, state, rng_offset, &L, buffer);
/* continue in case of transparency */ /* continue in case of transparency */
throughput *= shader_bsdf_transparency(kg, &sd); throughput *= shader_bsdf_transparency(kg, &sd);
shader_release(kg, &sd);
if(is_zero(throughput)) if(is_zero(throughput))
break; break;

View File

@@ -200,5 +200,19 @@ __device void path_rng_end(KernelGlobals *kg, __global uint *rng_state, RNG rng)
#endif #endif
__device float lcg_step(uint *rng)
{
/* implicit mod 2^32 */
*rng = (1103515245*(*rng) + 12345);
return (float)*rng * (1.0f/(float)0xFFFFFFFF);
}
__device uint lcg_init(float seed)
{
uint rng = __float_as_int(seed);
lcg_step(&rng);
return rng;
}
CCL_NAMESPACE_END CCL_NAMESPACE_END

View File

@@ -158,6 +158,103 @@ __device_noinline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
#endif #endif
} }
/* ShaderData setup from BSSRDF scatter */
#ifdef __SUBSURFACE__
__device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderData *sd,
const Intersection *isect, const Ray *ray)
{
bool backfacing = sd->flag & SD_BACKFACING;
/* object, matrices, time, ray_length stay the same */
sd->flag = kernel_tex_fetch(__object_flag, sd->object);
sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
#ifdef __HAIR__
if(kernel_tex_fetch(__prim_segment, isect->prim) != ~0) {
/* Strand Shader setting*/
float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
sd->shader = __float_as_int(curvedata.z);
sd->segment = isect->segment;
float tcorr = isect->t;
if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_POSTINTERSECTCORRECTION)
tcorr = (isect->u < 0)? tcorr + sqrtf(isect->v) : tcorr - sqrtf(isect->v);
sd->P = bvh_curve_refine(kg, sd, isect, ray, tcorr);
}
else {
#endif
/* fetch triangle data */
float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim);
float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
sd->shader = __float_as_int(Ns.w);
#ifdef __HAIR__
sd->segment = ~0;
#endif
#ifdef __UV__
sd->u = isect->u;
sd->v = isect->v;
#endif
/* vectors */
sd->P = bvh_triangle_refine(kg, sd, isect, ray);
sd->Ng = Ng;
sd->N = Ng;
/* smooth normal */
if(sd->shader & SHADER_SMOOTH_NORMAL)
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
#ifdef __DPDU__
/* dPdu/dPdv */
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
#endif
#ifdef __HAIR__
}
#endif
sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
#ifdef __INSTANCING__
if(isect->object != ~0) {
/* instance transform */
object_normal_transform(kg, sd, &sd->N);
object_normal_transform(kg, sd, &sd->Ng);
#ifdef __DPDU__
object_dir_transform(kg, sd, &sd->dPdu);
object_dir_transform(kg, sd, &sd->dPdv);
#endif
}
#endif
/* backfacing test */
if(backfacing) {
sd->flag |= SD_BACKFACING;
sd->Ng = -sd->Ng;
sd->N = -sd->N;
#ifdef __DPDU__
sd->dPdu = -sd->dPdu;
sd->dPdv = -sd->dPdv;
#endif
}
/* should not get used in principle as the shading will only use a diffuse
* BSDF, but the shader might still access it */
sd->I = sd->N;
#ifdef __RAY_DIFFERENTIALS__
/* differentials */
differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
/* don't modify dP and dI */
#endif
}
#endif
/* ShaderData setup from position sampled on mesh */ /* ShaderData setup from position sampled on mesh */
__device_noinline void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, __device_noinline void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
@@ -283,11 +380,9 @@ __device_noinline void shader_setup_from_sample(KernelGlobals *kg, ShaderData *s
/* ShaderData setup for displacement */ /* ShaderData setup for displacement */
__device_noinline void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd, __device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
int object, int prim, float u, float v) int object, int prim, float u, float v)
{ {
/* Note: no OSLShader::init call here, this is done in shader_setup_from_sample! */
float3 P, Ng, I = make_float3(0.0f, 0.0f, 0.0f); float3 P, Ng, I = make_float3(0.0f, 0.0f, 0.0f);
int shader; int shader;
@@ -418,7 +513,7 @@ __device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
const ShaderClosure *sc = &sd->closure[sampled]; const ShaderClosure *sc = &sd->closure[sampled];
if(CLOSURE_IS_BSDF(sc->type)) { if(CLOSURE_IS_BSDF(sc->type)) {
sum += sd->closure[sampled].sample_weight; sum += sc->sample_weight;
if(r <= sum) if(r <= sum)
break; break;
@@ -811,7 +906,7 @@ __device void shader_merge_closures(KernelGlobals *kg, ShaderData *sd)
ShaderClosure *scj = &sd->closure[j]; ShaderClosure *scj = &sd->closure[j];
#ifdef __OSL__ #ifdef __OSL__
if(!sci->prim && sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) { if(!sci->prim && !scj->prim && sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
#else #else
if(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) { if(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
#endif #endif
@@ -823,18 +918,12 @@ __device void shader_merge_closures(KernelGlobals *kg, ShaderData *sd)
memmove(scj, scj+1, size*sizeof(ShaderClosure)); memmove(scj, scj+1, size*sizeof(ShaderClosure));
sd->num_closure--; sd->num_closure--;
j--;
} }
} }
} }
} }
#endif #endif
/* Free ShaderData */
__device void shader_release(KernelGlobals *kg, ShaderData *sd)
{
/* nothing to do currently */
}
CCL_NAMESPACE_END CCL_NAMESPACE_END

View File

@@ -0,0 +1,241 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
CCL_NAMESPACE_BEGIN
#define BSSRDF_MULTI_EVAL
#define BSSRDF_SKIP_NO_HIT
__device float bssrdf_sample_distance(KernelGlobals *kg, float radius, float refl, float u)
{
int table_offset = kernel_data.bssrdf.table_offset;
float r = lookup_table_read_2D(kg, u, refl, table_offset, BSSRDF_RADIUS_TABLE_SIZE, BSSRDF_REFL_TABLE_SIZE);
return r*radius;
}
#ifdef BSSRDF_MULTI_EVAL
__device float bssrdf_pdf(KernelGlobals *kg, float radius, float refl, float r)
{
if(r >= radius)
return 0.0f;
/* todo: when we use the real BSSRDF this will need to be divided by the maximum
* radius instead of the average radius */
float t = r/radius;
int table_offset = kernel_data.bssrdf.table_offset + BSSRDF_PDF_TABLE_OFFSET;
float pdf = lookup_table_read_2D(kg, t, refl, table_offset, BSSRDF_RADIUS_TABLE_SIZE, BSSRDF_REFL_TABLE_SIZE);
pdf /= radius;
return pdf;
}
#endif
__device ShaderClosure *subsurface_scatter_pick_closure(KernelGlobals *kg, ShaderData *sd, float *probability)
{
/* sum sample weights of bssrdf and bsdf */
float bsdf_sum = 0.0f;
float bssrdf_sum = 0.0f;
for(int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_BSDF(sc->type))
bsdf_sum += sc->sample_weight;
else if(CLOSURE_IS_BSSRDF(sc->type))
bssrdf_sum += sc->sample_weight;
}
/* use bsdf or bssrdf? */
float r = sd->randb_closure*(bsdf_sum + bssrdf_sum);
if(r < bsdf_sum) {
/* use bsdf, and adjust randb so we can reuse it for picking a bsdf */
sd->randb_closure = r/bsdf_sum;
*probability = (bsdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/bsdf_sum: 1.0f;
return NULL;
}
/* use bssrdf */
r -= bsdf_sum;
sd->randb_closure = 0.0f; /* not needed anymore */
float sum = 0.0f;
for(int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_BSSRDF(sc->type)) {
sum += sc->sample_weight;
if(r <= sum) {
#ifdef BSSRDF_MULTI_EVAL
*probability = (bssrdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/bssrdf_sum: 1.0f;
#else
*probability = (bssrdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/sc->sample_weight: 1.0f;
#endif
return sc;
}
}
}
/* should never happen */
*probability = 1.0f;
return NULL;
}
#ifdef BSSRDF_MULTI_EVAL
__device float3 subsurface_scatter_multi_eval(KernelGlobals *kg, ShaderData *sd, bool hit, float refl, float *r, int num_r, bool all)
{
/* compute pdf */
float3 eval_sum = make_float3(0.0f, 0.0f, 0.0f);
float pdf_sum = 0.0f;
float sample_weight_sum = 0.0f;
int num_bssrdf = 0;
for(int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_BSSRDF(sc->type)) {
float sample_weight = (all)? 1.0f: sc->sample_weight;
/* compute pdf */
float pdf = 1.0f;
for(int i = 0; i < num_r; i++)
pdf *= bssrdf_pdf(kg, sc->data0, refl, r[i]);
eval_sum += sc->weight*pdf;
pdf_sum += sample_weight*pdf;
sample_weight_sum += sample_weight;
num_bssrdf++;
}
}
float inv_pdf_sum;
if(pdf_sum > 0.0f) {
/* in case of non-progressive integrate we sample all bssrdf's once,
* for progressive we pick one, so adjust pdf for that */
if(all)
inv_pdf_sum = 1.0f/pdf_sum;
else
inv_pdf_sum = sample_weight_sum/pdf_sum;
}
else
inv_pdf_sum = 0.0f;
float3 weight = eval_sum * inv_pdf_sum;
return weight;
}
#endif
/* replace closures with a single diffuse bsdf closure after scatter step */
__device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, float3 weight)
{
ShaderClosure *sc = &sd->closure[0];
sd->num_closure = 1;
sc->weight = weight;
sc->sample_weight = 1.0f;
sc->data0 = 0.0f;
sc->data1 = 0.0f;
sc->N = sd->N;
sd->flag &= ~SD_CLOSURE_FLAGS;
sd->flag |= bsdf_diffuse_setup(sc);
sd->randb_closure = 0.0f;
/* todo: evaluate shading to get blurred textures and bump mapping */
/* shader_eval_surface(kg, sd, 0.0f, state_flag, SHADER_CONTEXT_SSS); */
}
/* subsurface scattering step, from a point on the surface to another nearby point on the same object */
__device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, int state_flag, ShaderClosure *sc, uint *lcg_state, bool all)
{
float radius = sc->data0;
float refl = max(average(sc->weight)*3.0f, 0.0f);
float r = 0.0f;
bool hit = false;
float3 weight = make_float3(1.0f, 1.0f, 1.0f);
#ifdef BSSRDF_MULTI_EVAL
float r_attempts[BSSRDF_MAX_ATTEMPTS];
#endif
int num_attempts;
/* attempt to find a hit a given number of times before giving up */
for(num_attempts = 0; num_attempts < kernel_data.bssrdf.num_attempts; num_attempts++) {
/* random numbers for sampling */
float u1 = lcg_step(lcg_state);
float u2 = lcg_step(lcg_state);
float u3 = lcg_step(lcg_state);
float u4 = lcg_step(lcg_state);
float u5 = lcg_step(lcg_state);
float u6 = lcg_step(lcg_state);
r = bssrdf_sample_distance(kg, radius, refl, u5);
#ifdef BSSRDF_MULTI_EVAL
r_attempts[num_attempts] = r;
#endif
float3 p1 = sd->P + sample_uniform_sphere(u1, u2)*r;
float3 p2 = sd->P + sample_uniform_sphere(u3, u4)*r;
/* create ray */
Ray ray;
ray.P = p1;
ray.D = normalize_len(p2 - p1, &ray.t);
ray.dP = sd->dP;
ray.dD.dx = make_float3(0.0f, 0.0f, 0.0f);
ray.dD.dy = make_float3(0.0f, 0.0f, 0.0f);
ray.time = sd->time;
/* intersect with the same object. if multiple intersections are
* found it will randomly pick one of them */
Intersection isect;
if(scene_intersect_subsurface(kg, &ray, &isect, sd->object, u6) == 0)
continue;
/* setup new shading point */
shader_setup_from_subsurface(kg, sd, &isect, &ray);
hit = true;
num_attempts++;
break;
}
/* evaluate subsurface scattering closures */
#ifdef BSSRDF_MULTI_EVAL
weight *= subsurface_scatter_multi_eval(kg, sd, hit, refl, r_attempts, num_attempts, all);
#else
weight *= sc->weight;
#endif
#ifdef BSSRDF_SKIP_NO_HIT
if(!hit)
weight = make_float3(0.0f, 0.0f, 0.0f);
#endif
/* replace closures with a single diffuse BSDF */
subsurface_scatter_setup_diffuse_bsdf(sd, weight);
}
CCL_NAMESPACE_END

View File

@@ -66,8 +66,8 @@ KERNEL_TEX(uint4, texture_uint4, __svm_nodes)
KERNEL_TEX(uint, texture_uint, __shader_flag) KERNEL_TEX(uint, texture_uint, __shader_flag)
KERNEL_TEX(uint, texture_uint, __object_flag) KERNEL_TEX(uint, texture_uint, __object_flag)
/* camera/film */ /* lookup tables */
KERNEL_TEX(float, texture_float, __filter_table) KERNEL_TEX(float, texture_float, __lookup_table)
/* sobol */ /* sobol */
KERNEL_TEX(uint, texture_uint, __sobol_directions) KERNEL_TEX(uint, texture_uint, __sobol_directions)

View File

@@ -37,6 +37,13 @@ CCL_NAMESPACE_BEGIN
#define PARTICLE_SIZE 5 #define PARTICLE_SIZE 5
#define TIME_INVALID FLT_MAX #define TIME_INVALID FLT_MAX
#define BSSRDF_RADIUS_TABLE_SIZE 1024
#define BSSRDF_REFL_TABLE_SIZE 256
#define BSSRDF_PDF_TABLE_OFFSET (BSSRDF_RADIUS_TABLE_SIZE*BSSRDF_REFL_TABLE_SIZE)
#define BSSRDF_LOOKUP_TABLE_SIZE (BSSRDF_RADIUS_TABLE_SIZE*BSSRDF_REFL_TABLE_SIZE*2)
#define BSSRDF_MIN_RADIUS 1e-8f
#define BSSRDF_MAX_ATTEMPTS 8
#define TEX_NUM_FLOAT_IMAGES 5 #define TEX_NUM_FLOAT_IMAGES 5
/* device capabilities */ /* device capabilities */
@@ -48,6 +55,7 @@ CCL_NAMESPACE_BEGIN
#ifdef WITH_OSL #ifdef WITH_OSL
#define __OSL__ #define __OSL__
#endif #endif
#define __SUBSURFACE__
#endif #endif
#ifdef __KERNEL_CUDA__ #ifdef __KERNEL_CUDA__
@@ -423,7 +431,8 @@ typedef enum ShaderContext {
SHADER_CONTEXT_INDIRECT = 1, SHADER_CONTEXT_INDIRECT = 1,
SHADER_CONTEXT_EMISSION = 2, SHADER_CONTEXT_EMISSION = 2,
SHADER_CONTEXT_SHADOW = 3, SHADER_CONTEXT_SHADOW = 3,
SHADER_CONTEXT_NUM = 4 SHADER_CONTEXT_SSS = 4,
SHADER_CONTEXT_NUM = 5
} ShaderContext; } ShaderContext;
/* Shader Data /* Shader Data
@@ -438,20 +447,23 @@ enum ShaderDataFlag {
SD_BSDF = 4, /* have bsdf closure? */ SD_BSDF = 4, /* have bsdf closure? */
SD_BSDF_HAS_EVAL = 8, /* have non-singular bsdf closure? */ SD_BSDF_HAS_EVAL = 8, /* have non-singular bsdf closure? */
SD_BSDF_GLOSSY = 16, /* have glossy bsdf */ SD_BSDF_GLOSSY = 16, /* have glossy bsdf */
SD_HOLDOUT = 32, /* have holdout closure? */ SD_BSSRDF = 32, /* have bssrdf */
SD_VOLUME = 64, /* have volume closure? */ SD_HOLDOUT = 64, /* have holdout closure? */
SD_AO = 128, /* have ao closure? */ SD_VOLUME = 128, /* have volume closure? */
SD_AO = 256, /* have ao closure? */
SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY|SD_BSSRDF|SD_HOLDOUT|SD_VOLUME|SD_AO),
/* shader flags */ /* shader flags */
SD_SAMPLE_AS_LIGHT = 256, /* direct light sample */ SD_SAMPLE_AS_LIGHT = 512, /* direct light sample */
SD_HAS_SURFACE_TRANSPARENT = 512, /* has surface transparency */ SD_HAS_SURFACE_TRANSPARENT = 1024, /* has surface transparency */
SD_HAS_VOLUME = 1024, /* has volume shader */ SD_HAS_VOLUME = 2048, /* has volume shader */
SD_HOMOGENEOUS_VOLUME = 2048, /* has homogeneous volume */ SD_HOMOGENEOUS_VOLUME = 4096, /* has homogeneous volume */
/* object flags */ /* object flags */
SD_HOLDOUT_MASK = 4096, /* holdout for camera rays */ SD_HOLDOUT_MASK = 8192, /* holdout for camera rays */
SD_OBJECT_MOTION = 8192, /* has object motion blur */ SD_OBJECT_MOTION = 16384, /* has object motion blur */
SD_TRANSFORM_APPLIED = 16384 /* vertices have transform applied */ SD_TRANSFORM_APPLIED = 32768 /* vertices have transform applied */
}; };
typedef struct ShaderData { typedef struct ShaderData {
@@ -611,8 +623,9 @@ typedef struct KernelFilm {
int pass_shadow; int pass_shadow;
float pass_shadow_scale; float pass_shadow_scale;
int pass_pad1;
int pass_pad2; int filter_table_offset;
int filter_pad;
} KernelFilm; } KernelFilm;
typedef struct KernelBackground { typedef struct KernelBackground {
@@ -680,6 +693,9 @@ typedef struct KernelIntegrator {
int ao_samples; int ao_samples;
int mesh_light_samples; int mesh_light_samples;
int use_lamp_mis; int use_lamp_mis;
int subsurface_samples;
int pad1, pad2, pad3;
} KernelIntegrator; } KernelIntegrator;
typedef struct KernelBVH { typedef struct KernelBVH {
@@ -711,9 +727,14 @@ typedef struct KernelCurves {
float encasing_ratio; float encasing_ratio;
int curveflags; int curveflags;
int subdivisions; int subdivisions;
} KernelCurves; } KernelCurves;
typedef struct KernelBSSRDF {
int table_offset;
int num_attempts;
int pad1, pad2;
} KernelBSSRDF;
typedef struct KernelData { typedef struct KernelData {
KernelCamera cam; KernelCamera cam;
KernelFilm film; KernelFilm film;
@@ -722,6 +743,7 @@ typedef struct KernelData {
KernelIntegrator integrator; KernelIntegrator integrator;
KernelBVH bvh; KernelBVH bvh;
KernelCurves curve_kernel_data; KernelCurves curve_kernel_data;
KernelBSSRDF bssrdf;
} KernelData; } KernelData;
CCL_NAMESPACE_END CCL_NAMESPACE_END

View File

@@ -18,12 +18,14 @@ set(SRC
bsdf_phong_ramp.cpp bsdf_phong_ramp.cpp
bsdf_toon.cpp bsdf_toon.cpp
emissive.cpp emissive.cpp
osl_bssrdf.cpp
osl_closures.cpp osl_closures.cpp
osl_services.cpp osl_services.cpp
osl_shader.cpp osl_shader.cpp
) )
set(HEADER_SRC set(HEADER_SRC
osl_bssrdf.h
osl_closures.h osl_closures.h
osl_globals.h osl_globals.h
osl_services.h osl_services.h

View File

@@ -0,0 +1,90 @@
/*
* Adapted from Open Shading Language with this license:
*
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
* All Rights Reserved.
*
* Modifications Copyright 2011, Blender Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Sony Pictures Imageworks nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <OpenImageIO/fmath.h>
#include <OSL/genclosure.h>
#include "osl_bssrdf.h"
#include "osl_closures.h"
#include "kernel_types.h"
#include "kernel_montecarlo.h"
#include "closure/bsdf_diffuse.h"
#include "closure/bssrdf.h"
CCL_NAMESPACE_BEGIN
using namespace OSL;
class BSSRDFClosure : public CBSSRDFClosure {
public:
size_t memsize() const { return sizeof(*this); }
const char *name() const { return "bssrdf_cubic"; }
void setup()
{
sc.prim = NULL;
sc.data0 = fabsf(average(radius));
sc.data1 = 1.3f;
m_shaderdata_flag = bssrdf_setup(&sc);
}
bool mergeable(const ClosurePrimitive *other) const
{
return false;
}
void print_on(std::ostream &out) const
{
out << name() << " ((" << sc.N[0] << ", " << sc.N[1] << ", " << sc.N[2] << "))";
}
};
ClosureParam *closure_bssrdf_params()
{
static ClosureParam params[] = {
CLOSURE_FLOAT3_PARAM(BSSRDFClosure, sc.N),
CLOSURE_FLOAT3_PARAM(BSSRDFClosure, radius),
//CLOSURE_FLOAT_PARAM(BSSRDFClosure, sc.data1),
CLOSURE_STRING_KEYPARAM("label"),
CLOSURE_FINISH_PARAM(BSSRDFClosure)
};
return params;
}
CLOSURE_PREPARE(closure_bssrdf_prepare, BSSRDFClosure)
CCL_NAMESPACE_END

View File

@@ -0,0 +1,65 @@
/*
* Adapted from Open Shading Language with this license:
*
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
* All Rights Reserved.
*
* Modifications Copyright 2011, Blender Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Sony Pictures Imageworks nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __OSL_BSSRDF_H__
#define __OSL_BSSRDF_H__
#include <OSL/oslclosure.h>
#include <OSL/oslexec.h>
#include <OSL/genclosure.h>
#include "kernel_types.h"
#include "util_types.h"
CCL_NAMESPACE_BEGIN
class CBSSRDFClosure : public OSL::ClosurePrimitive {
public:
ShaderClosure sc;
float3 radius;
CBSSRDFClosure() : OSL::ClosurePrimitive(BSSRDF),
m_shaderdata_flag(0) { }
~CBSSRDFClosure() { }
int scattering() const { return LABEL_DIFFUSE; }
int shaderdata_flag() const { return m_shaderdata_flag; }
protected:
int m_shaderdata_flag;
};
CCL_NAMESPACE_END
#endif /* __OSL_BSSRDF_H__ */

View File

@@ -201,6 +201,8 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
closure_bsdf_diffuse_toon_params(), closure_bsdf_diffuse_toon_prepare); closure_bsdf_diffuse_toon_params(), closure_bsdf_diffuse_toon_prepare);
register_closure(ss, "specular_toon", id++, register_closure(ss, "specular_toon", id++,
closure_bsdf_specular_toon_params(), closure_bsdf_specular_toon_prepare); closure_bsdf_specular_toon_params(), closure_bsdf_specular_toon_prepare);
register_closure(ss, "bssrdf_cubic", id++,
closure_bssrdf_params(), closure_bssrdf_prepare);
} }
CCL_NAMESPACE_END CCL_NAMESPACE_END

View File

@@ -51,6 +51,7 @@ OSL::ClosureParam *closure_bsdf_diffuse_ramp_params();
OSL::ClosureParam *closure_bsdf_phong_ramp_params(); OSL::ClosureParam *closure_bsdf_phong_ramp_params();
OSL::ClosureParam *closure_bsdf_diffuse_toon_params(); OSL::ClosureParam *closure_bsdf_diffuse_toon_params();
OSL::ClosureParam *closure_bsdf_specular_toon_params(); OSL::ClosureParam *closure_bsdf_specular_toon_params();
OSL::ClosureParam *closure_bssrdf_params();
void closure_emission_prepare(OSL::RendererServices *, int id, void *data); void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
void closure_background_prepare(OSL::RendererServices *, int id, void *data); void closure_background_prepare(OSL::RendererServices *, int id, void *data);
@@ -60,6 +61,7 @@ void closure_bsdf_diffuse_ramp_prepare(OSL::RendererServices *, int id, void *da
void closure_bsdf_phong_ramp_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_phong_ramp_prepare(OSL::RendererServices *, int id, void *data);
void closure_bsdf_diffuse_toon_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_diffuse_toon_prepare(OSL::RendererServices *, int id, void *data);
void closure_bsdf_specular_toon_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_specular_toon_prepare(OSL::RendererServices *, int id, void *data);
void closure_bssrdf_prepare(OSL::RendererServices *, int id, void *data);
enum { enum {
AmbientOcclusion = 100 AmbientOcclusion = 100

View File

@@ -21,6 +21,7 @@
#include "kernel_globals.h" #include "kernel_globals.h"
#include "kernel_object.h" #include "kernel_object.h"
#include "osl_bssrdf.h"
#include "osl_closures.h" #include "osl_closures.h"
#include "osl_globals.h" #include "osl_globals.h"
#include "osl_services.h" #include "osl_services.h"
@@ -201,7 +202,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
} }
break; break;
} }
case OSL::ClosurePrimitive::Holdout: case OSL::ClosurePrimitive::Holdout: {
sc.sample_weight = 0.0f; sc.sample_weight = 0.0f;
sc.type = CLOSURE_HOLDOUT_ID; sc.type = CLOSURE_HOLDOUT_ID;
sc.prim = NULL; sc.prim = NULL;
@@ -211,7 +212,43 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
sd->flag |= SD_HOLDOUT; sd->flag |= SD_HOLDOUT;
} }
break; break;
case OSL::ClosurePrimitive::BSSRDF: }
case OSL::ClosurePrimitive::BSSRDF: {
CBSSRDFClosure *bssrdf = (CBSSRDFClosure *)prim;
float sample_weight = fabsf(average(weight));
if(sample_weight > 1e-5f && sd->num_closure+2 < MAX_CLOSURE) {
sc.sample_weight = sample_weight;
sc.type = bssrdf->sc.type;
sc.N = bssrdf->sc.N;
sc.data1 = bssrdf->sc.data1;
sc.prim = NULL;
/* create one closure for each color channel */
if(fabsf(weight.x) > 0.0f) {
sc.weight = make_float3(weight.x, 0.0f, 0.0f);
sc.data0 = bssrdf->radius.x;
sd->closure[sd->num_closure++] = sc;
sd->flag |= bssrdf->shaderdata_flag();
}
if(fabsf(weight.y) > 0.0f) {
sc.weight = make_float3(0.0f, weight.y, 0.0f);
sc.data0 = bssrdf->radius.y;
sd->closure[sd->num_closure++] = sc;
sd->flag |= bssrdf->shaderdata_flag();
}
if(fabsf(weight.z) > 0.0f) {
sc.weight = make_float3(0.0f, 0.0f, weight.z);
sc.data0 = bssrdf->radius.z;
sd->closure[sd->num_closure++] = sc;
sd->flag |= bssrdf->shaderdata_flag();
}
}
break;
}
case OSL::ClosurePrimitive::Debug: case OSL::ClosurePrimitive::Debug:
break; /* not implemented */ break; /* not implemented */
case OSL::ClosurePrimitive::Background: case OSL::ClosurePrimitive::Background:

View File

@@ -55,6 +55,7 @@ set(SRC_OSL
node_separate_rgb.osl node_separate_rgb.osl
node_set_normal.osl node_set_normal.osl
node_sky_texture.osl node_sky_texture.osl
node_subsurface_scattering.osl
node_tangent.osl node_tangent.osl
node_texture_coordinate.osl node_texture_coordinate.osl
node_translucent_bsdf.osl node_translucent_bsdf.osl

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2011, Blender Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "stdosl.h"
shader node_subsurface_scattering(
color Color = 0.8,
float Scale = 1.0,
vector Radius = vector(0.1, 0.1, 0.1),
float IOR = 1.3,
normal Normal = N,
output closure color BSSRDF = 0)
{
float eta = max(IOR, 1.0 + 1e-5);
BSSRDF = Color * bssrdf_cubic(N, Scale * Radius);
}

View File

@@ -461,6 +461,7 @@ closure color emission() BUILTIN;
closure color background() BUILTIN; closure color background() BUILTIN;
closure color holdout() BUILTIN; closure color holdout() BUILTIN;
closure color ambient_occlusion() BUILTIN; closure color ambient_occlusion() BUILTIN;
closure color bssrdf_cubic(normal N, vector radius) BUILTIN;
// Renderer state // Renderer state
int raytype (string typename) BUILTIN; int raytype (string typename) BUILTIN;

View File

@@ -25,6 +25,7 @@ __device void svm_node_glass_setup(ShaderData *sd, ShaderClosure *sc, int type,
if(type == CLOSURE_BSDF_SHARP_GLASS_ID) { if(type == CLOSURE_BSDF_SHARP_GLASS_ID) {
if(refract) { if(refract) {
sc->data0 = eta; sc->data0 = eta;
sc->data1 = 0.0f;
sd->flag |= bsdf_refraction_setup(sc); sd->flag |= bsdf_refraction_setup(sc);
} }
else else
@@ -58,6 +59,9 @@ __device_inline ShaderClosure *svm_node_closure_get_non_bsdf(ShaderData *sd, Clo
if(sd->num_closure < MAX_CLOSURE) { if(sd->num_closure < MAX_CLOSURE) {
sc->weight *= mix_weight; sc->weight *= mix_weight;
sc->type = type; sc->type = type;
#ifdef __OSL__
sc->prim = NULL;
#endif
sd->num_closure++; sd->num_closure++;
return sc; return sc;
} }
@@ -79,6 +83,9 @@ __device_inline ShaderClosure *svm_node_closure_get_bsdf(ShaderData *sd, float m
sc->weight = weight; sc->weight = weight;
sc->sample_weight = sample_weight; sc->sample_weight = sample_weight;
sd->num_closure++; sd->num_closure++;
#ifdef __OSL__
sc->prim = NULL;
#endif
return sc; return sc;
} }
@@ -125,10 +132,13 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
float roughness = param1; float roughness = param1;
if(roughness == 0.0f) { if(roughness == 0.0f) {
sc->data0 = 0.0f;
sc->data1 = 0.0f;
sd->flag |= bsdf_diffuse_setup(sc); sd->flag |= bsdf_diffuse_setup(sc);
} }
else { else {
sc->data0 = roughness; sc->data0 = roughness;
sc->data1 = 0.0f;
sd->flag |= bsdf_oren_nayar_setup(sc); sd->flag |= bsdf_oren_nayar_setup(sc);
} }
} }
@@ -138,6 +148,8 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
if(sc) { if(sc) {
sc->data0 = 0.0f;
sc->data1 = 0.0f;
sc->N = N; sc->N = N;
sd->flag |= bsdf_translucent_setup(sc); sd->flag |= bsdf_translucent_setup(sc);
} }
@@ -147,6 +159,8 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
if(sc) { if(sc) {
sc->data0 = 0.0f;
sc->data1 = 0.0f;
sc->N = N; sc->N = N;
sd->flag |= bsdf_transparent_setup(sc); sd->flag |= bsdf_transparent_setup(sc);
} }
@@ -164,6 +178,7 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
if(sc) { if(sc) {
sc->N = N; sc->N = N;
sc->data0 = param1; sc->data0 = param1;
sc->data1 = 0.0f;
/* setup bsdf */ /* setup bsdf */
if(type == CLOSURE_BSDF_REFLECTION_ID) if(type == CLOSURE_BSDF_REFLECTION_ID)
@@ -302,10 +317,73 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
/* sigma */ /* sigma */
sc->data0 = clamp(param1, 0.0f, 1.0f); sc->data0 = clamp(param1, 0.0f, 1.0f);
sc->data1 = 0.0f;
sd->flag |= bsdf_ashikhmin_velvet_setup(sc); sd->flag |= bsdf_ashikhmin_velvet_setup(sc);
} }
break; break;
} }
#ifdef __SUBSURFACE__
case CLOSURE_BSSRDF_ID: {
ShaderClosure *sc = &sd->closure[sd->num_closure];
float3 weight = sc->weight * mix_weight;
float sample_weight = fabsf(average(weight));
if(sample_weight > 1e-5f && sd->num_closure+2 < MAX_CLOSURE) {
/* radius * scale */
float3 radius = stack_load_float3(stack, data_node.w)*param1;
/* index of refraction */
float eta = fmaxf(param2, 1.0f + 1e-5f);
/* create one closure per color channel */
if(fabsf(weight.x) > 0.0f) {
sc->weight = make_float3(weight.x, 0.0f, 0.0f);
sc->sample_weight = sample_weight;
sc->data0 = radius.x;
sc->data1 = eta;
#ifdef __OSL__
sc->prim = NULL;
#endif
sc->N = N;
sd->flag |= bssrdf_setup(sc);
sd->num_closure++;
sc++;
}
if(fabsf(weight.y) > 0.0f) {
sc->weight = make_float3(0.0f, weight.y, 0.0f);
sc->sample_weight = sample_weight;
sc->data0 = radius.y;
sc->data1 = eta;
#ifdef __OSL__
sc->prim = NULL;
#endif
sc->N = N;
sd->flag |= bssrdf_setup(sc);
sd->num_closure++;
sc++;
}
if(fabsf(weight.z) > 0.0f) {
sc->weight = make_float3(0.0f, 0.0f, weight.z);
sc->sample_weight = sample_weight;
sc->data0 = radius.z;
sc->data1 = eta;
#ifdef __OSL__
sc->prim = NULL;
#endif
sc->N = N;
sd->flag |= bssrdf_setup(sc);
sd->num_closure++;
sc++;
}
}
break;
}
#endif
default: default:
break; break;
} }

View File

@@ -346,12 +346,11 @@ typedef enum ClosureType {
CLOSURE_BSDF_TRANSPARENT_ID, CLOSURE_BSDF_TRANSPARENT_ID,
CLOSURE_BSSRDF_CUBIC_ID, CLOSURE_BSSRDF_ID,
CLOSURE_EMISSION_ID, CLOSURE_EMISSION_ID,
CLOSURE_DEBUG_ID, CLOSURE_DEBUG_ID,
CLOSURE_BACKGROUND_ID, CLOSURE_BACKGROUND_ID,
CLOSURE_HOLDOUT_ID, CLOSURE_HOLDOUT_ID,
CLOSURE_SUBSURFACE_ID,
CLOSURE_AMBIENT_OCCLUSION_ID, CLOSURE_AMBIENT_OCCLUSION_ID,
CLOSURE_VOLUME_ID, CLOSURE_VOLUME_ID,
@@ -366,6 +365,7 @@ typedef enum ClosureType {
#define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_OREN_NAYAR_ID) #define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_OREN_NAYAR_ID)
#define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_GLOSSY_ID && type <= CLOSURE_BSDF_PHONG_RAMP_ID) #define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_GLOSSY_ID && type <= CLOSURE_BSDF_PHONG_RAMP_ID)
#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID) #define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID)
#define CLOSURE_IS_BSSRDF(type) (type == CLOSURE_BSSRDF_ID)
#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID) #define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID)
#define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID) #define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID)
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID) #define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)

View File

@@ -17,10 +17,10 @@ set(SRC
attribute.cpp attribute.cpp
background.cpp background.cpp
buffers.cpp buffers.cpp
bssrdf.cpp
camera.cpp camera.cpp
film.cpp film.cpp
# film_response.cpp (code unused) # film_response.cpp (code unused)
filter.cpp
graph.cpp graph.cpp
image.cpp image.cpp
integrator.cpp integrator.cpp
@@ -37,6 +37,7 @@ set(SRC
shader.cpp shader.cpp
sobol.cpp sobol.cpp
svm.cpp svm.cpp
tables.cpp
tile.cpp tile.cpp
) )
@@ -44,10 +45,10 @@ set(SRC_HEADERS
attribute.h attribute.h
background.h background.h
buffers.h buffers.h
bssrdf.h
camera.h camera.h
film.h film.h
# film_response.h (code unused) # film_response.h (code unused)
filter.h
graph.h graph.h
image.h image.h
integrator.h integrator.h
@@ -63,6 +64,7 @@ set(SRC_HEADERS
shader.h shader.h
sobol.h sobol.h
svm.h svm.h
tables.h
tile.h tile.h
) )

View File

@@ -0,0 +1,141 @@
/*
* Copyright 2011, Blender Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "bssrdf.h"
#include "util_algorithm.h"
#include "util_math.h"
#include "util_types.h"
#include "kernel_types.h"
#include "kernel_montecarlo.h"
#include "closure/bsdf_diffuse.h"
#include "closure/bssrdf.h"
CCL_NAMESPACE_BEGIN
/* Cumulative density function utilities */
static float cdf_lookup_inverse(const vector<float>& table, float2 range, float x)
{
int index = upper_bound(table.begin(), table.end(), x) - table.begin();
if(index == 0)
return range[0];
else if(index == table.size())
return range[1];
else
index--;
float t = (x - table[index])/(table[index+1] - table[index]);
float y = ((index + t)/(table.size() - 1));
return y*(range[1] - range[0]) + range[0];
}
static void cdf_invert(vector<float>& to, float2 to_range, const vector<float>& from, float2 from_range)
{
float step = 1.0f/(float)(to.size() - 1);
for(int i = 0; i < to.size(); i++) {
float x = (i*step)*(from_range[1] - from_range[0]) + from_range[0];
to[i] = cdf_lookup_inverse(from, to_range, x);
}
}
/* BSSRDF */
static float bssrdf_lookup_table_max_radius(const BSSRDFParams *ss)
{
/* todo: adjust when we use the real BSSRDF */
return ss->ld;
}
static void bssrdf_lookup_table_create(const BSSRDFParams *ss, vector<float>& sample_table, vector<float>& pdf_table)
{
const int size = BSSRDF_RADIUS_TABLE_SIZE;
vector<float> cdf(size);
vector<float> pdf(size);
float step = 1.0f/(float)(size - 1);
float max_radius = bssrdf_lookup_table_max_radius(ss);
float pdf_sum = 0.0f;
/* compute the probability density function */
for(int i = 0; i < pdf.size(); i++) {
float x = (i*step)*max_radius;
pdf[i] = bssrdf_cubic(ss->ld, x);
pdf_sum += pdf[i];
}
/* adjust for area covered by each distance */
for(int i = 0; i < pdf.size(); i++) {
float x = (i*step)*max_radius;
pdf[i] *= 2*M_PI_F*x;
}
/* normalize pdf, we multiply in reflectance later */
if(pdf_sum > 0.0f)
for(int i = 0; i < pdf.size(); i++)
pdf[i] /= pdf_sum;
/* sum to account for sampling which uses overlapping sphere */
for(int i = pdf.size() - 2; i >= 0; i--)
pdf[i] = pdf[i] + pdf[i+1];
/* compute the cumulative density function */
cdf[0] = 0.0f;
for(int i = 1; i < size; i++)
cdf[i] = cdf[i-1] + 0.5f*(pdf[i-1] + pdf[i])*step*max_radius;
/* invert cumulative density function for importance sampling */
float2 cdf_range = make_float2(0.0f, cdf[size - 1]);
float2 table_range = make_float2(0.0f, max_radius);
cdf_invert(sample_table, table_range, cdf, cdf_range);
/* copy pdf table */
for(int i = 0; i < pdf.size(); i++)
pdf_table[i] = pdf[i];
}
void bssrdf_table_build(vector<float>& table)
{
vector<float> sample_table(BSSRDF_RADIUS_TABLE_SIZE);
vector<float> pdf_table(BSSRDF_RADIUS_TABLE_SIZE);
table.resize(BSSRDF_LOOKUP_TABLE_SIZE);
/* create a 2D lookup table, for reflection x sample radius */
for(int i = 0; i < BSSRDF_REFL_TABLE_SIZE; i++) {
float refl = (float)i/(float)(BSSRDF_REFL_TABLE_SIZE-1);
float ior = 1.3f;
float radius = 1.0f;
BSSRDFParams ss;
bssrdf_setup_params(&ss, refl, radius, ior);
bssrdf_lookup_table_create(&ss, sample_table, pdf_table);
memcpy(&table[i*BSSRDF_RADIUS_TABLE_SIZE], &sample_table[0], BSSRDF_RADIUS_TABLE_SIZE*sizeof(float));
memcpy(&table[BSSRDF_PDF_TABLE_OFFSET + i*BSSRDF_RADIUS_TABLE_SIZE], &pdf_table[0], BSSRDF_RADIUS_TABLE_SIZE*sizeof(float));
}
}
CCL_NAMESPACE_END

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2011, Blender Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __BSSRDF_H__
#define __BSSRDF_H__
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
void bssrdf_table_build(vector<float>& table);
CCL_NAMESPACE_END
#endif /* __BSSRDF_H__ */

View File

@@ -22,9 +22,12 @@
#include "integrator.h" #include "integrator.h"
#include "mesh.h" #include "mesh.h"
#include "scene.h" #include "scene.h"
#include "tables.h"
#include "util_algorithm.h" #include "util_algorithm.h"
#include "util_debug.h"
#include "util_foreach.h" #include "util_foreach.h"
#include "util_math.h"
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
@@ -171,12 +174,84 @@ bool Pass::contains(const vector<Pass>& passes, PassType type)
return false; return false;
} }
/* Pixel Filter */
static float filter_func_box(float v, float width)
{
return (float)1;
}
static float filter_func_gaussian(float v, float width)
{
v *= (float)2/width;
return (float)expf((float)-2*v*v);
}
static vector<float> filter_table(FilterType type, float width)
{
const int filter_table_size = FILTER_TABLE_SIZE-1;
vector<float> filter_table_cdf(filter_table_size+1);
vector<float> filter_table(filter_table_size+1);
float (*filter_func)(float, float) = NULL;
int i, half_size = filter_table_size/2;
switch(type) {
case FILTER_BOX:
filter_func = filter_func_box;
break;
case FILTER_GAUSSIAN:
filter_func = filter_func_gaussian;
break;
default:
assert(0);
}
/* compute cumulative distribution function */
filter_table_cdf[0] = 0.0f;
for(i = 0; i < filter_table_size; i++) {
float x = i*width*0.5f/(filter_table_size-1);
float y = filter_func(x, width);
filter_table_cdf[i+1] += filter_table_cdf[i] + fabsf(y);
}
for(i = 0; i <= filter_table_size; i++)
filter_table_cdf[i] /= filter_table_cdf[filter_table_size];
/* create importance sampling table */
for(i = 0; i <= half_size; i++) {
float x = i/(float)half_size;
int index = upper_bound(filter_table_cdf.begin(), filter_table_cdf.end(), x) - filter_table_cdf.begin();
float t;
if(index < filter_table_size+1) {
t = (x - filter_table_cdf[index])/(filter_table_cdf[index+1] - filter_table_cdf[index]);
}
else {
t = 0.0f;
index = filter_table_size;
}
float y = ((index + t)/(filter_table_size))*width;
filter_table[half_size+i] = 0.5f*(1.0f + y);
filter_table[half_size-i] = 0.5f*(1.0f - y);
}
return filter_table;
}
/* Film */ /* Film */
Film::Film() Film::Film()
{ {
exposure = 0.8f; exposure = 0.8f;
Pass::add(PASS_COMBINED, passes); Pass::add(PASS_COMBINED, passes);
filter_type = FILTER_BOX;
filter_width = 1.0f;
filter_table_offset = TABLE_OFFSET_INVALID;
need_update = true; need_update = true;
} }
@@ -184,10 +259,12 @@ Film::~Film()
{ {
} }
void Film::device_update(Device *device, DeviceScene *dscene) void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
{ {
if(!need_update) if(!need_update)
return; return;
device_free(device, dscene, scene);
KernelFilm *kfilm = &dscene->data.film; KernelFilm *kfilm = &dscene->data.film;
@@ -284,17 +361,28 @@ void Film::device_update(Device *device, DeviceScene *dscene)
kfilm->pass_stride = align_up(kfilm->pass_stride, 4); kfilm->pass_stride = align_up(kfilm->pass_stride, 4);
/* update filter table */
vector<float> table = filter_table(filter_type, filter_width);
filter_table_offset = scene->lookup_tables->add_table(dscene, table);
kfilm->filter_table_offset = (int)filter_table_offset;
need_update = false; need_update = false;
} }
void Film::device_free(Device *device, DeviceScene *dscene) void Film::device_free(Device *device, DeviceScene *dscene, Scene *scene)
{ {
if(filter_table_offset != TABLE_OFFSET_INVALID) {
scene->lookup_tables->remove_table(filter_table_offset);
filter_table_offset = TABLE_OFFSET_INVALID;
}
} }
bool Film::modified(const Film& film) bool Film::modified(const Film& film)
{ {
return !(exposure == film.exposure return !(exposure == film.exposure
&& Pass::equals(passes, film.passes)); && Pass::equals(passes, film.passes)
&& filter_type == film.filter_type
&& filter_width == film.filter_width);
} }
void Film::tag_passes_update(Scene *scene, const vector<Pass>& passes_) void Film::tag_passes_update(Scene *scene, const vector<Pass>& passes_)

View File

@@ -30,6 +30,11 @@ class Device;
class DeviceScene; class DeviceScene;
class Scene; class Scene;
typedef enum FilterType {
FILTER_BOX,
FILTER_GAUSSIAN
} FilterType;
class Pass { class Pass {
public: public:
PassType type; PassType type;
@@ -47,13 +52,18 @@ class Film {
public: public:
float exposure; float exposure;
vector<Pass> passes; vector<Pass> passes;
FilterType filter_type;
float filter_width;
size_t filter_table_offset;
bool need_update; bool need_update;
Film(); Film();
~Film(); ~Film();
void device_update(Device *device, DeviceScene *dscene); void device_update(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene); void device_free(Device *device, DeviceScene *dscene, Scene *scene);
bool modified(const Film& film); bool modified(const Film& film);
void tag_passes_update(Scene *scene, const vector<Pass>& passes_); void tag_passes_update(Scene *scene, const vector<Pass>& passes_);

View File

@@ -1,142 +0,0 @@
/*
* Copyright 2011, Blender Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "camera.h"
#include "device.h"
#include "filter.h"
#include "scene.h"
#include "kernel_types.h"
#include "util_algorithm.h"
#include "util_debug.h"
#include "util_math.h"
CCL_NAMESPACE_BEGIN
Filter::Filter()
{
filter_type = FILTER_BOX;
filter_width = 1.0f;
need_update = true;
}
Filter::~Filter()
{
}
static float filter_func_box(float v, float width)
{
return (float)1;
}
static float filter_func_gaussian(float v, float width)
{
v *= (float)2/width;
return (float)expf((float)-2*v*v);
}
static vector<float> filter_table(FilterType type, float width)
{
const int filter_table_size = FILTER_TABLE_SIZE-1;
vector<float> filter_table_cdf(filter_table_size+1);
vector<float> filter_table(filter_table_size+1);
float (*filter_func)(float, float) = NULL;
int i, half_size = filter_table_size/2;
switch(type) {
case FILTER_BOX:
filter_func = filter_func_box;
break;
case FILTER_GAUSSIAN:
filter_func = filter_func_gaussian;
break;
default:
assert(0);
}
/* compute cumulative distribution function */
filter_table_cdf[0] = 0.0f;
for(i = 0; i < filter_table_size; i++) {
float x = i*width*0.5f/(filter_table_size-1);
float y = filter_func(x, width);
filter_table_cdf[i+1] += filter_table_cdf[i] + fabsf(y);
}
for(i = 0; i <= filter_table_size; i++)
filter_table_cdf[i] /= filter_table_cdf[filter_table_size];
/* create importance sampling table */
for(i = 0; i <= half_size; i++) {
float x = i/(float)half_size;
int index = upper_bound(filter_table_cdf.begin(), filter_table_cdf.end(), x) - filter_table_cdf.begin();
float t;
if(index < filter_table_size+1) {
t = (x - filter_table_cdf[index])/(filter_table_cdf[index+1] - filter_table_cdf[index]);
}
else {
t = 0.0f;
index = filter_table_size;
}
float y = ((index + t)/(filter_table_size))*width;
filter_table[half_size+i] = 0.5f*(1.0f + y);
filter_table[half_size-i] = 0.5f*(1.0f - y);
}
return filter_table;
}
void Filter::device_update(Device *device, DeviceScene *dscene)
{
if(!need_update)
return;
device_free(device, dscene);
/* update __filter_table */
vector<float> table = filter_table(filter_type, filter_width);
dscene->filter_table.copy(&table[0], table.size());
device->tex_alloc("__filter_table", dscene->filter_table, true);
need_update = false;
}
void Filter::device_free(Device *device, DeviceScene *dscene)
{
device->tex_free(dscene->filter_table);
dscene->filter_table.clear();
}
bool Filter::modified(const Filter& filter)
{
return !(filter_type == filter.filter_type &&
filter_width == filter.filter_width);
}
void Filter::tag_update(Scene *scene)
{
need_update = true;
}
CCL_NAMESPACE_END

View File

@@ -187,6 +187,7 @@ public:
virtual bool has_surface_emission() { return false; } virtual bool has_surface_emission() { return false; }
virtual bool has_surface_transparent() { return false; } virtual bool has_surface_transparent() { return false; }
virtual bool has_surface_bssrdf() { return false; }
vector<ShaderInput*> inputs; vector<ShaderInput*> inputs;
vector<ShaderOutput*> outputs; vector<ShaderOutput*> outputs;

View File

@@ -54,6 +54,7 @@ Integrator::Integrator()
transmission_samples = 1; transmission_samples = 1;
ao_samples = 1; ao_samples = 1;
mesh_light_samples = 1; mesh_light_samples = 1;
subsurface_samples = 1;
progressive = true; progressive = true;
need_update = true; need_update = true;
@@ -108,6 +109,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->transmission_samples = transmission_samples; kintegrator->transmission_samples = transmission_samples;
kintegrator->ao_samples = ao_samples; kintegrator->ao_samples = ao_samples;
kintegrator->mesh_light_samples = mesh_light_samples; kintegrator->mesh_light_samples = mesh_light_samples;
kintegrator->subsurface_samples = subsurface_samples;
/* sobol directions table */ /* sobol directions table */
int max_samples = 1; int max_samples = 1;
@@ -163,6 +165,7 @@ bool Integrator::modified(const Integrator& integrator)
transmission_samples == integrator.transmission_samples && transmission_samples == integrator.transmission_samples &&
ao_samples == integrator.ao_samples && ao_samples == integrator.ao_samples &&
mesh_light_samples == integrator.mesh_light_samples && mesh_light_samples == integrator.mesh_light_samples &&
subsurface_samples == integrator.subsurface_samples &&
motion_blur == integrator.motion_blur); motion_blur == integrator.motion_blur);
} }

View File

@@ -54,6 +54,7 @@ public:
int transmission_samples; int transmission_samples;
int ao_samples; int ao_samples;
int mesh_light_samples; int mesh_light_samples;
int subsurface_samples;
bool progressive; bool progressive;

View File

@@ -1262,16 +1262,19 @@ void ProxyNode::compile(OSLCompiler& compiler)
/* BSDF Closure */ /* BSDF Closure */
BsdfNode::BsdfNode() BsdfNode::BsdfNode(bool scattering_)
: ShaderNode("bsdf") : ShaderNode("subsurface_scattering"), scattering(scattering_)
{ {
closure = ccl::CLOSURE_BSDF_DIFFUSE_ID; closure = ccl::CLOSURE_BSSRDF_ID;
add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
add_output("BSDF", SHADER_SOCKET_CLOSURE); if(scattering)
add_output("BSSRDF", SHADER_SOCKET_CLOSURE);
else
add_output("BSDF", SHADER_SOCKET_CLOSURE);
} }
void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3) void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3)
@@ -1313,7 +1316,8 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
(param3)? param3->stack_offset: SVM_STACK_INVALID); (param3)? param3->stack_offset: SVM_STACK_INVALID);
} }
else { else {
compiler.add_node(NODE_CLOSURE_BSDF, normal_in->stack_offset); compiler.add_node(NODE_CLOSURE_BSDF, normal_in->stack_offset, SVM_STACK_INVALID,
(param3)? param3->stack_offset: SVM_STACK_INVALID);
} }
} }
@@ -1548,6 +1552,29 @@ void TransparentBsdfNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_transparent_bsdf"); compiler.add(this, "node_transparent_bsdf");
} }
/* Subsurface Scattering Closure */
SubsurfaceScatteringNode::SubsurfaceScatteringNode()
: BsdfNode(true)
{
name = "subsurface_scattering";
closure = CLOSURE_BSSRDF_ID;
add_input("Scale", SHADER_SOCKET_FLOAT, 0.01f);
add_input("Radius", SHADER_SOCKET_VECTOR, make_float3(0.1f, 0.1f, 0.1f));
add_input("IOR", SHADER_SOCKET_FLOAT, 1.3f);
}
void SubsurfaceScatteringNode::compile(SVMCompiler& compiler)
{
BsdfNode::compile(compiler, input("Scale"), input("IOR"), input("Radius"));
}
void SubsurfaceScatteringNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_subsurface_scattering");
}
/* Emissive Closure */ /* Emissive Closure */
EmissionNode::EmissionNode() EmissionNode::EmissionNode()

View File

@@ -198,11 +198,13 @@ public:
class BsdfNode : public ShaderNode { class BsdfNode : public ShaderNode {
public: public:
SHADER_NODE_CLASS(BsdfNode) BsdfNode(bool scattering = false);
SHADER_NODE_BASE_CLASS(BsdfNode);
void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL); void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL);
ClosureType closure; ClosureType closure;
bool scattering;
}; };
class WardBsdfNode : public BsdfNode { class WardBsdfNode : public BsdfNode {
@@ -257,6 +259,12 @@ public:
static ShaderEnum distribution_enum; static ShaderEnum distribution_enum;
}; };
class SubsurfaceScatteringNode : public BsdfNode {
public:
SHADER_NODE_CLASS(SubsurfaceScatteringNode)
bool has_surface_bssrdf() { return true; }
};
class EmissionNode : public ShaderNode { class EmissionNode : public ShaderNode {
public: public:
SHADER_NODE_CLASS(EmissionNode) SHADER_NODE_CLASS(EmissionNode)

View File

@@ -73,7 +73,7 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
if(!need_update) if(!need_update)
return; return;
device_free(device, dscene); device_free(device, dscene, scene);
/* determine which shaders are in use */ /* determine which shaders are in use */
device_update_shaders_used(scene); device_update_shaders_used(scene);
@@ -114,11 +114,11 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
device_update_common(device, dscene, scene, progress); device_update_common(device, dscene, scene, progress);
} }
void OSLShaderManager::device_free(Device *device, DeviceScene *dscene) void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
{ {
OSLGlobals *og = (OSLGlobals*)device->osl_memory(); OSLGlobals *og = (OSLGlobals*)device->osl_memory();
device_free_common(device, dscene); device_free_common(device, dscene, scene);
/* clear shader engine */ /* clear shader engine */
og->use = false; og->use = false;
@@ -328,6 +328,7 @@ const char *OSLShaderManager::shader_load_bytecode(const string& hash, const str
OSLShaderInfo info; OSLShaderInfo info;
info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos); info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos); info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
loaded_shaders[hash] = info; loaded_shaders[hash] = info;
return loaded_shaders.find(hash)->first.c_str(); return loaded_shaders.find(hash)->first.c_str();
@@ -511,6 +512,8 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
current_shader->has_surface_emission = true; current_shader->has_surface_emission = true;
if(info->has_surface_transparent) if(info->has_surface_transparent)
current_shader->has_surface_transparent = true; current_shader->has_surface_transparent = true;
if(info->has_surface_bssrdf)
current_shader->has_surface_bssrdf = true;
} }
} }
@@ -671,6 +674,8 @@ void OSLCompiler::generate_nodes(const set<ShaderNode*>& nodes)
current_shader->has_surface_emission = true; current_shader->has_surface_emission = true;
if(node->has_surface_transparent()) if(node->has_surface_transparent())
current_shader->has_surface_transparent = true; current_shader->has_surface_transparent = true;
if(node->has_surface_bssrdf())
current_shader->has_surface_bssrdf = true;
} }
else else
nodes_done = false; nodes_done = false;
@@ -736,6 +741,7 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
shader->has_surface = false; shader->has_surface = false;
shader->has_surface_emission = false; shader->has_surface_emission = false;
shader->has_surface_transparent = false; shader->has_surface_transparent = false;
shader->has_surface_bssrdf = false;
shader->has_volume = false; shader->has_volume = false;
shader->has_displacement = false; shader->has_displacement = false;

View File

@@ -50,11 +50,13 @@ class ShaderOutput;
struct OSLShaderInfo { struct OSLShaderInfo {
OSLShaderInfo() OSLShaderInfo()
: has_surface_emission(false), has_surface_transparent(false) : has_surface_emission(false), has_surface_transparent(false),
has_surface_bssrdf(false)
{} {}
bool has_surface_emission; bool has_surface_emission;
bool has_surface_transparent; bool has_surface_transparent;
bool has_surface_bssrdf;
}; };
/* Shader Manage */ /* Shader Manage */
@@ -69,7 +71,7 @@ public:
bool use_osl() { return true; } bool use_osl() { return true; }
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene); void device_free(Device *device, DeviceScene *dscene, Scene *scene);
/* osl compile and query */ /* osl compile and query */
static bool osl_compile(const string& inputfile, const string& outputfile); static bool osl_compile(const string& inputfile, const string& outputfile);

View File

@@ -20,19 +20,19 @@
#include "background.h" #include "background.h"
#include "camera.h" #include "camera.h"
#include "curves.h"
#include "device.h" #include "device.h"
#include "film.h" #include "film.h"
#include "filter.h"
#include "integrator.h" #include "integrator.h"
#include "light.h" #include "light.h"
#include "shader.h"
#include "mesh.h" #include "mesh.h"
#include "object.h" #include "object.h"
#include "particles.h"
#include "curves.h"
#include "scene.h"
#include "svm.h"
#include "osl.h" #include "osl.h"
#include "particles.h"
#include "scene.h"
#include "shader.h"
#include "svm.h"
#include "tables.h"
#include "util_foreach.h" #include "util_foreach.h"
#include "util_progress.h" #include "util_progress.h"
@@ -46,7 +46,7 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
memset(&dscene.data, 0, sizeof(dscene.data)); memset(&dscene.data, 0, sizeof(dscene.data));
camera = new Camera(); camera = new Camera();
filter = new Filter(); lookup_tables = new LookupTables();
film = new Film(); film = new Film();
background = new Background(); background = new Background();
light_manager = new LightManager(); light_manager = new LightManager();
@@ -93,14 +93,13 @@ void Scene::free_memory(bool final)
if(device) { if(device) {
camera->device_free(device, &dscene); camera->device_free(device, &dscene);
filter->device_free(device, &dscene); film->device_free(device, &dscene, this);
film->device_free(device, &dscene);
background->device_free(device, &dscene); background->device_free(device, &dscene);
integrator->device_free(device, &dscene); integrator->device_free(device, &dscene);
object_manager->device_free(device, &dscene); object_manager->device_free(device, &dscene);
mesh_manager->device_free(device, &dscene); mesh_manager->device_free(device, &dscene);
shader_manager->device_free(device, &dscene); shader_manager->device_free(device, &dscene, this);
light_manager->device_free(device, &dscene); light_manager->device_free(device, &dscene);
particle_system_manager->device_free(device, &dscene); particle_system_manager->device_free(device, &dscene);
@@ -108,10 +107,12 @@ void Scene::free_memory(bool final)
if(!params.persistent_data || final) if(!params.persistent_data || final)
image_manager->device_free(device, &dscene); image_manager->device_free(device, &dscene);
lookup_tables->device_free(device, &dscene);
} }
if(final) { if(final) {
delete filter; delete lookup_tables;
delete camera; delete camera;
delete film; delete film;
delete background; delete background;
@@ -188,13 +189,8 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel()) return; if(progress.get_cancel()) return;
progress.set_status("Updating Filter");
filter->device_update(device, &dscene);
if(progress.get_cancel()) return;
progress.set_status("Updating Film"); progress.set_status("Updating Film");
film->device_update(device, &dscene); film->device_update(device, &dscene, this);
if(progress.get_cancel()) return; if(progress.get_cancel()) return;
@@ -203,6 +199,11 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel()) return; if(progress.get_cancel()) return;
progress.set_status("Updating Lookup Tables");
lookup_tables->device_update(device, &dscene);
if(progress.get_cancel()) return;
progress.set_status("Updating Device", "Writing constant memory"); progress.set_status("Updating Device", "Writing constant memory");
device->const_copy_to("__data", &dscene.data, sizeof(dscene.data)); device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
} }
@@ -247,7 +248,7 @@ bool Scene::need_reset()
|| object_manager->need_update || object_manager->need_update
|| mesh_manager->need_update || mesh_manager->need_update
|| light_manager->need_update || light_manager->need_update
|| filter->need_update || lookup_tables->need_update
|| integrator->need_update || integrator->need_update
|| shader_manager->need_update || shader_manager->need_update
|| particle_system_manager->need_update || particle_system_manager->need_update
@@ -261,7 +262,6 @@ void Scene::reset()
/* ensure all objects are updated */ /* ensure all objects are updated */
camera->tag_update(); camera->tag_update();
filter->tag_update(this);
film->tag_update(this); film->tag_update(this);
background->tag_update(this); background->tag_update(this);
integrator->tag_update(this); integrator->tag_update(this);

View File

@@ -39,10 +39,10 @@ class Camera;
class Device; class Device;
class DeviceInfo; class DeviceInfo;
class Film; class Film;
class Filter;
class Integrator; class Integrator;
class Light; class Light;
class LightManager; class LightManager;
class LookupTables;
class Mesh; class Mesh;
class MeshManager; class MeshManager;
class Object; class Object;
@@ -99,8 +99,8 @@ public:
device_vector<uint> shader_flag; device_vector<uint> shader_flag;
device_vector<uint> object_flag; device_vector<uint> object_flag;
/* filter */ /* lookup tables */
device_vector<float> filter_table; device_vector<float> lookup_table;
/* integrator */ /* integrator */
device_vector<uint> sobol_directions; device_vector<uint> sobol_directions;
@@ -155,7 +155,7 @@ class Scene {
public: public:
/* data */ /* data */
Camera *camera; Camera *camera;
Filter *filter; LookupTables *lookup_tables;
Film *film; Film *film;
Background *background; Background *background;
Integrator *integrator; Integrator *integrator;

View File

@@ -16,6 +16,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#include "bssrdf.h"
#include "device.h" #include "device.h"
#include "graph.h" #include "graph.h"
#include "light.h" #include "light.h"
@@ -25,6 +26,7 @@
#include "scene.h" #include "scene.h"
#include "shader.h" #include "shader.h"
#include "svm.h" #include "svm.h"
#include "tables.h"
#include "util_foreach.h" #include "util_foreach.h"
@@ -46,6 +48,7 @@ Shader::Shader()
has_surface = false; has_surface = false;
has_surface_transparent = false; has_surface_transparent = false;
has_surface_emission = false; has_surface_emission = false;
has_surface_bssrdf = false;
has_volume = false; has_volume = false;
has_displacement = false; has_displacement = false;
@@ -115,6 +118,7 @@ void Shader::tag_used(Scene *scene)
ShaderManager::ShaderManager() ShaderManager::ShaderManager()
{ {
need_update = true; need_update = true;
bssrdf_table_offset = TABLE_OFFSET_INVALID;
} }
ShaderManager::~ShaderManager() ShaderManager::~ShaderManager()
@@ -196,7 +200,8 @@ void ShaderManager::device_update_shaders_used(Scene *scene)
void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{ {
device_free_common(device, dscene); device->tex_free(dscene->shader_flag);
dscene->shader_flag.clear();
if(scene->shaders.size() == 0) if(scene->shaders.size() == 0)
return; return;
@@ -204,6 +209,7 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
uint shader_flag_size = scene->shaders.size()*4; uint shader_flag_size = scene->shaders.size()*4;
uint *shader_flag = dscene->shader_flag.resize(shader_flag_size); uint *shader_flag = dscene->shader_flag.resize(shader_flag_size);
uint i = 0; uint i = 0;
bool has_surface_bssrdf = false;
foreach(Shader *shader, scene->shaders) { foreach(Shader *shader, scene->shaders) {
uint flag = 0; uint flag = 0;
@@ -216,6 +222,8 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
flag |= SD_HAS_VOLUME; flag |= SD_HAS_VOLUME;
if(shader->homogeneous_volume) if(shader->homogeneous_volume)
flag |= SD_HOMOGENEOUS_VOLUME; flag |= SD_HOMOGENEOUS_VOLUME;
if(shader->has_surface_bssrdf)
has_surface_bssrdf = true;
shader_flag[i++] = flag; shader_flag[i++] = flag;
shader_flag[i++] = shader->pass_id; shader_flag[i++] = shader->pass_id;
@@ -224,10 +232,32 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
} }
device->tex_alloc("__shader_flag", dscene->shader_flag); device->tex_alloc("__shader_flag", dscene->shader_flag);
/* bssrdf lookup table */
KernelBSSRDF *kbssrdf = &dscene->data.bssrdf;
if(has_surface_bssrdf && bssrdf_table_offset == TABLE_OFFSET_INVALID) {
vector<float> table;
bssrdf_table_build(table);
bssrdf_table_offset = scene->lookup_tables->add_table(dscene, table);
kbssrdf->table_offset = (int)bssrdf_table_offset;
kbssrdf->num_attempts = BSSRDF_MAX_ATTEMPTS;
}
else if(!has_surface_bssrdf && bssrdf_table_offset != TABLE_OFFSET_INVALID) {
scene->lookup_tables->remove_table(bssrdf_table_offset);
bssrdf_table_offset = TABLE_OFFSET_INVALID;
}
} }
void ShaderManager::device_free_common(Device *device, DeviceScene *dscene) void ShaderManager::device_free_common(Device *device, DeviceScene *dscene, Scene *scene)
{ {
if(bssrdf_table_offset != TABLE_OFFSET_INVALID) {
scene->lookup_tables->remove_table(bssrdf_table_offset);
bssrdf_table_offset = TABLE_OFFSET_INVALID;
}
device->tex_free(dscene->shader_flag); device->tex_free(dscene->shader_flag);
dscene->shader_flag.clear(); dscene->shader_flag.clear();
} }

View File

@@ -75,6 +75,7 @@ public:
bool has_surface_transparent; bool has_surface_transparent;
bool has_volume; bool has_volume;
bool has_displacement; bool has_displacement;
bool has_surface_bssrdf;
/* requested mesh attributes */ /* requested mesh attributes */
AttributeRequestSet attributes; AttributeRequestSet attributes;
@@ -116,11 +117,11 @@ public:
/* device update */ /* device update */
virtual void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) = 0; virtual void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) = 0;
virtual void device_free(Device *device, DeviceScene *dscene) = 0; virtual void device_free(Device *device, DeviceScene *dscene, Scene *scene) = 0;
void device_update_shaders_used(Scene *scene); void device_update_shaders_used(Scene *scene);
void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free_common(Device *device, DeviceScene *dscene); void device_free_common(Device *device, DeviceScene *dscene, Scene *scene);
/* get globally unique id for a type of attribute */ /* get globally unique id for a type of attribute */
uint get_attribute_id(ustring name); uint get_attribute_id(ustring name);
@@ -138,6 +139,8 @@ protected:
typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap; typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap;
AttributeIDMap unique_attribute_id; AttributeIDMap unique_attribute_id;
size_t bssrdf_table_offset;
}; };
CCL_NAMESPACE_END CCL_NAMESPACE_END

View File

@@ -50,7 +50,7 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
return; return;
/* test if we need to update */ /* test if we need to update */
device_free(device, dscene); device_free(device, dscene, scene);
/* determine which shaders are in use */ /* determine which shaders are in use */
device_update_shaders_used(scene); device_update_shaders_used(scene);
@@ -99,9 +99,9 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
need_update = false; need_update = false;
} }
void SVMShaderManager::device_free(Device *device, DeviceScene *dscene) void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
{ {
device_free_common(device, dscene); device_free_common(device, dscene, scene);
device->tex_free(dscene->svm_nodes); device->tex_free(dscene->svm_nodes);
dscene->svm_nodes.clear(); dscene->svm_nodes.clear();
@@ -486,6 +486,8 @@ void SVMCompiler::generate_closure(ShaderNode *node, set<ShaderNode*>& done)
current_shader->has_surface_emission = true; current_shader->has_surface_emission = true;
if(node->has_surface_transparent()) if(node->has_surface_transparent())
current_shader->has_surface_transparent = true; current_shader->has_surface_transparent = true;
if(node->has_surface_bssrdf())
current_shader->has_surface_bssrdf = true;
/* end node is added outside of this */ /* end node is added outside of this */
} }
@@ -546,6 +548,8 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& don
current_shader->has_surface_emission = true; current_shader->has_surface_emission = true;
if(node->has_surface_transparent()) if(node->has_surface_transparent())
current_shader->has_surface_transparent = true; current_shader->has_surface_transparent = true;
if(node->has_surface_bssrdf())
current_shader->has_surface_bssrdf = true;
} }
done.insert(node); done.insert(node);
@@ -654,6 +658,7 @@ void SVMCompiler::compile(Shader *shader, vector<int4>& global_svm_nodes, int in
shader->has_surface = false; shader->has_surface = false;
shader->has_surface_emission = false; shader->has_surface_emission = false;
shader->has_surface_transparent = false; shader->has_surface_transparent = false;
shader->has_surface_bssrdf = false;
shader->has_volume = false; shader->has_volume = false;
shader->has_displacement = false; shader->has_displacement = false;

View File

@@ -48,7 +48,7 @@ public:
void reset(Scene *scene); void reset(Scene *scene);
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene); void device_free(Device *device, DeviceScene *dscene, Scene *scene);
}; };
/* Graph Compiler */ /* Graph Compiler */

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2011, Blender Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "device.h"
#include "scene.h"
#include "tables.h"
#include "util_debug.h"
CCL_NAMESPACE_BEGIN
/* Lookup Tables */
LookupTables::LookupTables()
{
need_update = true;
}
LookupTables::~LookupTables()
{
assert(lookup_tables.size() == 0);
}
void LookupTables::device_update(Device *device, DeviceScene *dscene)
{
if(!need_update)
return;
device->tex_alloc("__lookup_table", dscene->lookup_table);
need_update = false;
}
void LookupTables::device_free(Device *device, DeviceScene *dscene)
{
device->tex_free(dscene->lookup_table);
dscene->lookup_table.clear();
}
static size_t round_up_to_multiple(size_t size, size_t chunk)
{
return ((size + chunk - 1)/chunk) * chunk;
}
size_t LookupTables::add_table(DeviceScene *dscene, vector<float>& data)
{
assert(data.size() > 0);
need_update = true;
Table new_table;
new_table.offset = 0;
new_table.size = round_up_to_multiple(data.size(), TABLE_CHUNK_SIZE);
/* find space to put lookup table */
list<Table>::iterator table;
for(table = lookup_tables.begin(); table != lookup_tables.end(); table++) {
if(new_table.offset + new_table.size <= table->offset) {
lookup_tables.insert(table, new_table);
break;
}
else
new_table.offset = table->offset + table->size;
}
if(table == lookup_tables.end()) {
/* add at the end */
lookup_tables.push_back(new_table);
dscene->lookup_table.resize(new_table.offset + new_table.size);
}
/* copy table data and return offset */
dscene->lookup_table.copy_at(&data[0], new_table.offset, data.size());
return new_table.offset;
}
void LookupTables::remove_table(size_t offset)
{
need_update = true;
list<Table>::iterator table;
for(table = lookup_tables.begin(); table != lookup_tables.end(); table++) {
if(table->offset == offset) {
lookup_tables.erase(table);
break;
}
}
assert(table != lookup_tables.end());
}
CCL_NAMESPACE_END

View File

@@ -16,8 +16,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#ifndef __FILTER_H__ #ifndef __TABLES_H__
#define __FILTER_H__ #define __TABLES_H__
#include <util_list.h>
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
@@ -25,29 +27,30 @@ class Device;
class DeviceScene; class DeviceScene;
class Scene; class Scene;
typedef enum FilterType { enum { TABLE_CHUNK_SIZE = 256 };
FILTER_BOX, enum { TABLE_OFFSET_INVALID = -1 };
FILTER_GAUSSIAN
} FilterType;
class Filter { class LookupTables {
public: public:
/* pixel filter */ struct Table {
FilterType filter_type; size_t offset;
float filter_width; size_t size;
bool need_update; };
Filter(); bool need_update;
~Filter(); list<Table> lookup_tables;
LookupTables();
~LookupTables();
void device_update(Device *device, DeviceScene *dscene); void device_update(Device *device, DeviceScene *dscene);
void device_free(Device *device, DeviceScene *dscene); void device_free(Device *device, DeviceScene *dscene);
bool modified(const Filter& filter); size_t add_table(DeviceScene *dscene, vector<float>& data);
void tag_update(Scene *scene); void remove_table(size_t offset);
}; };
CCL_NAMESPACE_END CCL_NAMESPACE_END
#endif /* __FILTER_H__ */ #endif /* __TABLES_H__ */

View File

@@ -1151,14 +1151,7 @@ __device float safe_logf(float a, float b)
__device float safe_divide(float a, float b) __device float safe_divide(float a, float b)
{ {
float result; return (b != 0.0f)? a/b: 0.0f;
if(b == 0.0f)
result = 0.0f;
else
result = a/b;
return result;
} }
/* Ray Intersection */ /* Ray Intersection */

View File

@@ -171,6 +171,20 @@ void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
} }
#endif #endif
#if ((LIBAVCODEC_VERSION_MAJOR < 54) || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR < 28))
static inline
void avcodec_free_frame(AVFrame **frame)
{
/* don't need to do anything with old AVFrame
* since it does not have malloced members */
(void)frame;
}
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 54) || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 13))
#define FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
#endif
#ifndef FFMPEG_HAVE_AVIO #ifndef FFMPEG_HAVE_AVIO
#define AVIO_FLAG_WRITE URL_WRONLY #define AVIO_FLAG_WRITE URL_WRONLY
#define avio_open url_fopen #define avio_open url_fopen

View File

@@ -454,7 +454,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
GHOST_TDrawingContextType type, GHOST_TDrawingContextType type,
const bool stereoVisual, const GHOST_TUns16 numOfAASamples const bool stereoVisual, const GHOST_TUns16 numOfAASamples
) : ) :
GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone, stereoVisual, numOfAASamples), GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone, stereoVisual, false, numOfAASamples),
m_customCursor(0) m_customCursor(0)
{ {
NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[40]; NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[40];

View File

@@ -53,7 +53,7 @@ public:
const bool stereoVisual, const bool stereoVisual,
const GHOST_TUns16 numOfAASamples const GHOST_TUns16 numOfAASamples
) : ) :
GHOST_Window(width, height, state, type, stereoVisual, numOfAASamples), GHOST_Window(width, height, state, type, stereoVisual, false, numOfAASamples),
m_system(system) m_system(system)
{ {
setTitle(title); setTitle(title);

View File

@@ -130,7 +130,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(
int msPixelFormat) int msPixelFormat)
: :
GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone, GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone,
stereoVisual, numOfAASamples), stereoVisual, false, numOfAASamples),
m_system(system), m_system(system),
m_hDC(0), m_hDC(0),
m_hGlRc(0), m_hGlRc(0),

View File

@@ -44,6 +44,7 @@ set(SRC
if(WITH_OPENCOLORIO) if(WITH_OPENCOLORIO)
add_definitions( add_definitions(
-DWITH_OCIO -DWITH_OCIO
-DGLEW_STATIC
) )
list(APPEND INC_SYS list(APPEND INC_SYS

View File

@@ -30,7 +30,7 @@ Import('env')
sources = env.Glob('*.cc') sources = env.Glob('*.cc')
incs = '. ../guardedalloc ../../source/blender/blenlib' incs = '. ../guardedalloc ../../source/blender/blenlib'
defs = [] defs = [ 'GLEW_STATIC' ]
if env['WITH_BF_OCIO']: if env['WITH_BF_OCIO']:
defs.append('WITH_OCIO') defs.append('WITH_OCIO')

View File

@@ -381,8 +381,9 @@ void FallbackImpl::matrixTransformScale(float * , float * , const float *)
{ {
} }
void FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor) bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide)
{ {
return false;
} }
void FallbackImpl::finishGLSLDraw(OCIO_GLSLDrawState *state) void FallbackImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)

View File

@@ -283,9 +283,9 @@ void OCIO_matrixTransformScale(float * m44, float * offset4, const float *scale4
impl->matrixTransformScale(m44, offset4, scale4f); impl->matrixTransformScale(m44, offset4, scale4f);
} }
void OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor) int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, int predivide)
{ {
impl->setupGLSLDraw(state_r, processor); return (int) impl->setupGLSLDraw(state_r, processor, (bool) predivide);
} }
void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state) void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state)

View File

@@ -121,7 +121,7 @@ void OCIO_matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt);
void OCIO_matrixTransformScale(float * m44, float * offset4, const float * scale4); void OCIO_matrixTransformScale(float * m44, float * offset4, const float * scale4);
void OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor); int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, int predivide);
void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state); void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state);
void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state); void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state);

View File

@@ -551,228 +551,3 @@ void OCIOImpl::matrixTransformScale(float * m44, float * offset4, const float *s
{ {
MatrixTransform::Scale(m44, offset4, scale4f); MatrixTransform::Scale(m44, offset4, scale4f);
} }
/* **** OpenGL drawing routines using GLSL for color space transform ***** */
/* Some of the GLSL transform related functions below are adopted from
* ociodisplay utility of OpenColorIO project which are originally
*
* Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
*/
typedef struct OCIO_GLSLDrawState {
bool lut3d_texture_allocated; /* boolean flag indicating whether
* lut texture is allocated
*/
GLuint lut3d_texture; /* OGL texture ID for 3D LUT */
float *lut3d; /* 3D LUT table */
/* Cache */
std::string lut3dcacheid;
std::string shadercacheid;
/* GLSL stuff */
GLuint fragShader;
GLuint program;
/* Previous OpenGL state. */
GLint last_texture, last_texture_unit;
} OCIO_GLSLDrawState;
static const char * g_fragShaderText = ""
"\n"
"uniform sampler2D tex1;\n"
"uniform sampler3D tex2;\n"
"\n"
"void main()\n"
"{\n"
" vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
" gl_FragColor = OCIODisplay(col, tex2);\n"
"}\n";
static GLuint compileShaderText(GLenum shaderType, const char *text)
{
GLuint shader;
GLint stat;
shader = glCreateShader(shaderType);
glShaderSource(shader, 1, (const GLchar **) &text, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
if (!stat) {
GLchar log[1000];
GLsizei len;
glGetShaderInfoLog(shader, 1000, &len, log);
return 0;
}
return shader;
}
static GLuint linkShaders(GLuint fragShader)
{
if (!fragShader)
return 0;
GLuint program = glCreateProgram();
if (fragShader)
glAttachShader(program, fragShader);
glLinkProgram(program);
/* check link */
{
GLint stat;
glGetProgramiv(program, GL_LINK_STATUS, &stat);
if (!stat) {
GLchar log[1000];
GLsizei len;
glGetProgramInfoLog(program, 1000, &len, log);
fprintf(stderr, "Shader link error:\n%s\n", log);
return 0;
}
}
return program;
}
static OCIO_GLSLDrawState *allocateOpenGLState(void)
{
OCIO_GLSLDrawState *state;
/* Allocate memory for state. */
state = (OCIO_GLSLDrawState *) MEM_callocN(sizeof(OCIO_GLSLDrawState),
"OCIO OpenGL State struct");
/* Call constructors on new memory. */
new (&state->lut3dcacheid) std::string("");
new (&state->shadercacheid) std::string("");
return state;
}
/* Ensure LUT texture and array are allocated */
static void ensureLUT3DAllocated(OCIO_GLSLDrawState *state)
{
int num_3d_entries = 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE;
if (state->lut3d_texture_allocated)
return;
glGenTextures(1, &state->lut3d_texture);
state->lut3d = (float *) MEM_callocN(sizeof(float) * num_3d_entries, "OCIO GPU 3D LUT");
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB,
LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
0, GL_RGB,GL_FLOAT, &state->lut3d);
state->lut3d_texture_allocated = true;
}
/**
* Setup OpenGL contexts for a transform defined by processor using GLSL
* All LUT allocating baking and shader compilation happens here.
*
* Once this function is called, callee could start drawing images
* using regular 2D texture.
*
* When all drawing is finished, finishGLSLDraw shall be called to
* restore OpenGL context to it's pre-GLSL draw state.
*/
void OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor)
{
ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor;
/* Create state if needed. */
OCIO_GLSLDrawState *state;
if (!*state_r)
*state_r = allocateOpenGLState();
state = *state_r;
glGetIntegerv(GL_TEXTURE_2D, &state->last_texture);
glGetIntegerv(GL_ACTIVE_TEXTURE, &state->last_texture_unit);
ensureLUT3DAllocated(state);
/* Step 1: Create a GPU Shader Description */
GpuShaderDesc shaderDesc;
shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_0);
shaderDesc.setFunctionName("OCIODisplay");
shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
/* Step 2: Compute the 3D LUT */
std::string lut3dCacheID = ocio_processor->getGpuLut3DCacheID(shaderDesc);
if (lut3dCacheID != state->lut3dcacheid) {
state->lut3dcacheid = lut3dCacheID;
ocio_processor->getGpuLut3D(state->lut3d, shaderDesc);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0,
LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
GL_RGB, GL_FLOAT, state->lut3d);
}
/* Step 3: Compute the Shader */
std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc);
if (state->program == 0 || shaderCacheID != state->shadercacheid) {
state->shadercacheid = shaderCacheID;
std::ostringstream os;
os << ocio_processor->getGpuShaderText(shaderDesc) << "\n";
os << g_fragShaderText;
if (state->fragShader)
glDeleteShader(state->fragShader);
state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
if (state->program)
glDeleteProgram(state->program);
state->program = linkShaders(state->fragShader);
}
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
glActiveTexture(GL_TEXTURE0);
glUseProgram(state->program);
glUniform1i(glGetUniformLocation(state->program, "tex1"), 0);
glUniform1i(glGetUniformLocation(state->program, "tex2"), 1);
}
void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
{
glActiveTexture(state->last_texture_unit);
glBindTexture(GL_TEXTURE_2D, state->last_texture);
glUseProgram(0);
}
void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state)
{
using std::string;
if (state->lut3d_texture_allocated)
glDeleteTextures(1, &state->lut3d_texture);
if (state->lut3d)
MEM_freeN(state->lut3d);
state->lut3dcacheid.~string();
state->shadercacheid.~string();
MEM_freeN(state);
}

View File

@@ -96,7 +96,7 @@ public:
virtual void matrixTransformScale(float * m44, float * offset4, const float * scale4) = 0; virtual void matrixTransformScale(float * m44, float * offset4, const float * scale4) = 0;
virtual void setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor) = 0; virtual bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide) = 0;
virtual void finishGLSLDraw(struct OCIO_GLSLDrawState *state) = 0; virtual void finishGLSLDraw(struct OCIO_GLSLDrawState *state) = 0;
virtual void freeGLState(struct OCIO_GLSLDrawState *state_r) = 0; virtual void freeGLState(struct OCIO_GLSLDrawState *state_r) = 0;
}; };
@@ -169,7 +169,7 @@ public:
void matrixTransformScale(float * m44, float * offset4, const float * scale4); void matrixTransformScale(float * m44, float * offset4, const float * scale4);
void setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor); bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide);
void finishGLSLDraw(struct OCIO_GLSLDrawState *state); void finishGLSLDraw(struct OCIO_GLSLDrawState *state);
void freeGLState(struct OCIO_GLSLDrawState *state_r); void freeGLState(struct OCIO_GLSLDrawState *state_r);
}; };
@@ -243,7 +243,7 @@ public:
void matrixTransformScale(float * m44, float * offset4, const float * scale4); void matrixTransformScale(float * m44, float * offset4, const float * scale4);
void setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor); bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide);
void finishGLSLDraw(struct OCIO_GLSLDrawState *state); void finishGLSLDraw(struct OCIO_GLSLDrawState *state);
void freeGLState(struct OCIO_GLSLDrawState *state_r); void freeGLState(struct OCIO_GLSLDrawState *state_r);
}; };

View File

@@ -77,15 +77,33 @@ typedef struct OCIO_GLSLDrawState {
GLint last_texture, last_texture_unit; GLint last_texture, last_texture_unit;
} OCIO_GLSLDrawState; } OCIO_GLSLDrawState;
static const char * g_fragShaderText = "" /* Hardcoded to do alpha predivide before color space conversion */
static const char *g_fragShaderText = ""
"\n" "\n"
"uniform sampler2D tex1;\n" "uniform sampler2D tex1;\n"
"uniform sampler3D tex2;\n" "uniform sampler3D tex2;\n"
"uniform bool predivide;\n"
"\n" "\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n" " vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
" gl_FragColor = OCIODisplay(col, tex2);\n" " if (predivide == false || col[3] == 1.0f || col[3] == 0.0f) {\n"
" gl_FragColor = OCIODisplay(col, tex2);\n"
" } else {\n"
" float alpha = col[3];\n"
" float inv_alpha = 1.0f / alpha;\n"
"\n"
" col[0] *= inv_alpha;\n"
" col[1] *= inv_alpha;\n"
" col[2] *= inv_alpha;\n"
"\n"
" gl_FragColor = OCIODisplay(col, tex2);\n"
"\n"
" col[0] *= alpha;\n"
" col[1] *= alpha;\n"
" col[2] *= alpha;\n"
" }\n"
"\n"
"}\n"; "}\n";
static GLuint compileShaderText(GLenum shaderType, const char *text) static GLuint compileShaderText(GLenum shaderType, const char *text)
@@ -187,7 +205,7 @@ static void ensureLUT3DAllocated(OCIO_GLSLDrawState *state)
* When all drawing is finished, finishGLSLDraw shall be called to * When all drawing is finished, finishGLSLDraw shall be called to
* restore OpenGL context to it's pre-GLSL draw state. * restore OpenGL context to it's pre-GLSL draw state.
*/ */
void OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor) bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide)
{ {
ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor; ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor;
@@ -232,22 +250,36 @@ void OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
if (state->fragShader) if (state->fragShader)
glDeleteShader(state->fragShader); glDeleteShader(state->fragShader);
state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str()); state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
if (state->program) if (state->fragShader) {
glDeleteProgram(state->program); if (state->program)
glDeleteProgram(state->program);
state->program = linkShaders(state->fragShader); state->program = linkShaders(state->fragShader);
}
} }
glActiveTexture(GL_TEXTURE1); if (state->program) {
glBindTexture(GL_TEXTURE_3D, state->lut3d_texture); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glUseProgram(state->program); glUseProgram(state->program);
glUniform1i(glGetUniformLocation(state->program, "tex1"), 0); glUniform1i(glGetUniformLocation(state->program, "tex1"), 0);
glUniform1i(glGetUniformLocation(state->program, "tex2"), 1); glUniform1i(glGetUniformLocation(state->program, "tex2"), 1);
glUniform1i(glGetUniformLocation(state->program, "predivide"), predivide);
return true;
}
else {
glActiveTexture(state->last_texture_unit);
glBindTexture(GL_TEXTURE_2D, state->last_texture);
return false;
}
} }
void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state) void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
@@ -267,6 +299,12 @@ void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state)
if (state->lut3d) if (state->lut3d)
MEM_freeN(state->lut3d); MEM_freeN(state->lut3d);
if (state->program)
glDeleteProgram(state->program);
if (state->fragShader)
glDeleteShader(state->fragShader);
state->lut3dcacheid.~string(); state->lut3dcacheid.~string();
state->shadercacheid.~string(); state->shadercacheid.~string();

View File

@@ -66,7 +66,7 @@ colorspaces:
Rec. 709 (Full Range), Blender native linear space Rec. 709 (Full Range), Blender native linear space
isdata: false isdata: false
allocation: lg2 allocation: lg2
allocationvars: [-8.5, 5] allocationvars: [-15, 6]
- !<ColorSpace> - !<ColorSpace>
name: Raw name: Raw

View File

@@ -296,6 +296,7 @@ class SpellChecker():
"spacebar", "spacebar",
"tooltip", "tooltips", "tooltip", "tooltips",
"trackpad", "trackpad",
"tuple",
"unicode", "unicode",
"viewport", "viewports", "viewport", "viewports",
"viscoelastic", "viscoelastic",
@@ -437,6 +438,7 @@ class SpellChecker():
"ascii", "ascii",
"atrac", "atrac",
"bsdf", "bsdf",
"bssrdf",
"bw", "bw",
"ccd", "ccd",
"cmd", "cmd",

View File

@@ -204,36 +204,40 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
ob = context.object obj = context.object
split = layout.split() split = layout.split()
col = split.column() col = split.column()
col.prop(ob, "draw_type", text="Type") col.prop(obj, "draw_type", text="Type")
col = split.column() col = split.column()
row = col.row() row = col.row()
row.prop(ob, "show_bounds", text="Bounds") row.prop(obj, "show_bounds", text="Bounds")
sub = row.row() sub = row.row()
sub.active = ob.show_bounds sub.active = obj.show_bounds
sub.prop(ob, "draw_bounds_type", text="") sub.prop(obj, "draw_bounds_type", text="")
split = layout.split() split = layout.split()
col = split.column() col = split.column()
col.prop(ob, "show_name", text="Name") col.prop(obj, "show_name", text="Name")
col.prop(ob, "show_axis", text="Axis") col.prop(obj, "show_axis", text="Axis")
if ob.type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT'}:
obj_type = obj.type
if obj_type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT'}:
# Makes no sense for cameras, armtures, etc.! # Makes no sense for cameras, armtures, etc.!
col.prop(ob, "show_wire", text="Wire") col.prop(obj, "show_wire", text="Wire")
# Only useful with object having faces/materials... # Only useful with object having faces/materials...
col.prop(ob, "color", text="Object Color") col.prop(obj, "color", text="Object Color")
col = split.column() col = split.column()
col.prop(ob, "show_texture_space", text="Texture Space") col.prop(obj, "show_texture_space", text="Texture Space")
col.prop(ob, "show_x_ray", text="X-Ray") col.prop(obj, "show_x_ray", text="X-Ray")
if ob.type == 'MESH': if obj_type == 'MESH' or (obj_type == 'EMPTY' and obj.empty_draw_type == 'IMAGE'):
col.prop(ob, "show_transparent", text="Transparency") col.prop(obj, "show_transparent", text="Transparency")
col.prop(ob, "show_all_edges") if obj_type == 'MESH':
col.prop(obj, "show_all_edges")
class OBJECT_PT_duplication(ObjectButtonsPanel, Panel): class OBJECT_PT_duplication(ObjectButtonsPanel, Panel):

View File

@@ -886,6 +886,7 @@ class CLIP_PT_tools_clip(CLIP_PT_clip_view_panel, Panel):
layout.operator("clip.set_viewport_background") layout.operator("clip.set_viewport_background")
layout.operator("clip.setup_tracking_scene") layout.operator("clip.setup_tracking_scene")
layout.operator("clip.prefetch")
class CLIP_MT_view(Menu): class CLIP_MT_view(Menu):
@@ -945,6 +946,7 @@ class CLIP_MT_clip(Menu):
layout.operator("clip.open") layout.operator("clip.open")
if clip: if clip:
layout.operator("clip.prefetch")
layout.operator("clip.reload") layout.operator("clip.reload")
layout.menu("CLIP_MT_proxy") layout.menu("CLIP_MT_proxy")

View File

@@ -151,10 +151,17 @@ class NODE_MT_select(Menu):
layout.operator("node.select_all", text="Inverse").action = 'INVERT' layout.operator("node.select_all", text="Inverse").action = 'INVERT'
layout.operator("node.select_linked_from") layout.operator("node.select_linked_from")
layout.operator("node.select_linked_to") layout.operator("node.select_linked_to")
layout.separator()
layout.operator("node.select_same_type") layout.operator("node.select_same_type")
layout.operator("node.select_same_type_step").prev = True layout.operator("node.select_same_type_step").prev = True
layout.operator("node.select_same_type_step").prev = False layout.operator("node.select_same_type_step").prev = False
layout.separator()
layout.operator("node.find_node")
class NODE_MT_node(Menu): class NODE_MT_node(Menu):
bl_label = "Node" bl_label = "Node"

View File

@@ -247,6 +247,7 @@ struct DerivedMesh {
void *(*getVertDataArray)(DerivedMesh *dm, int type); void *(*getVertDataArray)(DerivedMesh *dm, int type);
void *(*getEdgeDataArray)(DerivedMesh *dm, int type); void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
void *(*getTessFaceDataArray)(DerivedMesh *dm, int type); void *(*getTessFaceDataArray)(DerivedMesh *dm, int type);
void *(*getLoopDataArray)(DerivedMesh *dm, int type);
void *(*getPolyDataArray)(DerivedMesh *dm, int type); void *(*getPolyDataArray)(DerivedMesh *dm, int type);
/** Retrieves the base CustomData structures for /** Retrieves the base CustomData structures for

View File

@@ -41,18 +41,17 @@ struct Object;
struct bAction; struct bAction;
struct Scene; struct Scene;
void BKE_group_free(struct Group *group); void BKE_group_free(struct Group *group);
void BKE_group_unlink(struct Group *group); void BKE_group_unlink(struct Group *group);
struct Group *add_group(struct Main *bmain, const char *name); struct Group *BKE_group_add(struct Main *bmain, const char *name);
struct Group *BKE_group_copy(struct Group *group); struct Group *BKE_group_copy(struct Group *group);
int add_to_group(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
int rem_from_group(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
struct Group *find_group(struct Object *ob, struct Group *group); struct Group *BKE_group_object_find(struct Group *group, struct Object *ob);
int object_in_group(struct Object *ob, struct Group *group); bool BKE_group_object_exists(struct Group *group, struct Object *ob);
int group_is_animated(struct Object *parent, struct Group *group); bool BKE_group_is_animated(struct Group *group, struct Object *parent);
void group_tag_recalc(struct Group *group); void BKE_group_tag_recalc(struct Group *group);
void group_handle_recalc_and_update(struct Scene *scene, struct Object *parent, struct Group *group); void BKE_group_handle_recalc_and_update(struct Scene *scene, struct Object *parent, struct Group *group);
#endif
#endif /* __BKE_GROUP_H__ */

View File

@@ -107,10 +107,12 @@ __attribute__((nonnull))
; ;
void clear_id_newpoins(void); void clear_id_newpoins(void);
#if 0
void IDnames_to_pupstring(const char **str, const char *title, const char *extraops, void IDnames_to_pupstring(const char **str, const char *title, const char *extraops,
struct ListBase *lb, struct ID *link, short *nr); struct ListBase *lb, struct ID *link, short *nr);
void IMAnames_to_pupstring(const char **str, const char *title, const char *extraops, void IMAnames_to_pupstring(const char **str, const char *title, const char *extraops,
struct ListBase *lb, struct ID *link, short *nr); struct ListBase *lb, struct ID *link, short *nr);
#endif
void flag_listbase_ids(ListBase *lb, short flag, short value); void flag_listbase_ids(ListBase *lb, short flag, short value);
void flag_all_listbases_ids(short flag, short value); void flag_all_listbases_ids(short flag, short value);

View File

@@ -59,7 +59,8 @@ struct Material *give_node_material(struct Material *ma); /* returns node materi
void BKE_material_make_local(struct Material *ma); void BKE_material_make_local(struct Material *ma);
void extern_local_matarar(struct Material **matar, short totcol); void extern_local_matarar(struct Material **matar, short totcol);
void automatname(struct Material *); /* UNUSED */
// void automatname(struct Material *);
/* material slots */ /* material slots */

View File

@@ -45,6 +45,7 @@ void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip);
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name); struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
void BKE_movieclip_reload(struct MovieClip *clip); void BKE_movieclip_reload(struct MovieClip *clip);
void BKE_movieclip_clear_cache(struct MovieClip *clip);
struct ImBuf *BKE_movieclip_get_ibuf(struct MovieClip *clip, struct MovieClipUser *user); struct ImBuf *BKE_movieclip_get_ibuf(struct MovieClip *clip, struct MovieClipUser *user);
struct ImBuf *BKE_movieclip_get_postprocessed_ibuf(struct MovieClip *clip, struct MovieClipUser *user, int postprocess_flag); struct ImBuf *BKE_movieclip_get_postprocessed_ibuf(struct MovieClip *clip, struct MovieClipUser *user, int postprocess_flag);

View File

@@ -444,9 +444,6 @@ const char * nodeStaticSocketInterfaceType(int type, int subtype);
BLI_ghashIterator_free(__node_socket_type_iter__); \ BLI_ghashIterator_free(__node_socket_type_iter__); \
} }
void nodeMakeDynamicType(struct bNode *node);
int nodeDynamicUnlinkText(struct ID *txtid);
struct bNodeSocket *nodeFindSocket(struct bNode *node, int in_out, const char *identifier); struct bNodeSocket *nodeFindSocket(struct bNode *node, int in_out, const char *identifier);
struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, const char *idname, struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, const char *idname,
const char *identifier, const char *name); const char *identifier, const char *name);
@@ -575,9 +572,6 @@ void BKE_node_preview_set_pixel(struct bNodePreview *preview, const f
/* ************** NODE TYPE ACCESS *************** */ /* ************** NODE TYPE ACCESS *************** */
const char *nodeLabel(struct bNode *node); const char *nodeLabel(struct bNode *node);
struct bNodeTree *nodeGroupEditGet(struct bNode *node);
struct bNodeTree *nodeGroupEditSet(struct bNode *node, int edit);
void nodeGroupEditClear(struct bNode *node);
int nodeGroupPoll(struct bNodeTree *nodetree, struct bNodeTree *grouptree); int nodeGroupPoll(struct bNodeTree *nodetree, struct bNodeTree *grouptree);
@@ -752,6 +746,7 @@ struct ShadeResult;
#define SH_NODE_TANGENT 174 #define SH_NODE_TANGENT 174
#define SH_NODE_NORMAL_MAP 175 #define SH_NODE_NORMAL_MAP 175
#define SH_NODE_HAIR_INFO 176 #define SH_NODE_HAIR_INFO 176
#define SH_NODE_SUBSURFACE_SCATTERING 177
/* custom defines options for Material node */ /* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1 #define SH_NODE_MAT_DIFF 1

View File

@@ -255,7 +255,8 @@ struct ParticleSystem *psys_get_current(struct Object *ob);
/* for rna */ /* for rna */
short psys_get_current_num(struct Object *ob); short psys_get_current_num(struct Object *ob);
void psys_set_current_num(Object *ob, int index); void psys_set_current_num(Object *ob, int index);
struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys); /* UNUSED */
// struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys);
struct Object *psys_get_lattice(struct ParticleSimulationData *sim); struct Object *psys_get_lattice(struct ParticleSimulationData *sim);

View File

@@ -45,7 +45,6 @@ void smokeModifier_reset_turbulence(struct SmokeModifierData *smd);
void smokeModifier_createType(struct SmokeModifierData *smd); void smokeModifier_createType(struct SmokeModifierData *smd);
void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData *tsmd); void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData *tsmd);
long long smoke_get_mem_req(int xres, int yres, int zres, int amplify);
float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]); float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
int smoke_get_data_flags(struct SmokeDomainSettings *sds); int smoke_get_data_flags(struct SmokeDomainSettings *sds);

View File

@@ -78,7 +78,8 @@ struct MTex *add_mtex_id(struct ID *id, int slot);
struct Tex *BKE_texture_copy(struct Tex *tex); struct Tex *BKE_texture_copy(struct Tex *tex);
struct Tex *localize_texture(struct Tex *tex); struct Tex *localize_texture(struct Tex *tex);
void BKE_texture_make_local(struct Tex *tex); void BKE_texture_make_local(struct Tex *tex);
void autotexname(struct Tex *tex); /* UNUSED */
// void autotexname(struct Tex *tex);
struct Tex *give_current_object_texture(struct Object *ob); struct Tex *give_current_object_texture(struct Object *ob);
struct Tex *give_current_material_texture(struct Material *ma); struct Tex *give_current_material_texture(struct Material *ma);

View File

@@ -124,7 +124,6 @@ void push_queue(DagNodeQueue *queue, DagNode *node);
void push_stack(DagNodeQueue *queue, DagNode *node); void push_stack(DagNodeQueue *queue, DagNode *node);
DagNode *pop_queue(DagNodeQueue *queue); DagNode *pop_queue(DagNodeQueue *queue);
DagNode *get_top_node_queue(DagNodeQueue *queue); DagNode *get_top_node_queue(DagNodeQueue *queue);
int queue_count(DagNodeQueue *queue);
void queue_delete(DagNodeQueue *queue); void queue_delete(DagNodeQueue *queue);
// Dag management // Dag management
@@ -137,9 +136,6 @@ DagNode *dag_get_node(DagForest *forest, void *fob);
DagNode *dag_get_sub_node(DagForest *forest, void *fob); DagNode *dag_get_sub_node(DagForest *forest, void *fob);
void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name); void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name);
DagNodeQueue *graph_dfs(void);
void set_node_xy(DagNode *node, float x, float y);
void graph_print_queue(DagNodeQueue *nqueue); void graph_print_queue(DagNodeQueue *nqueue);
void graph_print_queue_dist(DagNodeQueue *nqueue); void graph_print_queue_dist(DagNodeQueue *nqueue);
void graph_print_adj_list(DagForest *dag); void graph_print_adj_list(DagForest *dag);

View File

@@ -270,6 +270,7 @@ void DM_init_funcs(DerivedMesh *dm)
dm->getEdgeDataArray = DM_get_edge_data_layer; dm->getEdgeDataArray = DM_get_edge_data_layer;
dm->getTessFaceDataArray = DM_get_tessface_data_layer; dm->getTessFaceDataArray = DM_get_tessface_data_layer;
dm->getPolyDataArray = DM_get_poly_data_layer; dm->getPolyDataArray = DM_get_poly_data_layer;
dm->getLoopDataArray = DM_get_loop_data_layer;
bvhcache_init(&dm->bvhCache); bvhcache_init(&dm->bvhCache);
} }

View File

@@ -766,10 +766,10 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persiste
if (flag & DUPLILIST_DO_UPDATE) { if (flag & DUPLILIST_DO_UPDATE) {
/* note: update is optional because we don't always need object /* note: update is optional because we don't always need object
* transformations to be correct. Also fixes bug [#29616]. */ * transformations to be correct. Also fixes bug [#29616]. */
group_handle_recalc_and_update(scene, ob, group); BKE_group_handle_recalc_and_update(scene, ob, group);
} }
if (group_is_animated(ob, group)) if (BKE_group_is_animated(group, ob))
flag |= DUPLILIST_ANIMATED; flag |= DUPLILIST_ANIMATED;
for (go = group->gobject.first, id = 0; go; go = go->next, id++) { for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
@@ -953,6 +953,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
float vec[3], no[3], pmat[4][4]; float vec[3], no[3], pmat[4][4];
int totvert, a, oblay; int totvert, a, oblay;
unsigned int lay; unsigned int lay;
CustomDataMask dm_mask;
copy_m4_m4(pmat, par->obmat); copy_m4_m4(pmat, par->obmat);
@@ -961,16 +962,18 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
em = BMEdit_FromObject(par); em = BMEdit_FromObject(par);
if (em) { /* get derived mesh */
dm = editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); dm_mask = CD_MASK_BAREMESH;
} if (flag & DUPLILIST_FOR_RENDER)
else dm_mask |= CD_MASK_ORCO;
dm = mesh_get_derived_final(scene, par, CD_MASK_BAREMESH);
if (flag & DUPLILIST_FOR_RENDER) { if (em)
vdd.orco = (float(*)[3])BKE_mesh_orco_verts_get(par); dm = editbmesh_get_derived_cage(scene, par, em, dm_mask);
BKE_mesh_orco_verts_transform(me, vdd.orco, me->totvert, 0); else
} dm = mesh_get_derived_final(scene, par, dm_mask);
if (flag & DUPLILIST_FOR_RENDER)
vdd.orco = dm->getVertDataArray(dm, CD_ORCO);
else else
vdd.orco = NULL; vdd.orco = NULL;
@@ -1057,8 +1060,6 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
else go = go->next; /* group loop */ else go = go->next; /* group loop */
} }
if (vdd.orco)
MEM_freeN(vdd.orco);
dm->release(dm); dm->release(dm);
} }
@@ -1069,7 +1070,6 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
Base *base = NULL; Base *base = NULL;
DupliObject *dob; DupliObject *dob;
DerivedMesh *dm; DerivedMesh *dm;
Mesh *me = par->data;
MLoopUV *mloopuv; MLoopUV *mloopuv;
MPoly *mpoly, *mp; MPoly *mpoly, *mp;
MLoop *mloop; MLoop *mloop;
@@ -1081,6 +1081,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
GroupObject *go = NULL; GroupObject *go = NULL;
BMEditMesh *em; BMEditMesh *em;
float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */ float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
CustomDataMask dm_mask;
/* simple preventing of too deep nested groups */ /* simple preventing of too deep nested groups */
if (level > MAX_DUPLI_RECUR) return; if (level > MAX_DUPLI_RECUR) return;
@@ -1088,11 +1089,16 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
copy_m4_m4(pmat, par->obmat); copy_m4_m4(pmat, par->obmat);
em = BMEdit_FromObject(par); em = BMEdit_FromObject(par);
/* get derived mesh */
dm_mask = CD_MASK_BAREMESH;
if (flag & DUPLILIST_FOR_RENDER)
dm_mask |= CD_MASK_ORCO | CD_MASK_MLOOPUV;
if (em) { if (em) {
dm = editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); dm = editbmesh_get_derived_cage(scene, par, em, dm_mask);
} }
else { else {
dm = mesh_get_derived_final(scene, par, CD_MASK_BAREMESH); dm = mesh_get_derived_final(scene, par, dm_mask);
} }
totface = dm->getNumPolys(dm); totface = dm->getNumPolys(dm);
@@ -1101,9 +1107,8 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
mvert = dm->getVertArray(dm); mvert = dm->getVertArray(dm);
if (flag & DUPLILIST_FOR_RENDER) { if (flag & DUPLILIST_FOR_RENDER) {
orco = (float(*)[3])BKE_mesh_orco_verts_get(par); orco = dm->getVertDataArray(dm, CD_ORCO);
BKE_mesh_orco_verts_transform(me, orco, me->totvert, 0); mloopuv = dm->getLoopDataArray(dm, CD_MLOOPUV);
mloopuv = me->mloopuv;
} }
else { else {
orco = NULL; orco = NULL;
@@ -1215,7 +1220,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
if (mloopuv) { if (mloopuv) {
int j; int j;
for (j = 0; j < mpoly->totloop; j++) { for (j = 0; j < mpoly->totloop; j++) {
madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w); madd_v2_v2fl(dob->uv, mloopuv[mp->loopstart + j].uv, w);
} }
} }
} }
@@ -1238,9 +1243,6 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
else go = go->next; /* group loop */ else go = go->next; /* group loop */
} }
if (orco)
MEM_freeN(orco);
dm->release(dm); dm->release(dm);
} }
@@ -1331,7 +1333,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
/* gather list of objects or single object */ /* gather list of objects or single object */
if (part->ren_as == PART_DRAW_GR) { if (part->ren_as == PART_DRAW_GR) {
if (flag & DUPLILIST_DO_UPDATE) { if (flag & DUPLILIST_DO_UPDATE) {
group_handle_recalc_and_update(scene, par, part->dup_group); BKE_group_handle_recalc_and_update(scene, par, part->dup_group);
} }
if (part->draw & PART_DRAW_COUNT_GR) { if (part->draw & PART_DRAW_COUNT_GR) {

View File

@@ -1008,6 +1008,7 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
IMB_colormanagement_processor_free(cm_processor); IMB_colormanagement_processor_free(cm_processor);
} }
/* if view_settings, it also applies this to byte buffers */
void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings, void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings) const ColorManagedDisplaySettings *display_settings)
{ {
@@ -1021,7 +1022,7 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
float rgba[4], ycc[3], luma; float rgba[4], ycc[3], luma;
int ycc_mode = -1; int ycc_mode = -1;
const short is_float = (ibuf->rect_float != NULL); const short is_float = (ibuf->rect_float != NULL);
void *cache_handle = NULL;
struct ColormanageProcessor *cm_processor = NULL; struct ColormanageProcessor *cm_processor = NULL;
if (ibuf->rect == NULL && ibuf->rect_float == NULL) return; if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
@@ -1090,9 +1091,10 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
if (is_float) if (is_float)
rf = ibuf->rect_float; rf = ibuf->rect_float;
else else {
rc = (unsigned char *)ibuf->rect; rc = (unsigned char *)IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle);
}
if (ibuf->rect_float) if (ibuf->rect_float)
cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings); cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
@@ -1173,11 +1175,12 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
if (bin_b[x] > nb) nb = bin_b[x]; if (bin_b[x] > nb) nb = bin_b[x];
if (bin_a[x] > na) na = bin_a[x]; if (bin_a[x] > na) na = bin_a[x];
} }
divl = 1.0 / (double)nl; divl = nl ? 1.0 / (double)nl : 1.0;
diva = 1.0 / (double)na; diva = na ? 1.0 / (double)na : 1.0;
divr = 1.0 / (double)nr; divr = nr ? 1.0 / (double)nr : 1.0;
divg = 1.0 / (double)ng; divg = ng ? 1.0 / (double)ng : 1.0;
divb = 1.0 / (double)nb; divb = nb ? 1.0 / (double)nb : 1.0;
for (x = 0; x < 256; x++) { for (x = 0; x < 256; x++) {
scopes->hist.data_luma[x] = bin_lum[x] * divl; scopes->hist.data_luma[x] = bin_lum[x] * divl;
scopes->hist.data_r[x] = bin_r[x] * divr; scopes->hist.data_r[x] = bin_r[x] * divr;
@@ -1193,7 +1196,9 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
if (cm_processor) if (cm_processor)
IMB_colormanagement_processor_free(cm_processor); IMB_colormanagement_processor_free(cm_processor);
if (cache_handle)
IMB_display_buffer_release(cache_handle);
scopes->ok = 1; scopes->ok = 1;
} }

View File

@@ -1204,8 +1204,8 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
vec_to_quat(quat, dir, (short)data->trackflag, (short)data->upflag); vec_to_quat(quat, dir, (short)data->trackflag, (short)data->upflag);
normalize_v3(dir); normalize_v3(dir);
q[0] = (float)cos(0.5 * vec[3]); q[0] = cosf(0.5 * vec[3]);
x1 = (float)sin(0.5 * vec[3]); x1 = sinf(0.5 * vec[3]);
q[1] = -x1 * dir[0]; q[1] = -x1 * dir[0];
q[2] = -x1 * dir[1]; q[2] = -x1 * dir[1];
q[3] = -x1 * dir[2]; q[3] = -x1 * dir[2];

View File

@@ -95,7 +95,9 @@ void BKE_group_unlink(Group *group)
/* ensure objects are not in this group */ /* ensure objects are not in this group */
for (; base; base = base->next) { for (; base; base = base->next) {
if (rem_from_group(group, base->object, sce, base) && find_group(base->object, NULL) == NULL) { if (BKE_group_object_unlink(group, base->object, sce, base) &&
BKE_group_object_find(NULL, base->object) == NULL)
{
base->object->flag &= ~OB_FROMGROUP; base->object->flag &= ~OB_FROMGROUP;
base->flag &= ~OB_FROMGROUP; base->flag &= ~OB_FROMGROUP;
} }
@@ -132,7 +134,7 @@ void BKE_group_unlink(Group *group)
group->id.us = 0; group->id.us = 0;
} }
Group *add_group(Main *bmain, const char *name) Group *BKE_group_add(Main *bmain, const char *name)
{ {
Group *group; Group *group;
@@ -152,7 +154,7 @@ Group *BKE_group_copy(Group *group)
} }
/* external */ /* external */
static int add_to_group_internal(Group *group, Object *ob) static int group_object_add_internal(Group *group, Object *ob)
{ {
GroupObject *go; GroupObject *go;
@@ -173,9 +175,9 @@ static int add_to_group_internal(Group *group, Object *ob)
return TRUE; return TRUE;
} }
int add_to_group(Group *group, Object *object, Scene *scene, Base *base) bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base)
{ {
if (add_to_group_internal(group, object)) { if (group_object_add_internal(group, object)) {
if ((object->flag & OB_FROMGROUP) == 0) { if ((object->flag & OB_FROMGROUP) == 0) {
if (scene && base == NULL) if (scene && base == NULL)
@@ -186,15 +188,15 @@ int add_to_group(Group *group, Object *object, Scene *scene, Base *base)
if (base) if (base)
base->flag |= OB_FROMGROUP; base->flag |= OB_FROMGROUP;
} }
return 1; return true;
} }
else { else {
return 0; return false;
} }
} }
/* also used for (ob == NULL) */ /* also used for (ob == NULL) */
static int rem_from_group_internal(Group *group, Object *ob) static int group_object_unlink_internal(Group *group, Object *ob)
{ {
GroupObject *go, *gon; GroupObject *go, *gon;
int removed = 0; int removed = 0;
@@ -214,11 +216,11 @@ static int rem_from_group_internal(Group *group, Object *ob)
return removed; return removed;
} }
int rem_from_group(Group *group, Object *object, Scene *scene, Base *base) bool BKE_group_object_unlink(Group *group, Object *object, Scene *scene, Base *base)
{ {
if (rem_from_group_internal(group, object)) { if (group_object_unlink_internal(group, object)) {
/* object can be NULL */ /* object can be NULL */
if (object && find_group(object, NULL) == NULL) { if (object && BKE_group_object_find(NULL, object) == NULL) {
if (scene && base == NULL) if (scene && base == NULL)
base = BKE_scene_base_find(scene, object); base = BKE_scene_base_find(scene, object);
@@ -227,23 +229,24 @@ int rem_from_group(Group *group, Object *object, Scene *scene, Base *base)
if (base) if (base)
base->flag &= ~OB_FROMGROUP; base->flag &= ~OB_FROMGROUP;
} }
return 1; return true;
} }
else { else {
return 0; return false;
} }
} }
int object_in_group(Object *ob, Group *group) bool BKE_group_object_exists(Group *group, Object *ob)
{ {
if (group == NULL || ob == NULL) { if (group == NULL || ob == NULL) {
return FALSE; return false;
}
else {
return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
} }
return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
} }
Group *find_group(Object *ob, Group *group) Group *BKE_group_object_find(Group *group, Object *ob)
{ {
if (group) if (group)
group = group->id.next; group = group->id.next;
@@ -251,14 +254,14 @@ Group *find_group(Object *ob, Group *group)
group = G.main->group.first; group = G.main->group.first;
while (group) { while (group) {
if (object_in_group(ob, group)) if (BKE_group_object_exists(group, ob))
return group; return group;
group = group->id.next; group = group->id.next;
} }
return NULL; return NULL;
} }
void group_tag_recalc(Group *group) void BKE_group_tag_recalc(Group *group)
{ {
GroupObject *go; GroupObject *go;
@@ -270,7 +273,7 @@ void group_tag_recalc(Group *group)
} }
} }
int group_is_animated(Object *UNUSED(parent), Group *group) bool BKE_group_is_animated(Group *group, Object *UNUSED(parent))
{ {
GroupObject *go; GroupObject *go;
@@ -281,9 +284,9 @@ int group_is_animated(Object *UNUSED(parent), Group *group)
for (go = group->gobject.first; go; go = go->next) for (go = group->gobject.first; go; go = go->next)
if (go->ob && go->ob->proxy) if (go->ob && go->ob->proxy)
return 1; return true;
return 0; return false;
} }
#if 0 // add back when timeoffset & animsys work again #if 0 // add back when timeoffset & animsys work again
@@ -332,7 +335,7 @@ static void group_replaces_nla(Object *parent, Object *target, char mode)
* you can draw everything, leaves tags in objects to signal it needs further updating */ * you can draw everything, leaves tags in objects to signal it needs further updating */
/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */ /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
void group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Group *group) void BKE_group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Group *group)
{ {
GroupObject *go; GroupObject *go;

View File

@@ -1065,6 +1065,7 @@ ID *BKE_libblock_find_name(const short type, const char *name) /* type: "OB
return BLI_findstring(lb, name, offsetof(ID, name) + 2); return BLI_findstring(lb, name, offsetof(ID, name) + 2);
} }
#if 0 /* UNUSED */
static void get_flags_for_id(ID *id, char *buf) static void get_flags_for_id(ID *id, char *buf)
{ {
int isfake = id->flag & LIB_FAKEUSER; int isfake = id->flag & LIB_FAKEUSER;
@@ -1145,7 +1146,6 @@ static void IDnames_to_dyn_pupstring(DynStr *pupds, ListBase *lb, ID *link, shor
} }
} }
/* used by headerbuttons.c buttons.c editobject.c editseq.c */ /* used by headerbuttons.c buttons.c editobject.c editseq.c */
/* if (nr == NULL) no MAX_IDPUP, this for non-header browsing */ /* if (nr == NULL) no MAX_IDPUP, this for non-header browsing */
void IDnames_to_pupstring(const char **str, const char *title, const char *extraops, ListBase *lb, ID *link, short *nr) void IDnames_to_pupstring(const char **str, const char *title, const char *extraops, ListBase *lb, ID *link, short *nr)
@@ -1170,7 +1170,6 @@ void IDnames_to_pupstring(const char **str, const char *title, const char *extra
} }
/* skips viewer images */ /* skips viewer images */
#if 0 /* unused */
void IMAnames_to_pupstring(const char **str, const char *title, const char *extraops, ListBase *lb, ID *link, short *nr) void IMAnames_to_pupstring(const char **str, const char *title, const char *extraops, ListBase *lb, ID *link, short *nr)
{ {
DynStr *pupds = BLI_dynstr_new(); DynStr *pupds = BLI_dynstr_new();

View File

@@ -1426,7 +1426,8 @@ static void converge(const float p1[3], const float p2[3], float v1, float v2,
while (1) { while (1) {
if (i++ == RES) return; if (i++ == RES) return;
p[0] = 0.5f * (pos[0] + neg[0]); p[0] = 0.5f * (pos[0] + neg[0]);
if ((function(p[0], p[1], p[2])) > 0.0f) pos[0] = p[0]; else neg[0] = p[0]; if ((function(p[0], p[1], p[2])) > 0.0f) pos[0] = p[0];
else neg[0] = p[0];
} }
} }
@@ -1436,7 +1437,8 @@ static void converge(const float p1[3], const float p2[3], float v1, float v2,
while (1) { while (1) {
if (i++ == RES) return; if (i++ == RES) return;
p[1] = 0.5f * (pos[1] + neg[1]); p[1] = 0.5f * (pos[1] + neg[1]);
if ((function(p[0], p[1], p[2])) > 0.0f) pos[1] = p[1]; else neg[1] = p[1]; if ((function(p[0], p[1], p[2])) > 0.0f) pos[1] = p[1];
else neg[1] = p[1];
} }
} }
@@ -1446,7 +1448,8 @@ static void converge(const float p1[3], const float p2[3], float v1, float v2,
while (1) { while (1) {
if (i++ == RES) return; if (i++ == RES) return;
p[2] = 0.5f * (pos[2] + neg[2]); p[2] = 0.5f * (pos[2] + neg[2]);
if ((function(p[0], p[1], p[2])) > 0.0f) pos[2] = p[2]; else neg[2] = p[2]; if ((function(p[0], p[1], p[2])) > 0.0f) pos[2] = p[2];
else neg[2] = p[2];
} }
} }

View File

@@ -1162,13 +1162,17 @@ static void free_buffers(MovieClip *clip)
BKE_free_animdata((ID *) clip); BKE_free_animdata((ID *) clip);
} }
void BKE_movieclip_clear_cache(MovieClip *clip)
{
free_buffers(clip);
}
void BKE_movieclip_reload(MovieClip *clip) void BKE_movieclip_reload(MovieClip *clip)
{ {
/* clear cache */ /* clear cache */
free_buffers(clip); free_buffers(clip);
clip->tracking.stabilization.ok = FALSE; clip->tracking.stabilization.ok = FALSE;
clip->prefetch_ok = FALSE;
/* update clip source */ /* update clip source */
detect_clip_source(clip); detect_clip_source(clip);

View File

@@ -190,7 +190,10 @@ static void node_socket_set_typeinfo(bNodeTree *ntree, bNodeSocket *sock, bNodeS
{ {
if (typeinfo) { if (typeinfo) {
sock->typeinfo = typeinfo; sock->typeinfo = typeinfo;
/* deprecated integer type */
sock->type = typeinfo->type;
if (sock->default_value == NULL) { if (sock->default_value == NULL) {
/* initialize the default_value pointer used by standard socket types */ /* initialize the default_value pointer used by standard socket types */
node_socket_init_default_value(sock); node_socket_init_default_value(sock);
@@ -435,28 +438,6 @@ GHashIterator *nodeSocketTypeGetIterator(void)
return BLI_ghashIterator_new(nodesockettypes_hash); return BLI_ghashIterator_new(nodesockettypes_hash);
} }
void nodeMakeDynamicType(bNode *UNUSED(node))
{
#if 0 /* XXX deprecated */
/* find SH_DYNAMIC_NODE ntype */
bNodeType *ntype = ntreeType_Shader->node_types.first;
while (ntype) {
if (ntype->type == NODE_DYNAMIC)
break;
ntype = ntype->next;
}
/* make own type struct to fill */
if (ntype) {
/*node->typeinfo= MEM_dupallocN(ntype);*/
bNodeType *newtype = MEM_callocN(sizeof(bNodeType), "dynamic bNodeType");
*newtype = *ntype;
BLI_strncpy(newtype->name, ntype->name, sizeof(newtype->name));
node->typeinfo = newtype;
}
#endif
}
struct bNodeSocket *nodeFindSocket(bNode *node, int in_out, const char *identifier) struct bNodeSocket *nodeFindSocket(bNode *node, int in_out, const char *identifier)
{ {
bNodeSocket *sock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first); bNodeSocket *sock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first);
@@ -3438,6 +3419,7 @@ static void registerShaderNodes(void)
register_node_type_sh_holdout(); register_node_type_sh_holdout();
//register_node_type_sh_volume_transparent(); //register_node_type_sh_volume_transparent();
//register_node_type_sh_volume_isotropic(); //register_node_type_sh_volume_isotropic();
register_node_type_sh_subsurface_scattering();
register_node_type_sh_mix_shader(); register_node_type_sh_mix_shader();
register_node_type_sh_add_shader(); register_node_type_sh_add_shader();

View File

@@ -771,7 +771,7 @@ void BKE_object_unlink(Object *ob)
/* groups */ /* groups */
group = bmain->group.first; group = bmain->group.first;
while (group) { while (group) {
rem_from_group(group, ob, NULL, NULL); BKE_group_object_unlink(group, ob, NULL, NULL);
group = group->id.next; group = group->id.next;
} }
@@ -1848,8 +1848,8 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
/* the tilt */ /* the tilt */
normalize_v3(dir); normalize_v3(dir);
q[0] = (float)cos(0.5 * vec[3]); q[0] = cosf(0.5 * vec[3]);
si = (float)sin(0.5 * vec[3]); si = sinf(0.5 * vec[3]);
q[1] = -si * dir[0]; q[1] = -si * dir[0];
q[2] = -si * dir[1]; q[2] = -si * dir[1];
q[3] = -si * dir[2]; q[3] = -si * dir[2];
@@ -3403,7 +3403,7 @@ struct LinkNode *BKE_object_groups(Object *ob)
{ {
LinkNode *group_linknode = NULL; LinkNode *group_linknode = NULL;
Group *group = NULL; Group *group = NULL;
while ((group = find_group(ob, group))) { while ((group = BKE_group_object_find(group, ob))) {
BLI_linklist_prepend(&group_linknode, group); BLI_linklist_prepend(&group_linknode, group);
} }
@@ -3420,7 +3420,7 @@ void BKE_object_groups_clear(Scene *scene, Base *base, Object *object)
base = BKE_scene_base_find(scene, object); base = BKE_scene_base_find(scene, object);
} }
while ((group = find_group(base->object, group))) { while ((group = BKE_group_object_find(group, base->object))) {
rem_from_group(group, object, scene, base); BKE_group_object_unlink(group, object, scene, base);
} }
} }

View File

@@ -314,7 +314,7 @@ void psys_check_group_weights(ParticleSettings *part)
/* first remove all weights that don't have an object in the group */ /* first remove all weights that don't have an object in the group */
dw = part->dupliweights.first; dw = part->dupliweights.first;
while (dw) { while (dw) {
if (!object_in_group(dw->ob, part->dup_group)) { if (!BKE_group_object_exists(part->dup_group, dw->ob)) {
tdw = dw->next; tdw = dw->next;
BLI_freelinkN(&part->dupliweights, dw); BLI_freelinkN(&part->dupliweights, dw);
dw = tdw; dw = tdw;

View File

@@ -1093,7 +1093,7 @@ static void scene_depsgraph_hack(Scene *scene, Scene *scene_parent)
if (go->ob) if (go->ob)
go->ob->recalc |= recalc; go->ob->recalc |= recalc;
} }
group_handle_recalc_and_update(scene_parent, ob, ob->dup_group); BKE_group_handle_recalc_and_update(scene_parent, ob, ob->dup_group);
} }
} }
} }
@@ -1136,7 +1136,7 @@ static void scene_update_tagged_recursive(Main *bmain, Scene *scene, Scene *scen
BKE_object_handle_update_ex(scene_parent, ob, scene->rigidbody_world); BKE_object_handle_update_ex(scene_parent, ob, scene->rigidbody_world);
if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP)) if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP))
group_handle_recalc_and_update(scene_parent, ob, ob->dup_group); BKE_group_handle_recalc_and_update(scene_parent, ob, ob->dup_group);
/* always update layer, so that animating layers works (joshua july 2010) */ /* always update layer, so that animating layers works (joshua july 2010) */
/* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes /* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes

View File

@@ -88,10 +88,11 @@ static uint8_t *video_buffer = 0;
static int video_buffersize = 0; static int video_buffersize = 0;
static uint8_t *audio_input_buffer = 0; static uint8_t *audio_input_buffer = 0;
static uint8_t *audio_deinterleave_buffer = 0;
static int audio_input_samples = 0; static int audio_input_samples = 0;
static uint8_t *audio_output_buffer = 0;
static int audio_outbuf_size = 0;
static double audio_time = 0.0f; static double audio_time = 0.0f;
static bool audio_deinterleave = false;
static int audio_sample_size = 0;
#ifdef WITH_AUDASPACE #ifdef WITH_AUDASPACE
static AUD_Device *audio_mixdown_device = 0; static AUD_Device *audio_mixdown_device = 0;
@@ -122,37 +123,69 @@ static int write_audio_frame(void)
{ {
AVCodecContext *c = NULL; AVCodecContext *c = NULL;
AVPacket pkt; AVPacket pkt;
AVFrame *frame;
int got_output = 0;
c = audio_stream->codec; c = audio_stream->codec;
av_init_packet(&pkt); av_init_packet(&pkt);
pkt.size = 0; pkt.size = 0;
pkt.data = NULL;
frame = avcodec_alloc_frame();
frame->nb_samples = audio_input_samples;
frame->format = c->sample_fmt;
#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
frame->channel_layout = c->channel_layout;
#endif
AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples); AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples);
audio_time += (double) audio_input_samples / (double) c->sample_rate; audio_time += (double) audio_input_samples / (double) c->sample_rate;
pkt.size = avcodec_encode_audio(c, audio_output_buffer, audio_outbuf_size, (short *) audio_input_buffer); if (audio_deinterleave) {
int channel, i;
uint8_t *temp;
if (pkt.size < 0) { for (channel = 0; channel < c->channels; channel++) {
for (i = 0; i < frame->nb_samples; i++) {
memcpy(audio_deinterleave_buffer + (i + channel * frame->nb_samples) * audio_sample_size,
audio_input_buffer + (c->channels * i + channel) * audio_sample_size, audio_sample_size);
}
}
temp = audio_deinterleave_buffer;
audio_deinterleave_buffer = audio_input_buffer;
audio_input_buffer = temp;
}
avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, audio_input_buffer,
audio_input_samples * c->channels * audio_sample_size, 0);
if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) {
// XXX error("Error writing audio packet"); // XXX error("Error writing audio packet");
return -1; return -1;
} }
pkt.data = audio_output_buffer; if (got_output) {
if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE) {
pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, audio_stream->time_base);
PRINT("Audio Frame PTS: %d\n", (int) pkt.pts);
}
if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE) { pkt.stream_index = audio_stream->index;
pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, audio_stream->time_base);
PRINT("Audio Frame PTS: %d\n", (int) pkt.pts); pkt.flags |= AV_PKT_FLAG_KEY;
if (av_interleaved_write_frame(outfile, &pkt) != 0) {
fprintf(stderr, "Error writing audio packet!\n");
return -1;
}
av_free_packet(&pkt);
} }
pkt.stream_index = audio_stream->index; avcodec_free_frame(&frame);
pkt.flags |= AV_PKT_FLAG_KEY;
if (av_interleaved_write_frame(outfile, &pkt) != 0) {
fprintf(stderr, "Error writing audio packet!\n");
return -1;
}
return 0; return 0;
} }
#endif // #ifdef WITH_AUDASPACE #endif // #ifdef WITH_AUDASPACE
@@ -608,8 +641,6 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
return st; return st;
} }
/* Prepare an audio stream for the output file */
static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size) static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
{ {
AVStream *st; AVStream *st;
@@ -659,11 +690,6 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
} }
} }
if (c->sample_fmt == AV_SAMPLE_FMT_FLTP) {
BLI_strncpy(error, "Requested audio codec requires planar float sample format, which is not supported yet", error_size);
return NULL;
}
if (codec->supported_samplerates) { if (codec->supported_samplerates) {
const int *p = codec->supported_samplerates; const int *p = codec->supported_samplerates;
int best = 0; int best = 0;
@@ -692,24 +718,23 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
st->codec->time_base.num = 1; st->codec->time_base.num = 1;
st->codec->time_base.den = st->codec->sample_rate; st->codec->time_base.den = st->codec->sample_rate;
audio_outbuf_size = FF_MIN_BUFFER_SIZE; if (c->frame_size == 0)
// used to be if((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD)) // not sure if that is needed anymore, so let's try out if there are any
audio_input_samples = audio_outbuf_size * 8 / c->bits_per_coded_sample / c->channels; // complaints regarding some ffmpeg versions users might have
audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
else { else {
audio_input_samples = c->frame_size; audio_input_samples = c->frame_size;
if (c->frame_size * c->channels * sizeof(int16_t) * 4 > audio_outbuf_size)
audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
} }
audio_output_buffer = (uint8_t *) av_malloc(audio_outbuf_size); audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
if (c->sample_fmt == AV_SAMPLE_FMT_FLT) { audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * sizeof(float));
} audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
else {
audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * sizeof(int16_t)); if (audio_deinterleave)
} audio_deinterleave_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
audio_time = 0.0f; audio_time = 0.0f;
@@ -1010,12 +1035,27 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
AVCodecContext *c = audio_stream->codec; AVCodecContext *c = audio_stream->codec;
AUD_DeviceSpecs specs; AUD_DeviceSpecs specs;
specs.channels = c->channels; specs.channels = c->channels;
if (c->sample_fmt == AV_SAMPLE_FMT_FLT) {
specs.format = AUD_FORMAT_FLOAT32; switch (av_get_packed_sample_fmt(c->sample_fmt)) {
} case AV_SAMPLE_FMT_U8:
else { specs.format = AUD_FORMAT_U8;
break;
case AV_SAMPLE_FMT_S16:
specs.format = AUD_FORMAT_S16; specs.format = AUD_FORMAT_S16;
break;
case AV_SAMPLE_FMT_S32:
specs.format = AUD_FORMAT_S32;
break;
case AV_SAMPLE_FMT_FLT:
specs.format = AUD_FORMAT_FLOAT32;
break;
case AV_SAMPLE_FMT_DBL:
specs.format = AUD_FORMAT_FLOAT64;
break;
default:
return -31415;
} }
specs.rate = rd->ffcodecdata.audio_mixrate; specs.rate = rd->ffcodecdata.audio_mixrate;
audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume); audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume);
#ifdef FFMPEG_CODEC_TIME_BASE #ifdef FFMPEG_CODEC_TIME_BASE
@@ -1138,15 +1178,16 @@ static void end_ffmpeg_impl(int is_autosplit)
MEM_freeN(video_buffer); MEM_freeN(video_buffer);
video_buffer = 0; video_buffer = 0;
} }
if (audio_output_buffer) {
av_free(audio_output_buffer);
audio_output_buffer = 0;
}
if (audio_input_buffer) { if (audio_input_buffer) {
av_free(audio_input_buffer); av_free(audio_input_buffer);
audio_input_buffer = 0; audio_input_buffer = 0;
} }
if (audio_deinterleave_buffer) {
av_free(audio_deinterleave_buffer);
audio_deinterleave_buffer = 0;
}
if (img_convert_ctx) { if (img_convert_ctx) {
sws_freeContext(img_convert_ctx); sws_freeContext(img_convert_ctx);
img_convert_ctx = 0; img_convert_ctx = 0;

View File

@@ -244,6 +244,8 @@ void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]);
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist); void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist);
void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist); void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
void axis_sort_v3(const float axis_values[3], int r_axis_order[3]);
/***************************** Array Functions *******************************/ /***************************** Array Functions *******************************/
/* attempted to follow fixed length vertex functions. names could be improved*/ /* attempted to follow fixed length vertex functions. names could be improved*/
double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size); double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size);

View File

@@ -539,9 +539,9 @@ void QuatInterpolW(float *result, float quat1[4], float quat2[4], float t)
if ((1.0f - cosom) > 0.0001f) { if ((1.0f - cosom) > 0.0001f) {
omega = (float)acos(cosom); omega = (float)acos(cosom);
sinom = (float)sin(omega); sinom = sinf(omega);
sc1 = (float)sin((1.0 - t) * omega) / sinom; sc1 = sinf((1.0 - t) * omega) / sinom;
sc2 = (float)sin(t * omega) / sinom; sc2 = sinf(t * omega) / sinom;
} }
else { else {
sc1 = 1.0f - t; sc1 = 1.0f - t;
@@ -558,8 +558,8 @@ void QuatInterpolW(float *result, float quat1[4], float quat2[4], float t)
result[2] = quat2[1]; result[2] = quat2[1];
result[3] = -quat2[0]; result[3] = -quat2[0];
sc1 = (float)sin((1.0 - t) * M_PI_2); sc1 = sinf((1.0 - t) * M_PI_2);
sc2 = (float)sin(t * M_PI_2); sc2 = sinf(t * M_PI_2);
result[0] = sc1 * quat1[0] + sc2 * result[0]; result[0] = sc1 * quat1[0] + sc2 * result[0];
result[1] = sc1 * quat1[1] + sc2 * result[1]; result[1] = sc1 * quat1[1] + sc2 * result[1];

View File

@@ -527,6 +527,28 @@ void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist)
} }
} }
void axis_sort_v3(const float axis_values[3], int r_axis_order[3])
{
float v[3];
copy_v3_v3(v, axis_values);
#define SWAP_AXIS(a, b) { \
SWAP(float, v[a], v[b]); \
SWAP(int, r_axis_order[a], r_axis_order[b]); \
} (void)0
if (v[0] < v[1]) {
if (v[2] < v[0]) { SWAP_AXIS(0, 2); }
}
else {
if (v[1] < v[2]) { SWAP_AXIS(0, 1); }
else { SWAP_AXIS(0, 2); }
}
if (v[2] < v[1]) { SWAP_AXIS(1, 2); }
#undef SWAP_AXIS
}
/***************************** Array Functions *******************************/ /***************************** Array Functions *******************************/
double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size) double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size)

Some files were not shown because too many files have changed in this diff Show More