svn merge ^/trunk/blender -r55700:55776
This commit is contained in:
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
154
intern/cycles/kernel/closure/bssrdf.h
Normal file
154
intern/cycles/kernel/closure/bssrdf.h
Normal 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__ */
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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,11 +325,9 @@ __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
|
||||||
|
|
||||||
#ifdef __EMISSION__
|
#ifdef __EMISSION__
|
||||||
@@ -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,11 +951,9 @@ __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
|
||||||
|
|
||||||
#ifdef __EMISSION__
|
#ifdef __EMISSION__
|
||||||
@@ -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;
|
|
||||||
float num_samples_inv = 1.0f/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 = 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++) {
|
for(int i = 0; i< sd.num_closure; i++) {
|
||||||
const ShaderClosure *sc = &sd.closure[i];
|
ShaderClosure *sc = &sd.closure[i];
|
||||||
|
|
||||||
if(!CLOSURE_IS_BSDF(sc->type))
|
if(!CLOSURE_IS_BSSRDF(sc->type))
|
||||||
continue;
|
|
||||||
/* transparency is not handled here, but in outer loop */
|
|
||||||
if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int num_samples;
|
/* set up random number generator */
|
||||||
|
uint lcg_state = lcg_init(rbsdf);
|
||||||
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
|
int num_samples = kernel_data.integrator.subsurface_samples;
|
||||||
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;
|
float num_samples_inv = 1.0f/num_samples;
|
||||||
|
|
||||||
|
/* do subsurface scatter step with copy of shader data, this will
|
||||||
|
* replace the BSSRDF with a diffuse BSDF closure */
|
||||||
for(int j = 0; j < num_samples; j++) {
|
for(int j = 0; j < num_samples; j++) {
|
||||||
/* sample BSDF */
|
ShaderData bssrdf_sd = sd;
|
||||||
float bsdf_pdf;
|
subsurface_scatter_step(kg, &bssrdf_sd, state.flag, sc, &lcg_state, true);
|
||||||
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,
|
/* compute lighting with the BSDF closure */
|
||||||
&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
|
kernel_path_non_progressive_lighting(kg, rng, sample*num_samples + j,
|
||||||
|
&bssrdf_sd, throughput, num_samples_inv,
|
||||||
if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
|
ray_pdf, ray_pdf, state, rng_offset, &L, buffer);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
241
intern/cycles/kernel/kernel_subsurface.h
Normal file
241
intern/cycles/kernel/kernel_subsurface.h
Normal 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
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
90
intern/cycles/kernel/osl/osl_bssrdf.cpp
Normal file
90
intern/cycles/kernel/osl/osl_bssrdf.cpp
Normal 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
|
||||||
|
|
||||||
65
intern/cycles/kernel/osl/osl_bssrdf.h
Normal file
65
intern/cycles/kernel/osl/osl_bssrdf.h
Normal 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__ */
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
33
intern/cycles/kernel/shaders/node_subsurface_scattering.osl
Normal file
33
intern/cycles/kernel/shaders/node_subsurface_scattering.osl
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
141
intern/cycles/render/bssrdf.cpp
Normal file
141
intern/cycles/render/bssrdf.cpp
Normal 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
|
||||||
|
|
||||||
31
intern/cycles/render/bssrdf.h
Normal file
31
intern/cycles/render/bssrdf.h
Normal 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__ */
|
||||||
|
|
||||||
@@ -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,11 +259,13 @@ 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;
|
||||||
|
|
||||||
/* update __data */
|
/* update __data */
|
||||||
@@ -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_)
|
||||||
|
|||||||
@@ -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_);
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -1262,15 +1262,18 @@ 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);
|
||||||
|
|
||||||
|
if(scattering)
|
||||||
|
add_output("BSSRDF", SHADER_SOCKET_CLOSURE);
|
||||||
|
else
|
||||||
add_output("BSDF", SHADER_SOCKET_CLOSURE);
|
add_output("BSDF", SHADER_SOCKET_CLOSURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
110
intern/cycles/render/tables.cpp
Normal file
110
intern/cycles/render/tables.cpp
Normal 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
|
||||||
|
|
||||||
@@ -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__ */
|
||||||
|
|
||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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"
|
||||||
|
" if (predivide == false || col[3] == 1.0f || col[3] == 0.0f) {\n"
|
||||||
" gl_FragColor = OCIODisplay(col, tex2);\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,14 +250,18 @@ 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->fragShader) {
|
||||||
if (state->program)
|
if (state->program)
|
||||||
glDeleteProgram(state->program);
|
glDeleteProgram(state->program);
|
||||||
|
|
||||||
state->program = linkShaders(state->fragShader);
|
state->program = linkShaders(state->fragShader);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->program) {
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
|
glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
|
||||||
|
|
||||||
@@ -248,6 +270,16 @@ void OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
|
|||||||
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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -43,16 +43,15 @@ 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__ */
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,8 +1091,9 @@ 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,6 +1196,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -191,6 +191,9 @@ 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();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,24 +123,50 @@ 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) {
|
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);
|
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);
|
PRINT("Audio Frame PTS: %d\n", (int) pkt.pts);
|
||||||
@@ -153,6 +180,12 @@ static int write_audio_frame(void)
|
|||||||
fprintf(stderr, "Error writing audio packet!\n");
|
fprintf(stderr, "Error writing audio packet!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
av_free_packet(&pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_free_frame(&frame);
|
||||||
|
|
||||||
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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user