Merge branch 'master' into blender2.8

This commit is contained in:
Brecht Van Lommel 2018-03-10 06:55:39 +01:00
commit d27158aae9
71 changed files with 1522 additions and 1102 deletions

View File

@ -40,6 +40,7 @@
#include "util/util_foreach.h"
#include "util/util_path.h"
#include "util/util_projection.h"
#include "util/util_transform.h"
#include "util/util_xml.h"
@ -546,8 +547,10 @@ static void xml_read_transform(xml_node node, Transform& tfm)
{
if(node.attribute("matrix")) {
vector<float> matrix;
if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16)
tfm = tfm * transform_transpose((*(Transform*)&matrix[0]));
if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16) {
ProjectionTransform projection = *(ProjectionTransform*)&matrix[0];
tfm = tfm * projection_to_transform(projection_transpose(projection));
}
}
if(node.attribute("translate")) {

View File

@ -1082,7 +1082,7 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
cls.motion_steps = IntProperty(
name="Motion Steps",
description="Control accuracy of deformation motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
description="Control accuracy of motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
min=1, soft_max=8,
default=1,
)

View File

@ -783,7 +783,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
def poll(cls, context):
ob = context.object
if CyclesButtonsPanel.poll(context) and ob:
if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META'}:
if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA'}:
return True
if ob.dupli_type == 'GROUP' and ob.dupli_group:
return True
@ -815,11 +815,9 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
layout.active = (rd.use_motion_blur and cob.use_motion_blur)
row = layout.row()
row.prop(cob, "use_deform_motion", text="Deformation")
sub = row.row()
sub.active = cob.use_deform_motion
sub.prop(cob, "motion_steps", text="Steps")
if ob.type != 'CAMERA':
row.prop(cob, "use_deform_motion", text="Deformation")
row.prop(cob, "motion_steps", text="Steps")
class CYCLES_OBJECT_PT_cycles_settings(CyclesButtonsPanel, Panel):

View File

@ -83,6 +83,8 @@ struct BlenderCamera {
Transform matrix;
float offscreen_dicing_scale;
int motion_steps;
};
static void blender_camera_init(BlenderCamera *bcam,
@ -226,6 +228,8 @@ static void blender_camera_from_object(BlenderCamera *bcam,
bcam->sensor_fit = BlenderCamera::HORIZONTAL;
else
bcam->sensor_fit = BlenderCamera::VERTICAL;
bcam->motion_steps = object_motion_steps(b_ob, b_ob);
}
else {
/* from lamp not implemented yet */
@ -246,8 +250,7 @@ static Transform blender_camera_matrix(const Transform& tfm,
result = tfm *
make_transform(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
0.0f, 1.0f, 0.0f, 0.0f);
}
else {
/* Make it so environment camera needs to be pointed in the direction
@ -257,8 +260,7 @@ static Transform blender_camera_matrix(const Transform& tfm,
result = tfm *
make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
-1.0f, 0.0f, 0.0f, 0.0f);
}
}
else {
@ -455,9 +457,7 @@ static void blender_camera_sync(Camera *cam,
cam->matrix = blender_camera_matrix(bcam->matrix,
bcam->type,
bcam->panorama_type);
cam->motion.pre = cam->matrix;
cam->motion.post = cam->matrix;
cam->use_motion = false;
cam->motion.resize(bcam->motion_steps, cam->matrix);
cam->use_perspective_motion = false;
cam->shuttertime = bcam->shuttertime;
cam->fov_pre = cam->fov;
@ -566,20 +566,15 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render,
Transform tfm = get_transform(b_ob_matrix);
tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type);
if(tfm != cam->matrix) {
VLOG(1) << "Camera " << b_ob.name() << " motion detected.";
if(motion_time == 0.0f) {
/* When motion blur is not centered in frame, cam->matrix gets reset. */
cam->matrix = tfm;
}
else if(motion_time == -1.0f) {
cam->motion.pre = tfm;
cam->use_motion = true;
}
else if(motion_time == 1.0f) {
cam->motion.post = tfm;
cam->use_motion = true;
}
if(motion_time == 0.0f) {
/* When motion blur is not centered in frame, cam->matrix gets reset. */
cam->matrix = tfm;
}
/* Set transform in motion array. */
int motion_step = cam->motion_step(motion_time);
if(motion_step >= 0) {
cam->motion[motion_step] = tfm;
}
if(cam->type == CAMERA_PERSPECTIVE) {

View File

@ -633,10 +633,10 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa
}
}
static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int time_index)
static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int motion_step)
{
VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name
<< ", time index " << time_index;
<< ", motion step " << motion_step;
/* find attribute */
Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
@ -651,7 +651,7 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
/* export motion vectors for curve keys */
size_t numkeys = mesh->curve_keys.size();
float4 *mP = attr_mP->data_float4() + time_index*numkeys;
float4 *mP = attr_mP->data_float4() + motion_step*numkeys;
bool have_motion = false;
int i = 0;
@ -702,12 +702,12 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
}
mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
}
else if(time_index > 0) {
VLOG(1) << "Filling in new motion vertex position for time_index "
<< time_index;
else if(motion_step > 0) {
VLOG(1) << "Filling in new motion vertex position for motion_step "
<< motion_step;
/* motion, fill up previous steps that we might have skipped because
* they had no motion, but we need them anyway now */
for(int step = 0; step < time_index; step++) {
for(int step = 0; step < motion_step; step++) {
float4 *mP = attr_mP->data_float4() + step*numkeys;
for(int key = 0; key < numkeys; key++) {
@ -889,7 +889,7 @@ void BlenderSync::sync_curves(BL::Depsgraph& b_depsgraph,
BL::Mesh& b_mesh,
BL::Object& b_ob,
bool motion,
int time_index)
int motion_step)
{
if(!motion) {
/* Clear stored curve data */
@ -954,7 +954,7 @@ void BlenderSync::sync_curves(BL::Depsgraph& b_depsgraph,
}
else {
if(motion)
ExportCurveSegmentsMotion(mesh, &CData, time_index);
ExportCurveSegmentsMotion(mesh, &CData, motion_step);
else
ExportCurveSegments(scene, mesh, &CData);
}

View File

@ -1252,36 +1252,10 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
if(mesh_synced.find(mesh) == mesh_synced.end())
return;
/* for motion pass always compute, for motion blur it can be disabled */
int time_index = 0;
if(scene->need_motion() == Scene::MOTION_BLUR) {
if(!mesh->use_motion_blur)
return;
/* see if this mesh needs motion data at this time */
vector<float> object_times = object->motion_times();
bool found = false;
foreach(float object_time, object_times) {
if(motion_time == object_time) {
found = true;
break;
}
else
time_index++;
}
if(!found)
return;
}
else {
if(motion_time == -1.0f)
time_index = 0;
else if(motion_time == 1.0f)
time_index = 1;
else
return;
/* Find time matching motion step required by mesh. */
int motion_step = mesh->motion_step(motion_time);
if(motion_step < 0) {
return;
}
/* skip empty meshes */
@ -1324,9 +1298,9 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
float3 *P = &mesh->verts[0];
float3 *N = (attr_N)? attr_N->data_float3(): NULL;
memcpy(attr_mP->data_float3() + time_index*numverts, P, sizeof(float3)*numverts);
memcpy(attr_mP->data_float3() + motion_step*numverts, P, sizeof(float3)*numverts);
if(attr_mN)
memcpy(attr_mN->data_float3() + time_index*numverts, N, sizeof(float3)*numverts);
memcpy(attr_mN->data_float3() + motion_step*numverts, N, sizeof(float3)*numverts);
}
}
@ -1336,7 +1310,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
if(attr_mP) {
float3 *keys = &mesh->curve_keys[0];
memcpy(attr_mP->data_float3() + time_index*numkeys, keys, sizeof(float3)*numkeys);
memcpy(attr_mP->data_float3() + motion_step*numkeys, keys, sizeof(float3)*numkeys);
}
}
@ -1359,8 +1333,8 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
new_attribute = true;
}
/* Load vertex data from mesh. */
float3 *mP = attr_mP->data_float3() + time_index*numverts;
float3 *mN = (attr_mN)? attr_mN->data_float3() + time_index*numverts: NULL;
float3 *mP = attr_mP->data_float3() + motion_step*numverts;
float3 *mN = (attr_mN)? attr_mN->data_float3() + motion_step*numverts: NULL;
/* NOTE: We don't copy more that existing amount of vertices to prevent
* possible memory corruption.
*/
@ -1389,13 +1363,13 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
if(attr_mN)
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
}
else if(time_index > 0) {
else if(motion_step > 0) {
VLOG(1) << "Filling deformation motion for object " << b_ob.name();
/* motion, fill up previous steps that we might have skipped because
* they had no motion, but we need them anyway now */
float3 *P = &mesh->verts[0];
float3 *N = (attr_N)? attr_N->data_float3(): NULL;
for(int step = 0; step < time_index; step++) {
for(int step = 0; step < motion_step; step++) {
memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts);
if(attr_mN)
memcpy(attr_mN->data_float3() + step*numverts, N, sizeof(float3)*numverts);
@ -1405,7 +1379,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
else {
if(b_mesh.vertices.length() != numverts) {
VLOG(1) << "Topology differs, discarding motion blur for object "
<< b_ob.name() << " at time " << time_index;
<< b_ob.name() << " at time " << motion_step;
memcpy(mP, &mesh->verts[0], sizeof(float3)*numverts);
if(mN != NULL) {
memcpy(mN, attr_N->data_float3(), sizeof(float3)*numverts);
@ -1416,7 +1390,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
/* hair motion */
if(numkeys)
sync_curves(b_depsgraph, mesh, b_mesh, b_ob, true, time_index);
sync_curves(b_depsgraph, mesh, b_mesh, b_ob, true, motion_step);
/* free derived mesh */
b_data.meshes.remove(b_mesh, false, true, false);

View File

@ -347,22 +347,11 @@ Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph,
if(motion) {
object = object_map.find(key);
if(object && (scene->need_motion() == Scene::MOTION_PASS ||
object_use_motion(b_parent, b_ob)))
{
/* object transformation */
if(tfm != object->tfm) {
VLOG(1) << "Object " << b_ob.name() << " motion detected.";
if(motion_time == -1.0f || motion_time == 1.0f) {
object->use_motion = true;
}
}
if(motion_time == -1.0f) {
object->motion.pre = tfm;
}
else if(motion_time == 1.0f) {
object->motion.post = tfm;
if(object && object->use_motion()) {
/* Set transform at matching motion time step. */
int time_index = object->motion_step(motion_time);
if(time_index >= 0) {
object->motion[time_index] = tfm;
}
/* mesh deformation */
@ -409,25 +398,34 @@ Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph,
object->name = b_ob.name().c_str();
object->pass_id = b_ob.pass_index();
object->tfm = tfm;
object->motion.pre = transform_empty();
object->motion.post = transform_empty();
object->use_motion = false;
object->motion.clear();
/* motion blur */
if(scene->need_motion() == Scene::MOTION_BLUR && object->mesh) {
Scene::MotionType need_motion = scene->need_motion();
if(need_motion != Scene::MOTION_NONE && object->mesh) {
Mesh *mesh = object->mesh;
mesh->use_motion_blur = false;
mesh->motion_steps = 0;
if(object_use_motion(b_parent, b_ob)) {
uint motion_steps;
if(scene->need_motion() == Scene::MOTION_BLUR) {
motion_steps = object_motion_steps(b_parent, b_ob);
if(object_use_deform_motion(b_parent, b_ob)) {
mesh->motion_steps = object_motion_steps(b_ob);
mesh->motion_steps = motion_steps;
mesh->use_motion_blur = true;
}
}
else {
motion_steps = 3;
mesh->motion_steps = motion_steps;
}
vector<float> times = object->motion_times();
foreach(float time, times)
motion_times.insert(time);
object->motion.resize(motion_steps, transform_empty());
object->motion[motion_steps/2] = tfm;
for(size_t step = 0; step < motion_steps; step++) {
motion_times.insert(object->motion_time(step));
}
}
@ -646,6 +644,11 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
/* note iteration over motion_times set happens in sorted order */
foreach(float relative_time, motion_times) {
/* center time is already handled. */
if(relative_time == 0.0f) {
continue;
}
VLOG(1) << "Synchronizing motion for the relative time "
<< relative_time << ".";

View File

@ -96,7 +96,7 @@ bool BlenderObjectCulling::test(Scene *scene, BL::Object& b_ob, Transform& tfm)
bool BlenderObjectCulling::test_camera(Scene *scene, float3 bb[8])
{
Camera *cam = scene->camera;
Transform& worldtondc = cam->worldtondc;
const ProjectionTransform& worldtondc = cam->worldtondc;
float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
bool all_behind = true;

View File

@ -125,7 +125,7 @@ private:
BL::Mesh& b_mesh,
BL::Object& b_ob,
bool motion,
int time_index = 0);
int motion_step = 0);
Object *sync_object(BL::Depsgraph& b_depsgraph,
BL::Depsgraph::duplis_iterator& b_dupli_iter,
uint layer_flag,

View File

@ -248,14 +248,15 @@ static inline float *image_get_float_pixels_for_frame(BL::Image& image,
static inline Transform get_transform(const BL::Array<float, 16>& array)
{
Transform tfm;
ProjectionTransform projection;
/* we assume both types to be just 16 floats, and transpose because blender
* use column major matrix order while we use row major */
memcpy(&tfm, &array, sizeof(float)*16);
tfm = transform_transpose(tfm);
/* We assume both types to be just 16 floats, and transpose because blender
* use column major matrix order while we use row major. */
memcpy(&projection, &array, sizeof(float)*16);
projection = projection_transpose(projection);
return tfm;
/* Drop last row, matrix is assumed to be affine transform. */
return projection_to_transform(projection);
}
static inline float2 get_float2(const BL::Array<float, 2>& array)
@ -484,33 +485,34 @@ static inline void mesh_texture_space(BL::Mesh& b_mesh,
loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
}
/* object used for motion blur */
static inline bool object_use_motion(BL::Object& b_parent, BL::Object& b_ob)
/* Object motion steps, returns 0 if no motion blur needed. */
static inline uint object_motion_steps(BL::Object& b_parent, BL::Object& b_ob)
{
/* Get motion enabled and steps from object itself. */
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
bool use_motion = get_boolean(cobject, "use_motion_blur");
/* If motion blur is enabled for the object we also check
* whether it's enabled for the parent object as well.
*
* This way we can control motion blur from the dupligroup
* duplicator much easier.
*/
if(use_motion && b_parent.ptr.data != b_ob.ptr.data) {
if(!use_motion) {
return 0;
}
uint steps = max(1, get_int(cobject, "motion_steps"));
/* Also check parent object, so motion blur and steps can be
* controlled by dupligroup duplicator for linked groups. */
if(b_parent.ptr.data != b_ob.ptr.data) {
PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
use_motion &= get_boolean(parent_cobject, "use_motion_blur");
if(!use_motion) {
return 0;
}
steps = max(steps, get_int(parent_cobject, "motion_steps"));
}
return use_motion;
}
/* object motion steps */
static inline uint object_motion_steps(BL::Object& b_ob)
{
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
uint steps = get_int(cobject, "motion_steps");
/* use uneven number of steps so we get one keyframe at the current frame,
* and ue 2^(steps - 1) so objects with more/fewer steps still have samples
* at the same times, to avoid sampling at many different times */
/* Use uneven number of steps so we get one keyframe at the current frame,
* and use 2^(steps - 1) so objects with more/fewer steps still have samples
* at the same times, to avoid sampling at many different times. */
return (2 << (steps - 1)) + 1;
}

View File

@ -77,7 +77,7 @@ size_t SocketType::max_size()
void *SocketType::zero_default_value()
{
static Transform zero_transform = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
static Transform zero_transform = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
return &zero_transform;
}

View File

@ -196,7 +196,7 @@ void xml_read_node(XMLReader& reader, Node *node, xml_node xml_node)
case SocketType::TRANSFORM:
{
array<Transform> value;
xml_read_float_array<16>(value, attr);
xml_read_float_array<12>(value, attr);
if(value.size() == 1) {
node->set(socket, value[0]);
}
@ -205,7 +205,7 @@ void xml_read_node(XMLReader& reader, Node *node, xml_node xml_node)
case SocketType::TRANSFORM_ARRAY:
{
array<Transform> value;
xml_read_float_array<16>(value, attr);
xml_read_float_array<12>(value, attr);
node->set(socket, value);
break;
}
@ -400,12 +400,10 @@ xml_node xml_write_node(Node *node, xml_node xml_root)
{
Transform tfm = node->get_transform(socket);
std::stringstream ss;
for(int i = 0; i < 4; i++) {
ss << string_printf("%g %g %g %g", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
if(i != 3) {
ss << " ";
}
for(int i = 0; i < 3; i++) {
ss << string_printf("%g %g %g %g ", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
}
ss << string_printf("%g %g %g %g", 0.0, 0.0, 0.0, 1.0);
attr = ss.str().c_str();
break;
}
@ -416,11 +414,12 @@ xml_node xml_write_node(Node *node, xml_node xml_root)
for(size_t j = 0; j < value.size(); j++) {
const Transform& tfm = value[j];
for(int i = 0; i < 4; i++) {
ss << string_printf("%g %g %g %g", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
if(j != value.size() - 1 || i != 3) {
ss << " ";
}
for(int i = 0; i < 3; i++) {
ss << string_printf("%g %g %g %g ", (double)tfm[i][0], (double)tfm[i][1], (double)tfm[i][2], (double)tfm[i][3]);
}
ss << string_printf("%g %g %g %g", 0.0, 0.0, 0.0, 1.0);
if(j != value.size() - 1) {
ss << " ";
}
}
attr = ss.str().c_str();

View File

@ -254,6 +254,7 @@ set(SRC_UTIL_HEADERS
../util/util_math_int3.h
../util/util_math_int4.h
../util/util_math_matrix.h
../util/util_projection.h
../util/util_rect.h
../util/util_static_assert.h
../util/util_transform.h

View File

@ -25,7 +25,6 @@ ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(KernelGlobals *k
space.x = kernel_tex_fetch(__bvh_nodes, child_addr+1);
space.y = kernel_tex_fetch(__bvh_nodes, child_addr+2);
space.z = kernel_tex_fetch(__bvh_nodes, child_addr+3);
space.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
return space;
}

View File

@ -276,7 +276,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
shader = __float_as_int(str.z);
}
#endif
int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
/* if no transparent shadows, all light is blocked */
if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {

View File

@ -358,7 +358,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
shader = __float_as_int(str.z);
}
#endif
int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
/* if no transparent shadows, all light is blocked */
if(!(flag & SD_HAS_TRANSPARENT_SHADOW)) {

View File

@ -53,9 +53,7 @@ ccl_device_inline AttributeDescriptor attribute_not_found()
ccl_device_inline uint object_attribute_map_offset(KernelGlobals *kg, int object)
{
int offset = object*OBJECT_SIZE + 15;
float4 f = kernel_tex_fetch(__objects, offset);
return __float_as_uint(f.y);
return kernel_tex_fetch(__objects, object).attribute_map_offset;
}
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
@ -105,7 +103,6 @@ ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderD
tfm.x = kernel_tex_fetch(__attributes_float3, desc.offset + 0);
tfm.y = kernel_tex_fetch(__attributes_float3, desc.offset + 1);
tfm.z = kernel_tex_fetch(__attributes_float3, desc.offset + 2);
tfm.w = kernel_tex_fetch(__attributes_float3, desc.offset + 3);
return tfm;
}

View File

@ -170,8 +170,7 @@ ccl_device_forceinline bool cardinal_curve_intersect(
htfm = make_transform(
dir.z / d, 0, -dir.x /d, 0,
-dir.x * dir.y /d, d, -dir.y * dir.z /d, 0,
dir.x, dir.y, dir.z, 0,
0, 0, 0, 1);
dir.x, dir.y, dir.z, 0);
float4 v00 = kernel_tex_fetch(__curves, prim);

View File

@ -28,62 +28,44 @@ CCL_NAMESPACE_BEGIN
enum ObjectTransform {
OBJECT_TRANSFORM = 0,
OBJECT_INVERSE_TRANSFORM = 4,
OBJECT_TRANSFORM_MOTION_PRE = 0,
OBJECT_TRANSFORM_MOTION_MID = 4,
OBJECT_TRANSFORM_MOTION_POST = 8,
OBJECT_PROPERTIES = 12,
OBJECT_DUPLI = 13
OBJECT_INVERSE_TRANSFORM = 1,
};
enum ObjectVectorTransform {
OBJECT_VECTOR_MOTION_PRE = 0,
OBJECT_VECTOR_MOTION_POST = 3
OBJECT_PASS_MOTION_PRE = 0,
OBJECT_PASS_MOTION_POST = 1
};
/* Object to world space transformation */
ccl_device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type)
{
int offset = object*OBJECT_SIZE + (int)type;
Transform tfm;
tfm.x = kernel_tex_fetch(__objects, offset + 0);
tfm.y = kernel_tex_fetch(__objects, offset + 1);
tfm.z = kernel_tex_fetch(__objects, offset + 2);
tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
return tfm;
if(type == OBJECT_INVERSE_TRANSFORM) {
return kernel_tex_fetch(__objects, object).itfm;
}
else {
return kernel_tex_fetch(__objects, object).tfm;
}
}
/* Lamp to world space transformation */
ccl_device_inline Transform lamp_fetch_transform(KernelGlobals *kg, int lamp, bool inverse)
{
int offset = lamp*LIGHT_SIZE + (inverse? 8 : 5);
Transform tfm;
tfm.x = kernel_tex_fetch(__light_data, offset + 0);
tfm.y = kernel_tex_fetch(__light_data, offset + 1);
tfm.z = kernel_tex_fetch(__light_data, offset + 2);
tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
return tfm;
if(inverse) {
return kernel_tex_fetch(__lights, lamp).itfm;
}
else {
return kernel_tex_fetch(__lights, lamp).tfm;
}
}
/* Object to world space transformation for motion vectors */
ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type)
ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type)
{
int offset = object*OBJECT_VECTOR_SIZE + (int)type;
Transform tfm;
tfm.x = kernel_tex_fetch(__objects_vector, offset + 0);
tfm.y = kernel_tex_fetch(__objects_vector, offset + 1);
tfm.z = kernel_tex_fetch(__objects_vector, offset + 2);
tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
return tfm;
int offset = object*OBJECT_MOTION_PASS_SIZE + (int)type;
return kernel_tex_fetch(__object_motion_pass, offset);
}
/* Motion blurred object transformations */
@ -91,27 +73,12 @@ ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int
#ifdef __OBJECT_MOTION__
ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals *kg, int object, float time)
{
MotionTransform motion;
int offset = object*OBJECT_SIZE + (int)OBJECT_TRANSFORM_MOTION_PRE;
motion.pre.x = kernel_tex_fetch(__objects, offset + 0);
motion.pre.y = kernel_tex_fetch(__objects, offset + 1);
motion.pre.z = kernel_tex_fetch(__objects, offset + 2);
motion.pre.w = kernel_tex_fetch(__objects, offset + 3);
motion.mid.x = kernel_tex_fetch(__objects, offset + 4);
motion.mid.y = kernel_tex_fetch(__objects, offset + 5);
motion.mid.z = kernel_tex_fetch(__objects, offset + 6);
motion.mid.w = kernel_tex_fetch(__objects, offset + 7);
motion.post.x = kernel_tex_fetch(__objects, offset + 8);
motion.post.y = kernel_tex_fetch(__objects, offset + 9);
motion.post.z = kernel_tex_fetch(__objects, offset + 10);
motion.post.w = kernel_tex_fetch(__objects, offset + 11);
const uint motion_offset = kernel_tex_fetch(__objects, object).motion_offset;
const ccl_global DecomposedTransform *motion = &kernel_tex_fetch(__object_motion, motion_offset);
const uint num_steps = kernel_tex_fetch(__objects, object).numsteps * 2 + 1;
Transform tfm;
transform_motion_interpolate(&tfm, &motion, time);
transform_motion_array_interpolate(&tfm, motion, num_steps, time);
return tfm;
}
@ -237,9 +204,7 @@ ccl_device_inline float3 object_location(KernelGlobals *kg, const ShaderData *sd
ccl_device_inline float object_surface_area(KernelGlobals *kg, int object)
{
int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
float4 f = kernel_tex_fetch(__objects, offset);
return f.x;
return kernel_tex_fetch(__objects, object).surface_area;
}
/* Pass ID number of object */
@ -249,9 +214,7 @@ ccl_device_inline float object_pass_id(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return 0.0f;
int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
float4 f = kernel_tex_fetch(__objects, offset);
return f.y;
return kernel_tex_fetch(__objects, object).pass_id;
}
/* Per lamp random number for shader variation */
@ -261,8 +224,7 @@ ccl_device_inline float lamp_random_number(KernelGlobals *kg, int lamp)
if(lamp == LAMP_NONE)
return 0.0f;
float4 f = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 4);
return f.y;
return kernel_tex_fetch(__lights, lamp).random;
}
/* Per object random number for shader variation */
@ -272,9 +234,7 @@ ccl_device_inline float object_random_number(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return 0.0f;
int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
float4 f = kernel_tex_fetch(__objects, offset);
return f.z;
return kernel_tex_fetch(__objects, object).random_number;
}
/* Particle ID from which this object was generated */
@ -284,9 +244,7 @@ ccl_device_inline int object_particle_id(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return 0;
int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
float4 f = kernel_tex_fetch(__objects, offset);
return __float_as_uint(f.w);
return kernel_tex_fetch(__objects, object).particle_index;
}
/* Generated texture coordinate on surface from where object was instanced */
@ -296,9 +254,10 @@ ccl_device_inline float3 object_dupli_generated(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return make_float3(0.0f, 0.0f, 0.0f);
int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
float4 f = kernel_tex_fetch(__objects, offset);
return make_float3(f.x, f.y, f.z);
const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
return make_float3(kobject->dupli_generated[0],
kobject->dupli_generated[1],
kobject->dupli_generated[2]);
}
/* UV texture coordinate on surface from where object was instanced */
@ -308,27 +267,24 @@ ccl_device_inline float3 object_dupli_uv(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return make_float3(0.0f, 0.0f, 0.0f);
int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
float4 f = kernel_tex_fetch(__objects, offset + 1);
return make_float3(f.x, f.y, 0.0f);
const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
return make_float3(kobject->dupli_uv[0],
kobject->dupli_uv[1],
0.0f);
}
/* Information about mesh for motion blurred triangles and curves */
ccl_device_inline void object_motion_info(KernelGlobals *kg, int object, int *numsteps, int *numverts, int *numkeys)
{
int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
if(numkeys) {
float4 f = kernel_tex_fetch(__objects, offset);
*numkeys = __float_as_int(f.w);
*numkeys = kernel_tex_fetch(__objects, object).numkeys;
}
float4 f = kernel_tex_fetch(__objects, offset + 1);
if(numsteps)
*numsteps = __float_as_int(f.z);
*numsteps = kernel_tex_fetch(__objects, object).numsteps;
if(numverts)
*numverts = __float_as_int(f.w);
*numverts = kernel_tex_fetch(__objects, object).numverts;
}
/* Offset to an objects patch map */
@ -338,76 +294,56 @@ ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object)
if(object == OBJECT_NONE)
return 0;
int offset = object*OBJECT_SIZE + 15;
float4 f = kernel_tex_fetch(__objects, offset);
return __float_as_uint(f.x);
return kernel_tex_fetch(__objects, object).patch_map_offset;
}
/* Pass ID for shader */
ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)
{
return kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE + 1);
return kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).pass_id;
}
/* Particle data from which object was instanced */
ccl_device_inline uint particle_index(KernelGlobals *kg, int particle)
{
int offset = particle*PARTICLE_SIZE;
float4 f = kernel_tex_fetch(__particles, offset + 0);
return __float_as_uint(f.x);
return kernel_tex_fetch(__particles, particle).index;
}
ccl_device float particle_age(KernelGlobals *kg, int particle)
{
int offset = particle*PARTICLE_SIZE;
float4 f = kernel_tex_fetch(__particles, offset + 0);
return f.y;
return kernel_tex_fetch(__particles, particle).age;
}
ccl_device float particle_lifetime(KernelGlobals *kg, int particle)
{
int offset = particle*PARTICLE_SIZE;
float4 f = kernel_tex_fetch(__particles, offset + 0);
return f.z;
return kernel_tex_fetch(__particles, particle).lifetime;
}
ccl_device float particle_size(KernelGlobals *kg, int particle)
{
int offset = particle*PARTICLE_SIZE;
float4 f = kernel_tex_fetch(__particles, offset + 0);
return f.w;
return kernel_tex_fetch(__particles, particle).size;
}
ccl_device float4 particle_rotation(KernelGlobals *kg, int particle)
{
int offset = particle*PARTICLE_SIZE;
float4 f = kernel_tex_fetch(__particles, offset + 1);
return f;
return kernel_tex_fetch(__particles, particle).rotation;
}
ccl_device float3 particle_location(KernelGlobals *kg, int particle)
{
int offset = particle*PARTICLE_SIZE;
float4 f = kernel_tex_fetch(__particles, offset + 2);
return make_float3(f.x, f.y, f.z);
return float4_to_float3(kernel_tex_fetch(__particles, particle).location);
}
ccl_device float3 particle_velocity(KernelGlobals *kg, int particle)
{
int offset = particle*PARTICLE_SIZE;
float4 f2 = kernel_tex_fetch(__particles, offset + 2);
float4 f3 = kernel_tex_fetch(__particles, offset + 3);
return make_float3(f2.w, f3.x, f3.y);
return float4_to_float3(kernel_tex_fetch(__particles, particle).velocity);
}
ccl_device float3 particle_angular_velocity(KernelGlobals *kg, int particle)
{
int offset = particle*PARTICLE_SIZE;
float4 f3 = kernel_tex_fetch(__particles, offset + 3);
float4 f4 = kernel_tex_fetch(__particles, offset + 4);
return make_float3(f3.z, f3.w, f4.x);
return float4_to_float3(kernel_tex_fetch(__particles, particle).angular_velocity);
}
/* Object intersection in BVH */

View File

@ -193,10 +193,10 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
* transformation was set match the world/object space of motion_pre/post */
Transform tfm;
tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_PRE);
motion_pre = transform_point(&tfm, motion_pre);
tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_POST);
motion_post = transform_point(&tfm, motion_post);
float3 motion_center;
@ -204,14 +204,14 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
/* camera motion, for perspective/orthographic motion.pre/post will be a
* world-to-raster matrix, for panorama it's world-to-camera */
if(kernel_data.cam.type != CAMERA_PANORAMA) {
tfm = kernel_data.cam.worldtoraster;
motion_center = transform_perspective(&tfm, center);
ProjectionTransform projection = kernel_data.cam.worldtoraster;
motion_center = transform_perspective(&projection, center);
tfm = kernel_data.cam.motion.pre;
motion_pre = transform_perspective(&tfm, motion_pre);
projection = kernel_data.cam.perspective_pre;
motion_pre = transform_perspective(&projection, motion_pre);
tfm = kernel_data.cam.motion.post;
motion_post = transform_perspective(&tfm, motion_post);
projection = kernel_data.cam.perspective_post;
motion_post = transform_perspective(&projection, motion_post);
}
else {
tfm = kernel_data.cam.worldtocamera;
@ -220,13 +220,13 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
motion_center.x *= kernel_data.cam.width;
motion_center.y *= kernel_data.cam.height;
tfm = kernel_data.cam.motion.pre;
tfm = kernel_data.cam.motion_pass_pre;
motion_pre = normalize(transform_point(&tfm, motion_pre));
motion_pre = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_pre));
motion_pre.x *= kernel_data.cam.width;
motion_pre.y *= kernel_data.cam.height;
tfm = kernel_data.cam.motion.post;
tfm = kernel_data.cam.motion_pass_post;
motion_post = normalize(transform_point(&tfm, motion_post));
motion_post = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_post));
motion_post.x *= kernel_data.cam.width;

View File

@ -68,7 +68,7 @@ ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *s
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
if(r.w != 0.0f && r.w != 1.0f) {
if(r.w > 1e-8f && r.w != 1.0f) {
/* For RGBA colors, unpremultiply after interpolation. */
return float4_to_float3(r) / r.w;
}

View File

@ -42,7 +42,7 @@ ccl_device float2 camera_sample_aperture(ccl_constant KernelCamera *cam, float u
ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
{
/* create ray form raster position */
Transform rastertocamera = kernel_data.cam.rastertocamera;
ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
float3 raster = make_float3(raster_x, raster_y, 0.0f);
float3 Pcamera = transform_perspective(&rastertocamera, raster);
@ -54,13 +54,13 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
* interpolated field of view.
*/
if(ray->time < 0.5f) {
Transform rastertocamera_pre = kernel_data.cam.perspective_motion.pre;
ProjectionTransform rastertocamera_pre = kernel_data.cam.perspective_pre;
float3 Pcamera_pre =
transform_perspective(&rastertocamera_pre, raster);
Pcamera = interp(Pcamera_pre, Pcamera, ray->time * 2.0f);
}
else {
Transform rastertocamera_post = kernel_data.cam.perspective_motion.post;
ProjectionTransform rastertocamera_post = kernel_data.cam.perspective_post;
float3 Pcamera_post =
transform_perspective(&rastertocamera_post, raster);
Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f);
@ -91,17 +91,12 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
Transform cameratoworld = kernel_data.cam.cameratoworld;
#ifdef __CAMERA_MOTION__
if(kernel_data.cam.have_motion) {
# ifdef __KERNEL_OPENCL__
const MotionTransform tfm = kernel_data.cam.motion;
transform_motion_interpolate(&cameratoworld,
&tfm,
ray->time);
# else
transform_motion_interpolate(&cameratoworld,
&kernel_data.cam.motion,
ray->time);
# endif
if(kernel_data.cam.num_motion_steps) {
transform_motion_array_interpolate(
&cameratoworld,
kernel_tex_array(__camera_motion),
kernel_data.cam.num_motion_steps,
ray->time);
}
#endif
@ -175,7 +170,7 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, ccl_addr_space Ray *ray)
{
/* create ray form raster position */
Transform rastertocamera = kernel_data.cam.rastertocamera;
ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
float3 P;
@ -203,17 +198,12 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
Transform cameratoworld = kernel_data.cam.cameratoworld;
#ifdef __CAMERA_MOTION__
if(kernel_data.cam.have_motion) {
# ifdef __KERNEL_OPENCL__
const MotionTransform tfm = kernel_data.cam.motion;
transform_motion_interpolate(&cameratoworld,
&tfm,
ray->time);
# else
transform_motion_interpolate(&cameratoworld,
&kernel_data.cam.motion,
ray->time);
# endif
if(kernel_data.cam.num_motion_steps) {
transform_motion_array_interpolate(
&cameratoworld,
kernel_tex_array(__camera_motion),
kernel_data.cam.num_motion_steps,
ray->time);
}
#endif
@ -239,11 +229,12 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
/* Panorama Camera */
ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
const ccl_global DecomposedTransform *cam_motion,
float raster_x, float raster_y,
float lens_u, float lens_v,
ccl_addr_space Ray *ray)
{
Transform rastertocamera = cam->rastertocamera;
ProjectionTransform rastertocamera = cam->rastertocamera;
float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
/* create ray form raster position */
@ -281,17 +272,12 @@ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
Transform cameratoworld = cam->cameratoworld;
#ifdef __CAMERA_MOTION__
if(cam->have_motion) {
# ifdef __KERNEL_OPENCL__
const MotionTransform tfm = cam->motion;
transform_motion_interpolate(&cameratoworld,
&tfm,
ray->time);
# else
transform_motion_interpolate(&cameratoworld,
&cam->motion,
ray->time);
# endif
if(cam->num_motion_steps) {
transform_motion_array_interpolate(
&cameratoworld,
cam_motion,
cam->num_motion_steps,
ray->time);
}
#endif
@ -410,12 +396,16 @@ ccl_device_inline void camera_sample(KernelGlobals *kg,
#endif
/* sample */
if(kernel_data.cam.type == CAMERA_PERSPECTIVE)
if(kernel_data.cam.type == CAMERA_PERSPECTIVE) {
camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray);
else if(kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
}
else if(kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
camera_sample_orthographic(kg, raster_x, raster_y, lens_u, lens_v, ray);
else
camera_sample_panorama(&kernel_data.cam, raster_x, raster_y, lens_u, lens_v, ray);
}
else {
const ccl_global DecomposedTransform *cam_motion = kernel_tex_array(__camera_motion);
camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray);
}
}
/* Utilities */
@ -460,7 +450,7 @@ ccl_device_inline float3 camera_world_to_ndc(KernelGlobals *kg, ShaderData *sd,
if(sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE)
P += camera_position(kg);
Transform tfm = kernel_data.cam.worldtondc;
ProjectionTransform tfm = kernel_data.cam.worldtondc;
return transform_perspective(&tfm, P);
}
else {

View File

@ -118,6 +118,7 @@ template<typename T> struct texture {
#define kernel_tex_fetch_ssef(tex, index) (kg->tex.fetch_ssef(index))
#define kernel_tex_fetch_ssei(tex, index) (kg->tex.fetch_ssei(index))
#define kernel_tex_lookup(tex, t, offset, size) (kg->tex.lookup(t, offset, size))
#define kernel_tex_array(tex) (kg->tex.data)
#define kernel_data (kg->__data)

View File

@ -137,6 +137,7 @@ ccl_device_inline uint ccl_num_groups(uint d)
/* Use arrays for regular data. */
#define kernel_tex_fetch(t, index) t[(index)]
#define kernel_tex_array(t) (t)
#define kernel_data __data

View File

@ -144,7 +144,8 @@
/* data lookup defines */
#define kernel_data (*kg->data)
#define kernel_tex_fetch(tex, index) ((const ccl_global tex##_t*)(kg->buffers[kg->tex.cl_buffer] + kg->tex.data))[(index)]
#define kernel_tex_array(tex) ((const ccl_global tex##_t*)(kg->buffers[kg->tex.cl_buffer] + kg->tex.data))
#define kernel_tex_fetch(tex, index) kernel_tex_array(tex)[(index)]
/* define NULL */
#define NULL 0

View File

@ -29,7 +29,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
/* setup shading at emitter */
float3 eval;
int shader_flag = kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE);
int shader_flag = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).flags;
#ifdef __BACKGROUND_MIS__
if(ls->type == LIGHT_BACKGROUND) {
@ -51,9 +51,9 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
#endif
if(shader_flag & SD_HAS_CONSTANT_EMISSION)
{
eval.x = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 2));
eval.y = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 3));
eval.z = __int_as_float(kernel_tex_fetch(__shader_flag, (ls->shader & SHADER_MASK)*SHADER_SIZE + 4));
eval.x = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[0];
eval.y = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[1];
eval.z = kernel_tex_fetch(__shaders, (ls->shader & SHADER_MASK)).constant_emission[2];
if((ls->prim != PRIM_NONE) && dot(ls->Ng, I) < 0.0f) {
ls->Ng = -ls->Ng;
}

View File

@ -255,11 +255,11 @@ ccl_device_inline bool background_portal_data_fetch_and_check_side(KernelGlobals
float3 *lightpos,
float3 *dir)
{
float4 data0 = kernel_tex_fetch(__light_data, (index + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 0);
float4 data3 = kernel_tex_fetch(__light_data, (index + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 3);
int portal = kernel_data.integrator.portal_offset + index;
const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
*lightpos = make_float3(data0.y, data0.z, data0.w);
*dir = make_float3(data3.y, data3.z, data3.w);
*lightpos = make_float3(klight->co[0], klight->co[1], klight->co[2]);
*dir = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
/* Check whether portal is on the right side. */
if(dot(*dir, P - *lightpos) > 1e-4f)
@ -291,11 +291,10 @@ ccl_device_inline float background_portal_pdf(KernelGlobals *kg,
}
num_possible++;
float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
float3 axisu = make_float3(data1.y, data1.z, data1.w);
float3 axisv = make_float3(data2.y, data2.z, data2.w);
int portal = kernel_data.integrator.portal_offset + p;
const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL, NULL, NULL))
continue;
@ -346,10 +345,10 @@ ccl_device float3 background_portal_sample(KernelGlobals *kg,
if(portal == 0) {
/* p is the portal to be sampled. */
float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
float3 axisu = make_float3(data1.y, data1.z, data1.w);
float3 axisv = make_float3(data2.y, data2.z, data2.w);
int portal = kernel_data.integrator.portal_offset + p;
const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
float3 axisu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
float3 axisv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
*pdf = area_light_sample(P, &lightpos,
axisu, axisv,
@ -479,14 +478,10 @@ ccl_device float3 sphere_light_sample(float3 P, float3 center, float radius, flo
return disk_light_sample(normalize(P - center), randu, randv)*radius;
}
ccl_device float spot_light_attenuation(float4 data1, float4 data2, LightSample *ls)
ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot_smooth, LightSample *ls)
{
float3 dir = make_float3(data2.y, data2.z, data2.w);
float3 I = ls->Ng;
float spot_angle = data1.w;
float spot_smooth = data2.x;
float attenuation = dot(dir, I);
if(attenuation <= spot_angle) {
@ -518,12 +513,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
float3 P,
LightSample *ls)
{
float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
LightType type = (LightType)__float_as_int(data0.x);
const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
LightType type = (LightType)klight->type;
ls->type = type;
ls->shader = __float_as_int(data1.x);
ls->shader = klight->shader_id;
ls->object = PRIM_NONE;
ls->prim = PRIM_NONE;
ls->lamp = lamp;
@ -532,10 +525,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
if(type == LIGHT_DISTANT) {
/* distant light */
float3 lightD = make_float3(data0.y, data0.z, data0.w);
float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
float3 D = lightD;
float radius = data1.y;
float invarea = data1.w;
float radius = klight->distant.radius;
float invarea = klight->distant.invarea;
if(radius > 0.0f)
D = distant_light_sample(D, radius, randu, randv);
@ -562,10 +555,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
}
#endif
else {
ls->P = make_float3(data0.y, data0.z, data0.w);
ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
if(type == LIGHT_POINT || type == LIGHT_SPOT) {
float radius = data1.y;
float radius = klight->spot.radius;
if(radius > 0.0f)
/* sphere light */
@ -574,14 +567,19 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
ls->D = normalize_len(ls->P - P, &ls->t);
ls->Ng = -ls->D;
float invarea = data1.z;
float invarea = klight->spot.invarea;
ls->eval_fac = (0.25f*M_1_PI_F)*invarea;
ls->pdf = invarea;
if(type == LIGHT_SPOT) {
/* spot light attenuation */
float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
float3 dir = make_float3(klight->spot.dir[0],
klight->spot.dir[1],
klight->spot.dir[2]);
ls->eval_fac *= spot_light_attenuation(dir,
klight->spot.spot_angle,
klight->spot.spot_smooth,
ls);
if(ls->eval_fac == 0.0f) {
return false;
}
@ -594,12 +592,15 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
}
else {
/* area light */
float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
float4 data3 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 3);
float3 axisu = make_float3(data1.y, data1.z, data1.w);
float3 axisv = make_float3(data2.y, data2.z, data2.w);
float3 D = make_float3(data3.y, data3.z, data3.w);
float3 axisu = make_float3(klight->area.axisu[0],
klight->area.axisu[1],
klight->area.axisu[2]);
float3 axisv = make_float3(klight->area.axisv[0],
klight->area.axisv[1],
klight->area.axisv[2]);
float3 D = make_float3(klight->area.dir[0],
klight->area.dir[1],
klight->area.dir[2]);
if(dot(ls->P - P, D) > 0.0f) {
return false;
@ -618,7 +619,7 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
ls->Ng = D;
ls->D = normalize_len(ls->P - P, &ls->t);
float invarea = data2.x;
float invarea = klight->area.invarea;
ls->eval_fac = 0.25f*invarea;
}
}
@ -630,12 +631,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls)
{
float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
LightType type = (LightType)__float_as_int(data0.x);
const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
LightType type = (LightType)klight->type;
ls->type = type;
ls->shader = __float_as_int(data1.x);
ls->shader = klight->shader_id;
ls->object = PRIM_NONE;
ls->prim = PRIM_NONE;
ls->lamp = lamp;
@ -648,7 +647,7 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
if(type == LIGHT_DISTANT) {
/* distant light */
float radius = data1.y;
float radius = klight->distant.radius;
if(radius == 0.0f)
return false;
@ -670,9 +669,9 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
* P
*/
float3 lightD = make_float3(data0.y, data0.z, data0.w);
float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]);
float costheta = dot(-lightD, D);
float cosangle = data1.z;
float cosangle = klight->distant.cosangle;
if(costheta < cosangle)
return false;
@ -683,13 +682,14 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
ls->t = FLT_MAX;
/* compute pdf */
float invarea = data1.w;
float invarea = klight->distant.invarea;
ls->pdf = invarea/(costheta*costheta*costheta);
ls->eval_fac = ls->pdf;
}
else if(type == LIGHT_POINT || type == LIGHT_SPOT) {
float3 lightP = make_float3(data0.y, data0.z, data0.w);
float radius = data1.y;
float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
float radius = klight->spot.radius;
/* sphere light */
if(radius == 0.0f)
@ -704,14 +704,19 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
ls->Ng = -D;
ls->D = D;
float invarea = data1.z;
float invarea = klight->spot.invarea;
ls->eval_fac = (0.25f*M_1_PI_F)*invarea;
ls->pdf = invarea;
if(type == LIGHT_SPOT) {
/* spot light attenuation */
float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
ls->eval_fac *= spot_light_attenuation(data1, data2, ls);
float3 dir = make_float3(klight->spot.dir[0],
klight->spot.dir[1],
klight->spot.dir[2]);
ls->eval_fac *= spot_light_attenuation(dir,
klight->spot.spot_angle,
klight->spot.spot_smooth,
ls);
if(ls->eval_fac == 0.0f)
return false;
@ -726,22 +731,25 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
}
else if(type == LIGHT_AREA) {
/* area light */
float4 data2 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 2);
float4 data3 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 3);
float invarea = data2.x;
float invarea = klight->area.invarea;
if(invarea == 0.0f)
return false;
float3 axisu = make_float3(data1.y, data1.z, data1.w);
float3 axisv = make_float3(data2.y, data2.z, data2.w);
float3 Ng = make_float3(data3.y, data3.z, data3.w);
float3 axisu = make_float3(klight->area.axisu[0],
klight->area.axisu[1],
klight->area.axisu[2]);
float3 axisv = make_float3(klight->area.axisv[0],
klight->area.axisv[1],
klight->area.axisv[2]);
float3 Ng = make_float3(klight->area.dir[0],
klight->area.dir[1],
klight->area.dir[2]);
/* one sided */
if(dot(D, Ng) >= 0.0f)
return false;
float3 light_P = make_float3(data0.y, data0.z, data0.w);
float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
if(!ray_quad_intersect(P, D, 0.0f, t, light_P,
axisu, axisv, Ng,
@ -784,7 +792,8 @@ ccl_device_inline bool triangle_world_space_vertices(KernelGlobals *kg, int obje
#ifdef __INSTANCING__
if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
# ifdef __OBJECT_MOTION__
Transform tfm = object_fetch_transform_motion_test(kg, object, time, NULL);
float object_time = (time >= 0.0f) ? time : 0.5f;
Transform tfm = object_fetch_transform_motion_test(kg, object, object_time, NULL);
# else
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
# endif
@ -1040,7 +1049,7 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
int half_len = len >> 1;
int middle = first + half_len;
if(r < kernel_tex_fetch(__light_distribution, middle).x) {
if(r < kernel_tex_fetch(__light_distribution, middle).totarea) {
len = half_len;
}
else {
@ -1055,8 +1064,8 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
/* Rescale to reuse random number. this helps the 2D samples within
* each area light be stratified as well. */
float distr_min = kernel_tex_fetch(__light_distribution, index).x;
float distr_max = kernel_tex_fetch(__light_distribution, index+1).x;
float distr_min = kernel_tex_fetch(__light_distribution, index).totarea;
float distr_max = kernel_tex_fetch(__light_distribution, index+1).totarea;
*randu = (r - distr_min)/(distr_max - distr_min);
return index;
@ -1066,8 +1075,7 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, int bounce)
{
float4 data4 = kernel_tex_fetch(__light_data, index*LIGHT_SIZE + 4);
return (bounce > __float_as_int(data4.x));
return (bounce > kernel_tex_fetch(__lights, index).max_bounces);
}
ccl_device_noinline bool light_sample(KernelGlobals *kg,
@ -1082,12 +1090,12 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
int index = light_distribution_sample(kg, &randu);
/* fetch light data */
float4 l = kernel_tex_fetch(__light_distribution, index);
int prim = __float_as_int(l.y);
const ccl_global KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, index);
int prim = kdistribution->prim;
if(prim >= 0) {
int object = __float_as_int(l.w);
int shader_flag = __float_as_int(l.z);
int object = kdistribution->mesh_light.object_id;
int shader_flag = kdistribution->mesh_light.shader_flag;
triangle_light_sample(kg, prim, object, randu, randv, time, ls, P);
ls->shader |= shader_flag;
@ -1106,8 +1114,7 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
ccl_device int light_select_num_samples(KernelGlobals *kg, int index)
{
float4 data3 = kernel_tex_fetch(__light_data, index*LIGHT_SIZE + 3);
return __float_as_int(data3.x);
return kernel_tex_fetch(__lights, index).samples;
}
CCL_NAMESPACE_END

View File

@ -21,6 +21,7 @@
#include "util/util_math.h"
#include "util/util_math_fast.h"
#include "util/util_math_intersect.h"
#include "util/util_projection.h"
#include "util/util_texture.h"
#include "util/util_transform.h"

View File

@ -114,7 +114,7 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
sd->I = -ray->D;
sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
#ifdef __INSTANCING__
if(isect->object != OBJECT_NONE) {
@ -199,7 +199,7 @@ void shader_setup_from_subsurface(
motion_triangle_shader_setup(kg, sd, isect, ray, true);
}
sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
# ifdef __INSTANCING__
if(isect->object != OBJECT_NONE) {
@ -276,7 +276,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
sd->time = time;
sd->ray_length = t;
sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
sd->object_flag = 0;
if(sd->object != OBJECT_NONE) {
sd->object_flag |= kernel_tex_fetch(__object_flag,
@ -386,7 +386,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
sd->Ng = -ray->D;
sd->I = -ray->D;
sd->shader = kernel_data.background.surface_shader;
sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
sd->object_flag = 0;
sd->time = ray->time;
sd->ray_length = 0.0f;
@ -1181,7 +1181,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg,
sd->shader = stack[i].shader;
sd->flag &= ~SD_SHADER_FLAGS;
sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
sd->object_flag &= ~SD_OBJECT_FLAGS;
if(sd->object != OBJECT_NONE) {
@ -1254,7 +1254,7 @@ ccl_device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect
shader = __float_as_int(str.z);
}
#endif
int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*SHADER_SIZE);
int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
return (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
}

View File

@ -31,8 +31,13 @@ KERNEL_TEX(uint, __object_node)
KERNEL_TEX(float2, __prim_time)
/* objects */
KERNEL_TEX(float4, __objects)
KERNEL_TEX(float4, __objects_vector)
KERNEL_TEX(KernelObject, __objects)
KERNEL_TEX(Transform, __object_motion_pass)
KERNEL_TEX(DecomposedTransform, __object_motion)
KERNEL_TEX(uint, __object_flag)
/* cameras */
KERNEL_TEX(DecomposedTransform, __camera_motion)
/* triangles */
KERNEL_TEX(uint, __tri_shader)
@ -55,18 +60,17 @@ KERNEL_TEX(float4, __attributes_float3)
KERNEL_TEX(uchar4, __attributes_uchar4)
/* lights */
KERNEL_TEX(float4, __light_distribution)
KERNEL_TEX(float4, __light_data)
KERNEL_TEX(KernelLightDistribution, __light_distribution)
KERNEL_TEX(KernelLight, __lights)
KERNEL_TEX(float2, __light_background_marginal_cdf)
KERNEL_TEX(float2, __light_background_conditional_cdf)
/* particles */
KERNEL_TEX(float4, __particles)
KERNEL_TEX(KernelParticle, __particles)
/* shaders */
KERNEL_TEX(uint4, __svm_nodes)
KERNEL_TEX(uint, __shader_flag)
KERNEL_TEX(uint, __object_flag)
KERNEL_TEX(KernelShader, __shaders)
/* lookup tables */
KERNEL_TEX(float, __lookup_table)

View File

@ -35,14 +35,10 @@
CCL_NAMESPACE_BEGIN
/* Constants */
#define OBJECT_SIZE 16
#define OBJECT_VECTOR_SIZE 6
#define LIGHT_SIZE 11
#define FILTER_TABLE_SIZE 1024
#define RAMP_TABLE_SIZE 256
#define SHUTTER_TABLE_SIZE 256
#define PARTICLE_SIZE 5
#define SHADER_SIZE 5
#define OBJECT_MOTION_PASS_SIZE 2
#define FILTER_TABLE_SIZE 1024
#define RAMP_TABLE_SIZE 256
#define SHUTTER_TABLE_SIZE 256
#define BSSRDF_MIN_RADIUS 1e-8f
#define BSSRDF_MAX_HITS 4
@ -925,7 +921,7 @@ enum ShaderDataFlag {
SD_HAS_BUMP = (1 << 25),
/* Has true displacement. */
SD_HAS_DISPLACEMENT = (1 << 26),
/* Has constant emission (value stored in __shader_flag) */
/* Has constant emission (value stored in __shaders) */
SD_HAS_CONSTANT_EMISSION = (1 << 27),
/* Needs to access attributes */
SD_NEED_ATTRIBUTES = (1 << 28),
@ -1163,7 +1159,7 @@ typedef struct KernelCamera {
/* matrices */
Transform cameratoworld;
Transform rastertocamera;
ProjectionTransform rastertocamera;
/* differentials */
float4 dx;
@ -1177,7 +1173,7 @@ typedef struct KernelCamera {
/* motion blur */
float shuttertime;
int have_motion, have_perspective_motion;
int num_motion_steps, have_perspective_motion;
/* clipping */
float nearclip;
@ -1197,22 +1193,22 @@ typedef struct KernelCamera {
int is_inside_volume;
/* more matrices */
Transform screentoworld;
Transform rastertoworld;
/* work around cuda sm 2.0 crash, this seems to
* cross some limit in combination with motion
* Transform ndctoworld; */
Transform worldtoscreen;
Transform worldtoraster;
Transform worldtondc;
ProjectionTransform screentoworld;
ProjectionTransform rastertoworld;
ProjectionTransform ndctoworld;
ProjectionTransform worldtoscreen;
ProjectionTransform worldtoraster;
ProjectionTransform worldtondc;
Transform worldtocamera;
MotionTransform motion;
/* Stores changes in the projeciton matrix. Use for camera zoom motion
* blur and motion pass output for perspective camera. */
ProjectionTransform perspective_pre;
ProjectionTransform perspective_post;
/* Denotes changes in the projective matrix, namely in rastertocamera.
* Used for camera zoom motion blur,
*/
PerspectiveMotionTransform perspective_motion;
/* Transforms for motion pass. */
Transform motion_pass_pre;
Transform motion_pass_post;
int shutter_table_offset;
@ -1434,6 +1430,110 @@ typedef struct KernelData {
} KernelData;
static_assert_align(KernelData, 16);
/* Kernel data structures. */
typedef struct KernelObject {
Transform tfm;
Transform itfm;
float surface_area;
float pass_id;
float random_number;
int particle_index;
float dupli_generated[3];
float dupli_uv[2];
int numkeys;
int numsteps;
int numverts;
uint patch_map_offset;
uint attribute_map_offset;
uint motion_offset;
uint pad;
} KernelObject;;
static_assert_align(KernelObject, 16);
typedef struct KernelSpotLight {
float radius;
float invarea;
float spot_angle;
float spot_smooth;
float dir[3];
} KernelSpotLight;
/* PointLight is SpotLight with only radius and invarea being used. */
typedef struct KernelAreaLight {
float axisu[3];
float invarea;
float axisv[3];
float dir[3];
} KernelAreaLight;
typedef struct KernelDistantLight {
float radius;
float cosangle;
float invarea;
} KernelDistantLight;
typedef struct KernelLight {
int type;
float co[3];
int shader_id;
int samples;
float max_bounces;
float random;
Transform tfm;
Transform itfm;
union {
KernelSpotLight spot;
KernelAreaLight area;
KernelDistantLight distant;
};
} KernelLight;
static_assert_align(KernelLight, 16);
typedef struct KernelLightDistribution {
float totarea;
int prim;
union {
struct {
int shader_flag;
int object_id;
} mesh_light;
struct {
float pad;
float size;
} lamp;
};
} KernelLightDistribution;
static_assert_align(KernelLightDistribution, 16);
typedef struct KernelParticle {
int index;
float age;
float lifetime;
float size;
float4 rotation;
/* Only xyz are used of the following. float4 instead of float3 are used
* to ensure consistent padding/alignment across devices. */
float4 location;
float4 velocity;
float4 angular_velocity;
} KernelParticle;
static_assert_align(KernelParticle, 16);
typedef struct KernelShader {
float constant_emission[3];
float pad1;
int flags;
int pass_id;
int pad2, pad3;
} KernelShader;
static_assert_align(KernelShader, 16);
/* Declarations required for split kernel */
/* Macro for queues */

View File

@ -104,7 +104,7 @@ ccl_device float kernel_volume_channel_get(float3 value, int channel)
ccl_device bool volume_stack_is_heterogeneous(KernelGlobals *kg, ccl_addr_space VolumeStack *stack)
{
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
int shader_flag = kernel_tex_fetch(__shaders, (stack[i].shader & SHADER_MASK)).flags;
if(shader_flag & SD_HETEROGENEOUS_VOLUME) {
return true;
@ -134,7 +134,7 @@ ccl_device int volume_stack_sampling_method(KernelGlobals *kg, VolumeStack *stac
int method = -1;
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
int shader_flag = kernel_tex_fetch(__shaders, (stack[i].shader & SHADER_MASK)).flags;
if(shader_flag & SD_VOLUME_MIS) {
return SD_VOLUME_MIS;

View File

@ -62,11 +62,17 @@ CCL_NAMESPACE_BEGIN
/* RenderServices implementation */
#define COPY_MATRIX44(m1, m2) { \
CHECK_TYPE(m1, OSL::Matrix44*); \
CHECK_TYPE(m2, Transform*); \
memcpy(m1, m2, sizeof(*m2)); \
} (void)0
static void copy_matrix(OSL::Matrix44& m, const Transform& tfm)
{
ProjectionTransform t = projection_transpose(ProjectionTransform(tfm));
memcpy(&m, &t, sizeof(m));
}
static void copy_matrix(OSL::Matrix44& m, const ProjectionTransform& tfm)
{
ProjectionTransform t = projection_transpose(tfm);
memcpy(&m, &t, sizeof(m));
}
/* static ustrings */
ustring OSLRenderServices::u_distance("distance");
@ -167,14 +173,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
#else
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
#endif
tfm = transform_transpose(tfm);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, tfm);
return true;
}
else if(sd->type == PRIMITIVE_LAMP) {
Transform tfm = transform_transpose(sd->ob_tfm);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, sd->ob_tfm);
return true;
}
@ -203,14 +207,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
#else
Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
#endif
itfm = transform_transpose(itfm);
COPY_MATRIX44(&result, &itfm);
copy_matrix(result, itfm);
return true;
}
else if(sd->type == PRIMITIVE_LAMP) {
Transform tfm = transform_transpose(sd->ob_itfm);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, sd->ob_itfm);
return true;
}
@ -224,23 +226,19 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
KernelGlobals *kg = kernel_globals;
if(from == u_ndc) {
Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.ndctoworld);
return true;
}
else if(from == u_raster) {
Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.rastertoworld);
return true;
}
else if(from == u_screen) {
Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.screentoworld);
return true;
}
else if(from == u_camera) {
Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.cameratoworld);
return true;
}
else if(from == u_world) {
@ -256,23 +254,19 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
KernelGlobals *kg = kernel_globals;
if(to == u_ndc) {
Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.worldtondc);
return true;
}
else if(to == u_raster) {
Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.worldtoraster);
return true;
}
else if(to == u_screen) {
Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.worldtoscreen);
return true;
}
else if(to == u_camera) {
Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.worldtocamera);
return true;
}
else if(to == u_world) {
@ -298,14 +292,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
KernelGlobals *kg = sd->osl_globals;
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
#endif
tfm = transform_transpose(tfm);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, tfm);
return true;
}
else if(sd->type == PRIMITIVE_LAMP) {
Transform tfm = transform_transpose(sd->ob_tfm);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, sd->ob_tfm);
return true;
}
@ -329,14 +321,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
KernelGlobals *kg = sd->osl_globals;
Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
#endif
tfm = transform_transpose(tfm);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, tfm);
return true;
}
else if(sd->type == PRIMITIVE_LAMP) {
Transform tfm = transform_transpose(sd->ob_itfm);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, sd->ob_itfm);
return true;
}
@ -350,23 +340,19 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result
KernelGlobals *kg = kernel_globals;
if(from == u_ndc) {
Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.ndctoworld);
return true;
}
else if(from == u_raster) {
Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.rastertoworld);
return true;
}
else if(from == u_screen) {
Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.screentoworld);
return true;
}
else if(from == u_camera) {
Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.cameratoworld);
return true;
}
@ -378,23 +364,19 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44
KernelGlobals *kg = kernel_globals;
if(to == u_ndc) {
Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.worldtondc);
return true;
}
else if(to == u_raster) {
Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.worldtoraster);
return true;
}
else if(to == u_screen) {
Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.worldtoscreen);
return true;
}
else if(to == u_camera) {
Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
COPY_MATRIX44(&result, &tfm);
copy_matrix(result, kernel_data.cam.worldtocamera);
return true;
}
@ -570,8 +552,7 @@ static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives,
static bool set_attribute_matrix(const Transform& tfm, TypeDesc type, void *val)
{
if(type == TypeDesc::TypeMatrix) {
Transform transpose = transform_transpose(tfm);
memcpy(val, &transpose, sizeof(Transform));
copy_matrix(*(OSL::Matrix44*)val, tfm);
return true;
}

View File

@ -26,7 +26,6 @@ ccl_device void svm_node_mapping(KernelGlobals *kg, ShaderData *sd, float *stack
tfm.x = read_node_float(kg, offset);
tfm.y = read_node_float(kg, offset);
tfm.z = read_node_float(kg, offset);
tfm.w = read_node_float(kg, offset);
float3 r = transform_point(&tfm, v);
stack_store_float3(stack, out_offset, r);

View File

@ -42,7 +42,6 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg,
tfm.x = read_node_float(kg, offset);
tfm.y = read_node_float(kg, offset);
tfm.z = read_node_float(kg, offset);
tfm.w = read_node_float(kg, offset);
data = transform_point(&tfm, data);
}
break;
@ -123,7 +122,6 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
tfm.x = read_node_float(kg, offset);
tfm.y = read_node_float(kg, offset);
tfm.z = read_node_float(kg, offset);
tfm.w = read_node_float(kg, offset);
data = transform_point(&tfm, data);
}
break;
@ -207,7 +205,6 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
tfm.x = read_node_float(kg, offset);
tfm.y = read_node_float(kg, offset);
tfm.z = read_node_float(kg, offset);
tfm.w = read_node_float(kg, offset);
data = transform_point(&tfm, data);
}
break;

View File

@ -39,7 +39,6 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
tfm.x = read_node_float(kg, offset);
tfm.y = read_node_float(kg, offset);
tfm.z = read_node_float(kg, offset);
tfm.w = read_node_float(kg, offset);
co = transform_point(&tfm, co);
}

View File

@ -82,6 +82,7 @@ NODE_DEFINE(Camera)
SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f);
SOCKET_TRANSFORM(matrix, "Matrix", transform_identity());
SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f);
@ -151,9 +152,6 @@ Camera::Camera()
height = 512;
resolution = 1;
motion.pre = transform_identity();
motion.post = transform_identity();
use_motion = false;
use_perspective_motion = false;
shutter_curve.resize(RAMP_TABLE_SIZE);
@ -163,12 +161,12 @@ Camera::Camera()
compute_auto_viewplane();
screentoworld = transform_identity();
rastertoworld = transform_identity();
ndctoworld = transform_identity();
rastertocamera = transform_identity();
screentoworld = projection_identity();
rastertoworld = projection_identity();
ndctoworld = projection_identity();
rastertocamera = projection_identity();
cameratoworld = transform_identity();
worldtoraster = transform_identity();
worldtoraster = projection_identity();
dx = make_float3(0.0f, 0.0f, 0.0f);
dy = make_float3(0.0f, 0.0f, 0.0f);
@ -241,18 +239,18 @@ void Camera::update(Scene *scene)
Transform full_rastertoscreen = transform_inverse(full_screentoraster);
/* screen to camera */
Transform cameratoscreen;
ProjectionTransform cameratoscreen;
if(type == CAMERA_PERSPECTIVE)
cameratoscreen = transform_perspective(fov, nearclip, farclip);
cameratoscreen = projection_perspective(fov, nearclip, farclip);
else if(type == CAMERA_ORTHOGRAPHIC)
cameratoscreen = transform_orthographic(nearclip, farclip);
cameratoscreen = projection_orthographic(nearclip, farclip);
else
cameratoscreen = transform_identity();
cameratoscreen = projection_identity();
Transform screentocamera = transform_inverse(cameratoscreen);
ProjectionTransform screentocamera = projection_inverse(cameratoscreen);
rastertocamera = screentocamera * rastertoscreen;
Transform full_rastertocamera = screentocamera * full_rastertoscreen;
ProjectionTransform full_rastertocamera = screentocamera * full_rastertoscreen;
cameratoraster = screentoraster * cameratoscreen;
cameratoworld = matrix;
@ -270,10 +268,10 @@ void Camera::update(Scene *scene)
/* differentials */
if(type == CAMERA_ORTHOGRAPHIC) {
dx = transform_direction(&rastertocamera, make_float3(1, 0, 0));
dy = transform_direction(&rastertocamera, make_float3(0, 1, 0));
full_dx = transform_direction(&full_rastertocamera, make_float3(1, 0, 0));
full_dy = transform_direction(&full_rastertocamera, make_float3(0, 1, 0));
dx = transform_perspective_direction(&rastertocamera, make_float3(1, 0, 0));
dy = transform_perspective_direction(&rastertocamera, make_float3(0, 1, 0));
full_dx = transform_perspective_direction(&full_rastertocamera, make_float3(1, 0, 0));
full_dy = transform_perspective_direction(&full_rastertocamera, make_float3(0, 1, 0));
}
else if(type == CAMERA_PERSPECTIVE) {
dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
@ -302,23 +300,6 @@ void Camera::update(Scene *scene)
frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y));
}
/* TODO(sergey): Support other types of camera. */
if(type == CAMERA_PERSPECTIVE) {
/* TODO(sergey): Move to an utility function and de-duplicate with
* calculation above.
*/
Transform screentocamera_pre =
transform_inverse(transform_perspective(fov_pre,
nearclip,
farclip));
Transform screentocamera_post =
transform_inverse(transform_perspective(fov_post,
nearclip,
farclip));
perspective_motion.pre = screentocamera_pre * rastertoscreen;
perspective_motion.post = screentocamera_post * rastertoscreen;
}
/* Compute kernel camera data. */
KernelCamera *kcam = &kernel_camera;
@ -331,41 +312,65 @@ void Camera::update(Scene *scene)
kcam->worldtoscreen = worldtoscreen;
kcam->worldtoraster = worldtoraster;
kcam->worldtondc = worldtondc;
kcam->ndctoworld = ndctoworld;
/* camera motion */
kcam->have_motion = 0;
kcam->num_motion_steps = 0;
kcam->have_perspective_motion = 0;
kernel_camera_motion.clear();
/* Test if any of the transforms are actually different. */
bool have_motion = false;
for(size_t i = 0; i < motion.size(); i++) {
have_motion = have_motion || motion[i] != matrix;
}
if(need_motion == Scene::MOTION_PASS) {
/* TODO(sergey): Support perspective (zoom, fov) motion. */
if(type == CAMERA_PANORAMA) {
if(use_motion) {
kcam->motion.pre = transform_inverse(motion.pre);
kcam->motion.post = transform_inverse(motion.post);
if(have_motion) {
kcam->motion_pass_pre = transform_inverse(motion[0]);
kcam->motion_pass_post = transform_inverse(motion[motion.size()-1]);
}
else {
kcam->motion.pre = kcam->worldtocamera;
kcam->motion.post = kcam->worldtocamera;
kcam->motion_pass_pre = kcam->worldtocamera;
kcam->motion_pass_post = kcam->worldtocamera;
}
}
else {
if(use_motion) {
kcam->motion.pre = cameratoraster * transform_inverse(motion.pre);
kcam->motion.post = cameratoraster * transform_inverse(motion.post);
if(have_motion) {
kcam->perspective_pre = cameratoraster * transform_inverse(motion[0]);
kcam->perspective_post = cameratoraster * transform_inverse(motion[motion.size()-1]);
}
else {
kcam->motion.pre = worldtoraster;
kcam->motion.post = worldtoraster;
kcam->perspective_pre = worldtoraster;
kcam->perspective_post = worldtoraster;
}
}
}
else if(need_motion == Scene::MOTION_BLUR) {
if(use_motion) {
transform_motion_decompose(&kcam->motion, &motion, &matrix);
kcam->have_motion = 1;
if(have_motion) {
kernel_camera_motion.resize(motion.size());
transform_motion_decompose(kernel_camera_motion.data(), motion.data(), motion.size());
kcam->num_motion_steps = motion.size();
}
if(use_perspective_motion) {
kcam->perspective_motion = perspective_motion;
/* TODO(sergey): Support other types of camera. */
if(use_perspective_motion && type == CAMERA_PERSPECTIVE) {
/* TODO(sergey): Move to an utility function and de-duplicate with
* calculation above.
*/
ProjectionTransform screentocamera_pre =
projection_inverse(projection_perspective(fov_pre,
nearclip,
farclip));
ProjectionTransform screentocamera_post =
projection_inverse(projection_perspective(fov_post,
nearclip,
farclip));
kcam->perspective_pre = screentocamera_pre * rastertoscreen;
kcam->perspective_post = screentocamera_post * rastertoscreen;
kcam->have_perspective_motion = 1;
}
}
@ -470,6 +475,16 @@ void Camera::device_update(Device * /* device */,
}
dscene->data.cam = kernel_camera;
size_t num_motion_steps = kernel_camera_motion.size();
if(num_motion_steps) {
DecomposedTransform *camera_motion = dscene->camera_motion.alloc(num_motion_steps);
memcpy(camera_motion, kernel_camera_motion.data(), sizeof(*camera_motion) * num_motion_steps);
dscene->camera_motion.copy_to_device();
}
else {
dscene->camera_motion.free();
}
}
void Camera::device_update_volume(Device * /*device*/,
@ -496,10 +511,11 @@ void Camera::device_update_volume(Device * /*device*/,
}
void Camera::device_free(Device * /*device*/,
DeviceScene * /*dscene*/,
DeviceScene *dscene,
Scene *scene)
{
scene->lookup_tables->remove_table(&shutter_table_offset);
dscene->camera_motion.free();
}
bool Camera::modified(const Camera& cam)
@ -510,7 +526,6 @@ bool Camera::modified(const Camera& cam)
bool Camera::motion_modified(const Camera& cam)
{
return !((motion == cam.motion) &&
(use_motion == cam.use_motion) &&
(use_perspective_motion == cam.use_perspective_motion));
}
@ -606,7 +621,7 @@ float Camera::world_to_raster_size(float3 P)
res = min(len(full_dx), len(full_dy));
if(offscreen_dicing_scale > 1.0f) {
float3 p = transform_perspective(&worldtocamera, P);
float3 p = transform_point(&worldtocamera, P);
float3 v = transform_perspective(&rastertocamera, make_float3(width, height, 0.0f));
/* Create point clamped to frustum */
@ -707,17 +722,17 @@ float Camera::world_to_raster_size(float3 P)
* may be a better way to do this, but calculating differentials from the
* point directly ahead seems to produce good enough results. */
#if 0
float2 dir = direction_to_panorama(&kernel_camera, normalize(D));
float2 dir = direction_to_panorama(&kernel_camera, kernel_camera_motion.data(), normalize(D));
float3 raster = transform_perspective(&cameratoraster, make_float3(dir.x, dir.y, 0.0f));
ray.t = 1.0f;
camera_sample_panorama(&kernel_camera, raster.x, raster.y, 0.0f, 0.0f, &ray);
camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), raster.x, raster.y, 0.0f, 0.0f, &ray);
if(ray.t == 0.0f) {
/* No differentials, just use from directly ahead. */
camera_sample_panorama(&kernel_camera, 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
}
#else
camera_sample_panorama(&kernel_camera, 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*width, 0.5f*height, 0.0f, 0.0f, &ray);
#endif
differential_transfer(&ray.dP, ray.dP, ray.D, ray.dD, ray.D, dist);
@ -729,4 +744,27 @@ float Camera::world_to_raster_size(float3 P)
return res;
}
bool Camera::use_motion() const
{
return motion.size() > 1;
}
float Camera::motion_time(int step) const
{
return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
}
int Camera::motion_step(float time) const
{
if(use_motion()) {
for(int step = 0; step < motion.size(); step++) {
if(time == motion_time(step)) {
return step;
}
}
}
return -1;
}
CCL_NAMESPACE_END

View File

@ -22,6 +22,7 @@
#include "graph/node.h"
#include "util/util_boundbox.h"
#include "util/util_projection.h"
#include "util/util_transform.h"
#include "util/util_types.h"
@ -140,24 +141,23 @@ public:
Transform matrix;
/* motion */
MotionTransform motion;
bool use_motion, use_perspective_motion;
array<Transform> motion;
bool use_perspective_motion;
float fov_pre, fov_post;
PerspectiveMotionTransform perspective_motion;
/* computed camera parameters */
Transform screentoworld;
Transform rastertoworld;
Transform ndctoworld;
ProjectionTransform screentoworld;
ProjectionTransform rastertoworld;
ProjectionTransform ndctoworld;
Transform cameratoworld;
Transform worldtoraster;
Transform worldtoscreen;
Transform worldtondc;
ProjectionTransform worldtoraster;
ProjectionTransform worldtoscreen;
ProjectionTransform worldtondc;
Transform worldtocamera;
Transform rastertocamera;
Transform cameratoraster;
ProjectionTransform rastertocamera;
ProjectionTransform cameratoraster;
float3 dx;
float3 dy;
@ -176,6 +176,7 @@ public:
/* Kernel camera data, copied here for dicing. */
KernelCamera kernel_camera;
array<DecomposedTransform> kernel_camera_motion;
/* functions */
Camera();
@ -199,6 +200,11 @@ public:
/* Calculates the width of a pixel at point in world space. */
float world_to_raster_size(float3 P);
/* Motion blur. */
float motion_time(int step) const;
int motion_step(float time) const;
bool use_motion() const;
private:
/* Private utility functions. */
float3 transform_raster_to_world(float raster_x, float raster_y);

View File

@ -288,7 +288,7 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
/* emission area */
float4 *distribution = dscene->light_distribution.alloc(num_distribution + 1);
KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
float totarea = 0.0f;
/* triangles */
@ -334,10 +334,10 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
: scene->default_surface;
if(shader->use_mis && shader->has_surface_emission) {
distribution[offset].x = totarea;
distribution[offset].y = __int_as_float(i + mesh->tri_offset);
distribution[offset].z = __int_as_float(shader_flag);
distribution[offset].w = __int_as_float(object_id);
distribution[offset].totarea = totarea;
distribution[offset].prim = i + mesh->tri_offset;
distribution[offset].mesh_light.shader_flag = shader_flag;
distribution[offset].mesh_light.object_id = object_id;
offset++;
Mesh::Triangle t = mesh->get_triangle(i);
@ -372,10 +372,10 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
if(!light->is_enabled)
continue;
distribution[offset].x = totarea;
distribution[offset].y = __int_as_float(~light_index);
distribution[offset].z = 1.0f;
distribution[offset].w = light->size;
distribution[offset].totarea = totarea;
distribution[offset].prim = ~light_index;
distribution[offset].lamp.pad = 1.0f;
distribution[offset].lamp.size = light->size;
totarea += lightarea;
if(light->size > 0.0f && light->use_mis)
@ -390,15 +390,15 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
}
/* normalize cumulative distribution functions */
distribution[num_distribution].x = totarea;
distribution[num_distribution].y = 0.0f;
distribution[num_distribution].z = 0.0f;
distribution[num_distribution].w = 0.0f;
distribution[num_distribution].totarea = totarea;
distribution[num_distribution].prim = 0.0f;
distribution[num_distribution].lamp.pad = 0.0f;
distribution[num_distribution].lamp.size = 0.0f;
if(totarea > 0.0f) {
for(size_t i = 0; i < num_distribution; i++)
distribution[i].x /= totarea;
distribution[num_distribution].x = 1.0f;
distribution[i].totarea /= totarea;
distribution[num_distribution].totarea = 1.0f;
}
if(progress.get_cancel()) return;
@ -620,7 +620,7 @@ void LightManager::device_update_points(Device *,
}
}
float4 *light_data = dscene->light_data.alloc(num_lights*LIGHT_SIZE);
KernelLight *klights = dscene->lights.alloc(num_lights);
if(num_lights == 0) {
VLOG(1) << "No effective light, ignoring points update.";
@ -637,8 +637,8 @@ void LightManager::device_update_points(Device *,
float3 co = light->co;
Shader *shader = (light->shader) ? light->shader : scene->default_light;
int shader_id = scene->shader_manager->get_shader_id(shader);
float samples = __int_as_float(light->samples);
float max_bounces = __int_as_float(light->max_bounces);
int samples = light->samples;
int max_bounces = light->max_bounces;
float random = (float)light->random_id * (1.0f/(float)0xFFFFFFFF);
if(!light->cast_shadow)
@ -661,6 +661,9 @@ void LightManager::device_update_points(Device *,
use_light_visibility = true;
}
klights[light_index].type = light->type;
klights[light_index].samples = samples;
if(light->type == LIGHT_POINT) {
shader_id &= ~SHADER_AREA_LIGHT;
@ -670,10 +673,12 @@ void LightManager::device_update_points(Device *,
if(light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
klights[light_index].co[0] = co.x;
klights[light_index].co[1] = co.y;
klights[light_index].co[2] = co.z;
klights[light_index].spot.radius = radius;
klights[light_index].spot.invarea = invarea;
}
else if(light->type == LIGHT_DISTANT) {
shader_id &= ~SHADER_AREA_LIGHT;
@ -690,10 +695,13 @@ void LightManager::device_update_points(Device *,
if(light->use_mis && area > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
klights[light_index].co[0] = dir.x;
klights[light_index].co[1] = dir.y;
klights[light_index].co[2] = dir.z;
klights[light_index].distant.invarea = invarea;
klights[light_index].distant.radius = radius;
klights[light_index].distant.cosangle = cosangle;
}
else if(light->type == LIGHT_BACKGROUND) {
uint visibility = scene->background->visibility;
@ -717,11 +725,6 @@ void LightManager::device_update_points(Device *,
shader_id |= SHADER_EXCLUDE_SCATTER;
use_light_visibility = true;
}
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
}
else if(light->type == LIGHT_AREA) {
float3 axisu = light->axisu*(light->sizeu*light->size);
@ -735,10 +738,20 @@ void LightManager::device_update_points(Device *,
if(light->use_mis && area > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
klights[light_index].co[0] = co.x;
klights[light_index].co[1] = co.y;
klights[light_index].co[2] = co.z;
klights[light_index].area.axisu[0] = axisu.x;
klights[light_index].area.axisu[1] = axisu.y;
klights[light_index].area.axisu[2] = axisu.z;
klights[light_index].area.axisv[0] = axisv.x;
klights[light_index].area.axisv[1] = axisv.y;
klights[light_index].area.axisv[2] = axisv.z;
klights[light_index].area.invarea = invarea;
klights[light_index].area.dir[0] = dir.x;
klights[light_index].area.dir[1] = dir.y;
klights[light_index].area.dir[2] = dir.z;
}
else if(light->type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
@ -754,18 +767,26 @@ void LightManager::device_update_points(Device *,
if(light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
klights[light_index].co[0] = co.x;
klights[light_index].co[1] = co.y;
klights[light_index].co[2] = co.z;
klights[light_index].spot.radius = radius;
klights[light_index].spot.invarea = invarea;
klights[light_index].spot.spot_angle = spot_angle;
klights[light_index].spot.spot_smooth = spot_smooth;
klights[light_index].spot.dir[0] = dir.x;
klights[light_index].spot.dir[1] = dir.y;
klights[light_index].spot.dir[2] = dir.z;
}
light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, random, 0.0f, 0.0f);
klights[light_index].shader_id = shader_id;
Transform tfm = light->tfm;
Transform itfm = transform_inverse(tfm);
memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3);
memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3);
klights[light_index].max_bounces = max_bounces;
klights[light_index].random = random;
klights[light_index].tfm = light->tfm;
klights[light_index].itfm = transform_inverse(light->tfm);
light_index++;
}
@ -782,21 +803,27 @@ void LightManager::device_update_points(Device *,
float3 axisu = light->axisu*(light->sizeu*light->size);
float3 axisv = light->axisv*(light->sizev*light->size);
float area = len(axisu)*len(axisv);
float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
float3 dir = light->dir;
dir = safe_normalize(dir);
light_data[light_index*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
light_data[light_index*LIGHT_SIZE + 1] = make_float4(area, axisu.x, axisu.y, axisu.z);
light_data[light_index*LIGHT_SIZE + 2] = make_float4(invarea, axisv.x, axisv.y, axisv.z);
light_data[light_index*LIGHT_SIZE + 3] = make_float4(-1, dir.x, dir.y, dir.z);
light_data[light_index*LIGHT_SIZE + 4] = make_float4(-1, 0.0f, 0.0f, 0.0f);
klights[light_index].co[0] = co.x;
klights[light_index].co[1] = co.y;
klights[light_index].co[2] = co.z;
Transform tfm = light->tfm;
Transform itfm = transform_inverse(tfm);
memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3);
memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3);
klights[light_index].area.axisu[0] = axisu.x;
klights[light_index].area.axisu[1] = axisu.y;
klights[light_index].area.axisu[2] = axisu.z;
klights[light_index].area.axisv[0] = axisv.x;
klights[light_index].area.axisv[1] = axisv.y;
klights[light_index].area.axisv[2] = axisv.z;
klights[light_index].area.invarea = invarea;
klights[light_index].area.dir[0] = dir.x;
klights[light_index].area.dir[1] = dir.y;
klights[light_index].area.dir[2] = dir.z;
klights[light_index].tfm = light->tfm;
klights[light_index].itfm = transform_inverse(light->tfm);
light_index++;
}
@ -806,7 +833,7 @@ void LightManager::device_update_points(Device *,
VLOG(1) << "Number of lights without contribution: "
<< num_scene_lights - light_index;
dscene->light_data.copy_to_device();
dscene->lights.copy_to_device();
}
void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
@ -842,7 +869,7 @@ void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *sce
void LightManager::device_free(Device *, DeviceScene *dscene)
{
dscene->light_distribution.free();
dscene->light_data.free();
dscene->lights.free();
dscene->light_background_marginal_cdf.free();
dscene->light_background_conditional_cdf.free();
}

View File

@ -877,15 +877,8 @@ void Mesh::add_undisplaced()
}
}
void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
void Mesh::pack_shaders(Scene *scene, uint *tri_shader)
{
Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
if(attr_vN == NULL) {
/* Happens on objects with just hair. */
return;
}
float3 *vN = attr_vN->data_float3();
uint shader_id = 0;
uint last_shader = -1;
bool last_smooth = false;
@ -893,10 +886,6 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
size_t triangles_size = num_triangles();
int *shader_ptr = shader.data();
bool do_transform = transform_applied;
Transform ntfm = transform_normal;
/* save shader */
for(size_t i = 0; i < triangles_size; i++) {
if(shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
last_shader = shader_ptr[i];
@ -908,7 +897,20 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
tri_shader[i] = shader_id;
}
}
void Mesh::pack_normals(float4 *vnormal)
{
Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
if(attr_vN == NULL) {
/* Happens on objects with just hair. */
return;
}
bool do_transform = transform_applied;
Transform ntfm = transform_normal;
float3 *vN = attr_vN->data_float3();
size_t verts_size = verts.size();
for(size_t i = 0; i < verts_size; i++) {
@ -1117,6 +1119,32 @@ bool Mesh::has_true_displacement() const
return false;
}
float Mesh::motion_time(int step) const
{
return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f;
}
int Mesh::motion_step(float time) const
{
if(motion_steps > 1) {
int attr_step = 0;
for(int step = 0; step < motion_steps; step++) {
float step_time = motion_time(step);
if(step_time == time) {
return attr_step;
}
/* Center step is stored in a separate attribute. */
if(step != motion_steps / 2) {
attr_step++;
}
}
}
return -1;
}
bool Mesh::need_build_bvh() const
{
return !transform_applied || has_surface_bssrdf;
@ -1445,11 +1473,11 @@ static void update_attribute_element_offset(Mesh *mesh,
Transform *tfm = mattr->data_transform();
offset = attr_float3_offset;
assert(attr_float3.size() >= offset + size * 4);
for(size_t k = 0; k < size*4; k++) {
assert(attr_float3.size() >= offset + size * 3);
for(size_t k = 0; k < size*3; k++) {
attr_float3[offset+k] = (&tfm->x)[k];
}
attr_float3_offset += size * 4;
attr_float3_offset += size * 3;
}
else {
float4 *data = mattr->data_float4();
@ -1747,9 +1775,9 @@ void MeshManager::device_update_mesh(Device *,
float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
foreach(Mesh *mesh, scene->meshes) {
mesh->pack_normals(scene,
&tri_shader[mesh->tri_offset],
&vnormal[mesh->vert_offset]);
mesh->pack_shaders(scene,
&tri_shader[mesh->tri_offset]);
mesh->pack_normals(&vnormal[mesh->vert_offset]);
mesh->pack_verts(tri_prim_index,
&tri_vindex[mesh->tri_offset],
&tri_patch[mesh->tri_offset],
@ -2031,7 +2059,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
VLOG(1) << "Total " << scene->meshes.size() << " meshes.";
/* Update normals. */
bool true_displacement_used = false;
size_t total_tess_needed = 0;
foreach(Mesh *mesh, scene->meshes) {
foreach(Shader *shader, mesh->used_shaders) {
if(shader->need_update_mesh)
@ -2039,6 +2069,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
}
if(mesh->need_update) {
/* Update normals. */
mesh->add_face_normals();
mesh->add_vertex_normals();
@ -2046,57 +2077,53 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
mesh->add_undisplaced();
}
/* Test if we need tesselation. */
if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
mesh->num_subd_verts == 0 &&
mesh->subd_params)
{
total_tess_needed++;
}
/* Test if we need displacement. */
if(mesh->has_true_displacement()) {
true_displacement_used = true;
}
if(progress.get_cancel()) return;
}
}
/* Tessellate meshes that are using subdivision */
size_t total_tess_needed = 0;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
mesh->num_subd_verts == 0 &&
mesh->subd_params)
{
total_tess_needed++;
}
}
if(total_tess_needed) {
size_t i = 0;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
mesh->num_subd_verts == 0 &&
mesh->subd_params)
{
string msg = "Tessellating ";
if(mesh->name == "")
msg += string_printf("%u/%u", (uint)(i+1), (uint)total_tess_needed);
else
msg += string_printf("%s %u/%u", mesh->name.c_str(), (uint)(i+1), (uint)total_tess_needed);
size_t i = 0;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
mesh->subdivision_type != Mesh::SUBDIVISION_NONE &&
mesh->num_subd_verts == 0 &&
mesh->subd_params)
{
string msg = "Tessellating ";
if(mesh->name == "")
msg += string_printf("%u/%u", (uint)(i+1), (uint)total_tess_needed);
else
msg += string_printf("%s %u/%u", mesh->name.c_str(), (uint)(i+1), (uint)total_tess_needed);
progress.set_status("Updating Mesh", msg);
progress.set_status("Updating Mesh", msg);
DiagSplit dsplit(*mesh->subd_params);
mesh->tessellate(&dsplit);
DiagSplit dsplit(*mesh->subd_params);
mesh->tessellate(&dsplit);
i++;
i++;
if(progress.get_cancel()) return;
}
if(progress.get_cancel()) return;
}
}
/* Update images needed for true displacement. */
bool true_displacement_used = false;
bool old_need_object_flags_update = false;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
mesh->has_true_displacement())
{
true_displacement_used = true;
break;
}
}
if(true_displacement_used) {
VLOG(1) << "Updating images used for true displacement.";
device_update_displacement_images(device, scene, progress);
@ -2122,11 +2149,17 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
/* Update displacement. */
bool displacement_done = false;
size_t num_bvh = 0;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
displace(device, dscene, scene, mesh, progress))
{
displacement_done = true;
if(mesh->need_update) {
if(displace(device, dscene, scene, mesh, progress)) {
displacement_done = true;
}
if(mesh->need_build_bvh()) {
num_bvh++;
}
}
}
@ -2141,17 +2174,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
if(progress.get_cancel()) return;
}
/* Update bvh. */
size_t num_bvh = 0;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update && mesh->need_build_bvh()) {
num_bvh++;
}
}
TaskPool pool;
i = 0;
size_t i = 0;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update) {
pool.push(function_bind(&Mesh::compute_bvh,

View File

@ -279,7 +279,8 @@ public:
void add_vertex_normals();
void add_undisplaced();
void pack_normals(Scene *scene, uint *shader, float4 *vnormal);
void pack_shaders(Scene *scene, uint *shader);
void pack_normals(float4 *vnormal);
void pack_verts(const vector<uint>& tri_prim_index,
uint4 *tri_vindex,
uint *tri_patch,
@ -304,6 +305,11 @@ public:
bool has_motion_blur() const;
bool has_true_displacement() const;
/* Convert between normalized -1..1 motion time and index
* in the VERTEX_MOTION attribute. */
float motion_time(int step) const;
int motion_step(float time) const;
/* Check whether the mesh should have own BVH built separately. Briefly,
* own BVH is needed for mesh, if:
*

View File

@ -152,22 +152,22 @@ public:
void add_node_with_padding(int x, int y, int z);
void create_mesh(vector<float3> &vertices,
vector<int> &indices,
vector<float3> &face_normals);
vector<int> &indices,
vector<float3> &face_normals);
private:
void generate_vertices_and_quads(vector<int3> &vertices_is,
vector<QuadData> &quads);
vector<QuadData> &quads);
void deduplicate_vertices(vector<int3> &vertices,
vector<QuadData> &quads);
vector<QuadData> &quads);
void convert_object_space(const vector<int3> &vertices,
vector<float3> &out_vertices);
vector<float3> &out_vertices);
void convert_quads_to_tris(const vector<QuadData> &quads,
vector<int> &tris,
vector<float3> &face_normals);
vector<int> &tris,
vector<float3> &face_normals);
};
VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params)
@ -224,8 +224,8 @@ void VolumeMeshBuilder::add_node_with_padding(int x, int y, int z)
}
void VolumeMeshBuilder::create_mesh(vector<float3> &vertices,
vector<int> &indices,
vector<float3> &face_normals)
vector<int> &indices,
vector<float3> &face_normals)
{
/* We create vertices in index space (is), and only convert them to object
* space when done. */
@ -260,8 +260,8 @@ void VolumeMeshBuilder::generate_vertices_and_quads(
/* Compute min and max coords of the node in index space. */
int3 min = make_int3((x - pad_offset.x)*CUBE_SIZE,
(y - pad_offset.y)*CUBE_SIZE,
(z - pad_offset.z)*CUBE_SIZE);
(y - pad_offset.y)*CUBE_SIZE,
(z - pad_offset.z)*CUBE_SIZE);
/* Maximum is just CUBE_SIZE voxels away from minimum on each axis. */
int3 max = make_int3(min.x + CUBE_SIZE, min.y + CUBE_SIZE, min.z + CUBE_SIZE);
@ -316,7 +316,7 @@ void VolumeMeshBuilder::generate_vertices_and_quads(
}
void VolumeMeshBuilder::deduplicate_vertices(vector<int3> &vertices,
vector<QuadData> &quads)
vector<QuadData> &quads)
{
vector<int3> sorted_vertices = vertices;
std::sort(sorted_vertices.begin(), sorted_vertices.end());
@ -355,7 +355,7 @@ void VolumeMeshBuilder::deduplicate_vertices(vector<int3> &vertices,
}
void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
vector<float3> &out_vertices)
vector<float3> &out_vertices)
{
out_vertices.reserve(vertices.size());
@ -369,8 +369,8 @@ void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices,
}
void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads,
vector<int> &tris,
vector<float3> &face_normals)
vector<int> &tris,
vector<float3> &face_normals)
{
int index_offset = 0;
tris.resize(quads.size()*6);
@ -399,8 +399,8 @@ struct VoxelAttributeGrid {
};
void MeshManager::create_volume_mesh(Scene *scene,
Mesh *mesh,
Progress& progress)
Mesh *mesh,
Progress& progress)
{
string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str());
progress.set_status("Updating Mesh", msg);
@ -470,8 +470,8 @@ void MeshManager::create_volume_mesh(Scene *scene,
const int3 resolution = volume_params.resolution;
float3 start_point = make_float3(0.0f, 0.0f, 0.0f);
float3 cell_size = make_float3(1.0f/resolution.x,
1.0f/resolution.y,
1.0f/resolution.z);
1.0f/resolution.y,
1.0f/resolution.z);
if(attr) {
const Transform *tfm = attr->data_transform();
@ -575,12 +575,12 @@ void MeshManager::create_volume_mesh(Scene *scene,
/* Print stats. */
VLOG(1) << "Memory usage volume mesh: "
<< ((vertices.size() + face_normals.size())*sizeof(float3) + indices.size()*sizeof(int))/(1024.0*1024.0)
<< "Mb.";
<< ((vertices.size() + face_normals.size())*sizeof(float3) + indices.size()*sizeof(int))/(1024.0*1024.0)
<< "Mb.";
VLOG(1) << "Memory usage volume grid: "
<< (resolution.x*resolution.y*resolution.z*sizeof(float))/(1024.0*1024.0)
<< "Mb.";
<< (resolution.x*resolution.y*resolution.z*sizeof(float))/(1024.0*1024.0)
<< "Mb.";
}
CCL_NAMESPACE_END

View File

@ -117,8 +117,7 @@ Transform TextureMapping::compute_transform()
case NORMAL:
/* no translation for normals, and inverse transpose */
mat = rmat*smat;
mat = transform_inverse(mat);
mat = transform_transpose(mat);
mat = transform_transposed_inverse(mat);
break;
}
@ -153,7 +152,6 @@ void TextureMapping::compile(SVMCompiler& compiler, int offset_in, int offset_ou
compiler.add_node(tfm.x);
compiler.add_node(tfm.y);
compiler.add_node(tfm.z);
compiler.add_node(tfm.w);
if(use_minmax) {
compiler.add_node(NODE_MIN_MAX, offset_out, offset_out);
@ -193,9 +191,7 @@ void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in,
void TextureMapping::compile(OSLCompiler &compiler)
{
if(!skip()) {
Transform tfm = transform_transpose(compute_transform());
compiler.parameter("mapping", tfm);
compiler.parameter("mapping", compute_transform());
compiler.parameter("use_mapping", 1);
}
}
@ -1434,7 +1430,6 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(tfm.x);
compiler.add_node(tfm.y);
compiler.add_node(tfm.z);
compiler.add_node(tfm.w);
}
}
else {
@ -1478,7 +1473,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", transform_transpose(tfm));
compiler.parameter("mapping", tfm);
compiler.parameter("use_mapping", 1);
}
compiler.parameter(this, "interpolation");
@ -1558,8 +1553,7 @@ void MappingNode::compile(SVMCompiler& compiler)
void MappingNode::compile(OSLCompiler& compiler)
{
Transform tfm = transform_transpose(tex_mapping.compute_transform());
compiler.parameter("Matrix", tfm);
compiler.parameter("Matrix", tex_mapping.compute_transform());
compiler.parameter_point("mapping_min", tex_mapping.min);
compiler.parameter_point("mapping_max", tex_mapping.max);
compiler.parameter("use_minmax", tex_mapping.use_minmax);
@ -3220,7 +3214,6 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler)
compiler.add_node(ob_itfm.x);
compiler.add_node(ob_itfm.y);
compiler.add_node(ob_itfm.z);
compiler.add_node(ob_itfm.w);
}
}
@ -3259,7 +3252,7 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler)
if(compiler.output_type() == SHADER_TYPE_VOLUME)
compiler.parameter("is_volume", true);
compiler.parameter(this, "use_transform");
Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm));
Transform ob_itfm = transform_transposed_inverse(ob_tfm);
compiler.parameter("object_itfm", ob_itfm);
compiler.parameter(this, "from_dupli");

View File

@ -33,6 +33,52 @@
CCL_NAMESPACE_BEGIN
/* Global state of object transform update. */
struct UpdateObjectTransformState {
/* Global state used by device_update_object_transform().
* Common for both threaded and non-threaded update.
*/
/* Type of the motion required by the scene settings. */
Scene::MotionType need_motion;
/* Mapping from particle system to a index in packed particle array.
* Only used for read.
*/
map<ParticleSystem*, int> particle_offset;
/* Mesh area.
* Used to avoid calculation of mesh area multiple times. Used for both
* read and write. Acquire surface_area_lock to keep it all thread safe.
*/
map<Mesh*, float> surface_area_map;
/* Motion offsets for each object. */
array<uint> motion_offset;
/* Packed object arrays. Those will be filled in. */
uint *object_flag;
KernelObject *objects;
Transform *object_motion_pass;
DecomposedTransform *object_motion;
/* Flags which will be synchronized to Integrator. */
bool have_motion;
bool have_curves;
/* ** Scheduling queue. ** */
Scene *scene;
/* Some locks to keep everything thread-safe. */
thread_spin_lock queue_lock;
thread_spin_lock surface_area_lock;
/* First unused object index in the queue. */
int queue_start_object;
};
/* Object */
NODE_DEFINE(Object)
@ -48,6 +94,7 @@ NODE_DEFINE(Object)
SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false);
SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f));
SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);
@ -60,45 +107,54 @@ Object::Object()
particle_system = NULL;
particle_index = 0;
bounds = BoundBox::empty;
motion.pre = transform_empty();
motion.mid = transform_empty();
motion.post = transform_empty();
use_motion = false;
}
Object::~Object()
{
}
void Object::update_motion()
{
if(!use_motion()) {
return;
}
bool have_motion = false;
for(size_t i = 0; i < motion.size(); i++) {
if(motion[i] == transform_empty()) {
if(hide_on_missing_motion) {
/* Hide objects that have no valid previous or next
* transform, for example particle that stop existing. It
* would be better to handle this in the kernel and make
* objects invisible outside certain motion steps. */
tfm = transform_empty();
motion.clear();
return;
}
else {
/* Otherwise just copy center motion. */
motion[i] = tfm;
}
}
/* Test if any of the transforms are actually different. */
have_motion = have_motion || motion[i] != tfm;
}
/* Clear motion array if there is no actual motion. */
if(!have_motion) {
motion.clear();
}
}
void Object::compute_bounds(bool motion_blur)
{
BoundBox mbounds = mesh->bounds;
if(motion_blur && use_motion) {
MotionTransform mtfm = motion;
if(hide_on_missing_motion) {
/* Hide objects that have no valid previous or next transform, for
* example particle that stop existing. TODO: add support for this
* case in the kernel so we don't get render artifacts. */
if(mtfm.pre == transform_empty() ||
mtfm.post == transform_empty()) {
bounds = BoundBox::empty;
return;
}
}
/* In case of missing motion information for previous/next frame,
* assume there is no motion. */
if(mtfm.pre == transform_empty()) {
mtfm.pre = tfm;
}
if(mtfm.post == transform_empty()) {
mtfm.post = tfm;
}
MotionTransform decomp;
transform_motion_decompose(&decomp, &mtfm, &tfm);
if(motion_blur && use_motion()) {
array<DecomposedTransform> decomp(motion.size());
transform_motion_decompose(decomp.data(), motion.data(), motion.size());
bounds = BoundBox::empty;
@ -108,11 +164,12 @@ void Object::compute_bounds(bool motion_blur)
for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
Transform ttfm;
transform_motion_interpolate(&ttfm, &decomp, t);
transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t);
bounds.grow(mbounds.transformed(&ttfm));
}
}
else {
/* No motion blur case. */
if(mesh->transform_applied) {
bounds = mbounds;
}
@ -132,7 +189,7 @@ void Object::apply_transform(bool apply_to_motion)
/* store matrix to transform later. when accessing these as attributes we
* do not want the transform to be applied for consistency between static
* and dynamic BVH, so we do it on packing. */
mesh->transform_normal = transform_transpose(transform_inverse(tfm));
mesh->transform_normal = transform_transposed_inverse(tfm);
/* apply to mesh vertices */
for(size_t i = 0; i < mesh->verts.size(); i++)
@ -232,27 +289,30 @@ void Object::tag_update(Scene *scene)
scene->object_manager->need_update = true;
}
vector<float> Object::motion_times()
bool Object::use_motion() const
{
/* compute times at which we sample motion for this object */
vector<float> times;
return (motion.size() > 1);
}
if(!mesh || mesh->motion_steps == 1)
return times;
float Object::motion_time(int step) const
{
return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
}
int motion_steps = mesh->motion_steps;
for(int step = 0; step < motion_steps; step++) {
if(step != motion_steps / 2) {
float time = 2.0f * step / (motion_steps - 1) - 1.0f;
times.push_back(time);
int Object::motion_step(float time) const
{
if(use_motion()) {
for(size_t step = 0; step < motion.size(); step++) {
if(time == motion_time(step)) {
return step;
}
}
}
return times;
return -1;
}
bool Object::is_traceable()
bool Object::is_traceable() const
{
/* Mesh itself can be empty,can skip all such objects. */
if(!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
@ -289,8 +349,8 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
Object *ob,
int object_index)
{
float4 *objects = state->objects;
float4 *objects_vector = state->objects_vector;
KernelObject& kobject = state->objects[object_index];
Transform *object_motion_pass = state->object_motion_pass;
Mesh *mesh = ob->mesh;
uint flag = 0;
@ -357,15 +417,13 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
}
}
/* Pack in texture. */
int offset = object_index*OBJECT_SIZE;
/* OBJECT_TRANSFORM */
memcpy(&objects[offset], &tfm, sizeof(float4)*3);
/* OBJECT_INVERSE_TRANSFORM */
memcpy(&objects[offset+4], &itfm, sizeof(float4)*3);
/* OBJECT_PROPERTIES */
objects[offset+12] = make_float4(surface_area, pass_id, random_number, __int_as_float(particle_index));
kobject.tfm = tfm;
kobject.itfm = itfm;
kobject.surface_area = surface_area;
kobject.pass_id = pass_id;
kobject.random_number = random_number;
kobject.particle_index = particle_index;
kobject.motion_offset = 0;
if(mesh->use_motion_blur) {
state->have_motion = true;
@ -375,50 +433,56 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
}
if(state->need_motion == Scene::MOTION_PASS) {
/* Clear motion array if there is no actual motion. */
ob->update_motion();
/* Compute motion transforms. */
Transform tfm_pre, tfm_post;
if(ob->use_motion()) {
tfm_pre = ob->motion[0];
tfm_post = ob->motion[ob->motion.size() - 1];
}
else {
tfm_pre = tfm;
tfm_post = tfm;
}
/* Motion transformations, is world/object space depending if mesh
* comes with deformed position in object space, or if we transform
* the shading point in world space.
*/
MotionTransform mtfm = ob->motion;
/* In case of missing motion information for previous/next frame,
* assume there is no motion. */
if(!ob->use_motion || mtfm.pre == transform_empty()) {
mtfm.pre = ob->tfm;
}
if(!ob->use_motion || mtfm.post == transform_empty()) {
mtfm.post = ob->tfm;
}
* the shading point in world space. */
if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
mtfm.pre = mtfm.pre * itfm;
mtfm.post = mtfm.post * itfm;
tfm_pre = tfm_pre * itfm;
tfm_post = tfm_post * itfm;
}
memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+0], &mtfm.pre, sizeof(float4)*3);
memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+3], &mtfm.post, sizeof(float4)*3);
int motion_pass_offset = object_index*OBJECT_MOTION_PASS_SIZE;
object_motion_pass[motion_pass_offset + 0] = tfm_pre;
object_motion_pass[motion_pass_offset + 1] = tfm_post;
}
else if(state->need_motion == Scene::MOTION_BLUR) {
if(ob->use_motion) {
/* decompose transformations for interpolation. */
MotionTransform decomp;
if(ob->use_motion()) {
kobject.motion_offset = state->motion_offset[object_index];
transform_motion_decompose(&decomp, &ob->motion, &ob->tfm);
memcpy(&objects[offset], &decomp, sizeof(float4)*12);
/* Decompose transforms for interpolation. */
DecomposedTransform *decomp = state->object_motion + kobject.motion_offset;
transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size());
flag |= SD_OBJECT_MOTION;
state->have_motion = true;
}
}
/* Dupli object coords and motion info. */
kobject.dupli_generated[0] = ob->dupli_generated[0];
kobject.dupli_generated[1] = ob->dupli_generated[1];
kobject.dupli_generated[2] = ob->dupli_generated[2];
kobject.numkeys = mesh->curve_keys.size();
kobject.dupli_uv[0] = ob->dupli_uv[0];
kobject.dupli_uv[1] = ob->dupli_uv[1];
int totalsteps = mesh->motion_steps;
int numsteps = (totalsteps - 1)/2;
int numverts = mesh->verts.size();
int numkeys = mesh->curve_keys.size();
objects[offset+13] = make_float4(ob->dupli_generated[0], ob->dupli_generated[1], ob->dupli_generated[2], __int_as_float(numkeys));
objects[offset+14] = make_float4(ob->dupli_uv[0], ob->dupli_uv[1], __int_as_float(numsteps), __int_as_float(numverts));
objects[offset+15] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
kobject.numsteps = (totalsteps - 1)/2;
kobject.numverts = mesh->verts.size();;
kobject.patch_map_offset = 0;
kobject.attribute_map_offset = 0;
/* Object flag. */
if(ob->use_holdout) {
@ -475,7 +539,6 @@ void ObjectManager::device_update_object_transform_task(
void ObjectManager::device_update_transforms(DeviceScene *dscene,
Scene *scene,
uint *object_flag,
Progress& progress)
{
UpdateObjectTransformState state;
@ -485,13 +548,29 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene,
state.scene = scene;
state.queue_start_object = 0;
state.object_flag = object_flag;
state.objects = dscene->objects.alloc(OBJECT_SIZE*scene->objects.size());
state.objects = dscene->objects.alloc(scene->objects.size());
state.object_flag = dscene->object_flag.alloc(scene->objects.size());
state.object_motion = NULL;
state.object_motion_pass = NULL;
if(state.need_motion == Scene::MOTION_PASS) {
state.objects_vector = dscene->objects_vector.alloc(OBJECT_VECTOR_SIZE*scene->objects.size());
state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE*scene->objects.size());
}
else {
state.objects_vector = NULL;
else if(state.need_motion == Scene::MOTION_BLUR) {
/* Set object offsets into global object motion array. */
uint *motion_offsets = state.motion_offset.resize(scene->objects.size());
uint motion_offset = 0;
foreach(Object *ob, scene->objects) {
*motion_offsets = motion_offset;
motion_offsets++;
/* Clear motion array if there is no actual motion. */
ob->update_motion();
motion_offset += ob->motion.size();
}
state.object_motion = dscene->object_motion.alloc(motion_offset);
}
/* Particle system device offsets
@ -534,7 +613,10 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene,
dscene->objects.copy_to_device();
if(state.need_motion == Scene::MOTION_PASS) {
dscene->objects_vector.copy_to_device();
dscene->object_motion_pass.copy_to_device();
}
else if(state.need_motion == Scene::MOTION_BLUR) {
dscene->object_motion.copy_to_device();
}
dscene->data.bvh.have_motion = state.have_motion;
@ -554,12 +636,9 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
if(scene->objects.size() == 0)
return;
/* object info flag */
uint *object_flag = dscene->object_flag.alloc(scene->objects.size());
/* set object transform matrices, before applying static transforms */
progress.set_status("Updating Objects", "Copying Transformations to device");
device_update_transforms(dscene, scene, object_flag, progress);
device_update_transforms(dscene, scene, progress);
if(progress.get_cancel()) return;
@ -567,7 +646,7 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
/* todo: do before to support getting object level coords? */
if(scene->params.bvh_type == SceneParams::BVH_STATIC) {
progress.set_status("Updating Objects", "Applying Static Transformations");
apply_static_transforms(dscene, scene, object_flag, progress);
apply_static_transforms(dscene, scene, progress);
}
}
@ -586,9 +665,10 @@ void ObjectManager::device_update_flags(Device *,
if(scene->objects.size() == 0)
return;
/* object info flag */
/* Object info flag. */
uint *object_flag = dscene->object_flag.data();
/* Object volume intersection. */
vector<Object *> volume_objects;
bool has_volume_objects = false;
foreach(Object *object, scene->objects) {
@ -642,7 +722,7 @@ void ObjectManager::device_update_flags(Device *,
++object_index;
}
/* allocate object flag */
/* Copy object flag. */
dscene->object_flag.copy_to_device();
}
@ -652,27 +732,26 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
return;
}
uint4* objects = (uint4*)dscene->objects.data();
KernelObject *kobjects = dscene->objects.data();
bool update = false;
int object_index = 0;
foreach(Object *object, scene->objects) {
Mesh* mesh = object->mesh;
int offset = object_index*OBJECT_SIZE + 15;
if(mesh->patch_table) {
uint patch_map_offset = 2*(mesh->patch_table_offset + mesh->patch_table->total_size() -
mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - mesh->patch_offset;
if(objects[offset].x != patch_map_offset) {
objects[offset].x = patch_map_offset;
if(kobjects[object_index].patch_map_offset != patch_map_offset) {
kobjects[object_index].patch_map_offset = patch_map_offset;
update = true;
}
}
if(objects[offset].y != mesh->attr_map_offset) {
objects[offset].y = mesh->attr_map_offset;
if(kobjects[object_index].attribute_map_offset != mesh->attr_map_offset) {
kobjects[object_index].attribute_map_offset = mesh->attr_map_offset;
update = true;
}
@ -687,11 +766,12 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
void ObjectManager::device_free(Device *, DeviceScene *dscene)
{
dscene->objects.free();
dscene->objects_vector.free();
dscene->object_motion_pass.free();
dscene->object_motion.free();
dscene->object_flag.free();
}
void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress)
void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress& progress)
{
/* todo: normals and displacement should be done before applying transform! */
/* todo: create objects/meshes in right order! */
@ -715,6 +795,8 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
if(progress.get_cancel()) return;
uint *object_flag = dscene->object_flag.data();
/* apply transforms for objects with single user meshes */
foreach(Object *object, scene->objects) {
/* Annoying feedback loop here: we can't use is_instanced() because
@ -725,7 +807,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
!object->mesh->has_true_displacement() && object->mesh->subdivision_type == Mesh::SUBDIVISION_NONE)
{
if(!(motion_blur && object->use_motion)) {
if(!(motion_blur && object->use_motion())) {
if(!object->mesh->transform_applied) {
object->apply_transform(apply_to_motion);
object->mesh->transform_applied = true;

View File

@ -35,6 +35,7 @@ class ParticleSystem;
class Progress;
class Scene;
struct Transform;
struct UpdateObjectTransformState;
/* Object */
@ -49,8 +50,7 @@ public:
int pass_id;
vector<ParamValue> attributes;
uint visibility;
MotionTransform motion;
bool use_motion;
array<Transform> motion;
bool hide_on_missing_motion;
bool use_holdout;
bool is_shadow_catcher;
@ -69,12 +69,17 @@ public:
void compute_bounds(bool motion_blur);
void apply_transform(bool apply_to_motion);
vector<float> motion_times();
/* Convert between normalized -1..1 motion time and index
* in the motion array. */
bool use_motion() const;
float motion_time(int step) const;
int motion_step(float time) const;
void update_motion();
/* Check whether object is traceable and it worth adding it to
* kernel scene.
*/
bool is_traceable();
bool is_traceable() const;
/* Combine object's visibility with all possible internal run-time
* determined flags which denotes trace-time visibility.
@ -95,7 +100,6 @@ public:
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_transforms(DeviceScene *dscene,
Scene *scene,
uint *object_flag,
Progress& progress);
void device_update_flags(Device *device,
@ -109,49 +113,9 @@ public:
void tag_update(Scene *scene);
void apply_static_transforms(DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress);
void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress& progress);
protected:
/* Global state of object transform update. */
struct UpdateObjectTransformState {
/* Global state used by device_update_object_transform().
* Common for both threaded and non-threaded update.
*/
/* Type of the motion required by the scene settings. */
Scene::MotionType need_motion;
/* Mapping from particle system to a index in packed particle array.
* Only used for read.
*/
map<ParticleSystem*, int> particle_offset;
/* Mesh area.
* Used to avoid calculation of mesh area multiple times. Used for both
* read and write. Acquire surface_area_lock to keep it all thread safe.
*/
map<Mesh*, float> surface_area_map;
/* Packed object arrays. Those will be filled in. */
uint *object_flag;
float4 *objects;
float4 *objects_vector;
/* Flags which will be synchronized to Integrator. */
bool have_motion;
bool have_curves;
/* ** Scheduling queue. ** */
Scene *scene;
/* Some locks to keep everything thread-safe. */
thread_spin_lock queue_lock;
thread_spin_lock surface_area_lock;
/* First unused object index in the queue. */
int queue_start_object;
};
void device_update_object_transform(UpdateObjectTransformState *state,
Object *ob,
const int object_index);

View File

@ -34,6 +34,7 @@
#include "util/util_md5.h"
#include "util/util_path.h"
#include "util/util_progress.h"
#include "util/util_projection.h"
#endif
@ -832,7 +833,9 @@ void OSLCompiler::parameter(ShaderNode* node, const char *name)
case SocketType::TRANSFORM:
{
Transform value = node->get_transform(socket);
ss->Parameter(uname, TypeDesc::TypeMatrix, &value);
ProjectionTransform projection(value);
projection = projection_transpose(projection);
ss->Parameter(uname, TypeDesc::TypeMatrix, &projection);
break;
}
case SocketType::BOOLEAN_ARRAY:
@ -900,7 +903,11 @@ void OSLCompiler::parameter(ShaderNode* node, const char *name)
case SocketType::TRANSFORM_ARRAY:
{
const array<Transform>& value = node->get_transform_array(socket);
ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, value.size()), value.data());
array<ProjectionTransform> fvalue(value.size());
for(size_t i = 0; i < value.size(); i++) {
fvalue[i] = projection_transpose(ProjectionTransform(value[i]));
}
ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, fvalue.size()), fvalue.data());
break;
}
case SocketType::CLOSURE:
@ -967,7 +974,9 @@ void OSLCompiler::parameter(const char *name, ustring s)
void OSLCompiler::parameter(const char *name, const Transform& tfm)
{
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&tfm);
ProjectionTransform projection(tfm);
projection = projection_transpose(projection);
ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&projection);
}
void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)

View File

@ -62,14 +62,10 @@ void ParticleSystemManager::device_update_particles(Device *, DeviceScene *dscen
for(size_t j = 0; j < scene->particle_systems.size(); j++)
num_particles += scene->particle_systems[j]->particles.size();
float4 *particles = dscene->particles.alloc(PARTICLE_SIZE*num_particles);
KernelParticle *kparticles = dscene->particles.alloc(num_particles);
/* dummy particle */
particles[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
particles[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
particles[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
particles[3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
particles[4] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
memset(kparticles, 0, sizeof(KernelParticle));
int i = 1;
for(size_t j = 0; j < scene->particle_systems.size(); j++) {
@ -78,13 +74,15 @@ void ParticleSystemManager::device_update_particles(Device *, DeviceScene *dscen
for(size_t k = 0; k < psys->particles.size(); k++) {
/* pack in texture */
Particle& pa = psys->particles[k];
int offset = i*PARTICLE_SIZE;
particles[offset] = make_float4(__uint_as_float(pa.index), pa.age, pa.lifetime, pa.size);
particles[offset+1] = pa.rotation;
particles[offset+2] = make_float4(pa.location.x, pa.location.y, pa.location.z, pa.velocity.x);
particles[offset+3] = make_float4(pa.velocity.y, pa.velocity.z, pa.angular_velocity.x, pa.angular_velocity.y);
particles[offset+4] = make_float4(pa.angular_velocity.z, 0.0f, 0.0f, 0.0f);
kparticles[i].index = pa.index;
kparticles[i].age = pa.age;
kparticles[i].lifetime = pa.lifetime;
kparticles[i].size = pa.size;
kparticles[i].rotation = pa.rotation;
kparticles[i].location = float3_to_float4(pa.location);
kparticles[i].velocity = float3_to_float4(pa.velocity);
kparticles[i].angular_velocity = float3_to_float4(pa.angular_velocity);
i++;

View File

@ -60,19 +60,21 @@ DeviceScene::DeviceScene(Device *device)
curve_keys(device, "__curve_keys", MEM_TEXTURE),
patches(device, "__patches", MEM_TEXTURE),
objects(device, "__objects", MEM_TEXTURE),
objects_vector(device, "__objects_vector", MEM_TEXTURE),
object_motion_pass(device, "__object_motion_pass", MEM_TEXTURE),
object_motion(device, "__object_motion", MEM_TEXTURE),
object_flag(device, "__object_flag", MEM_TEXTURE),
camera_motion(device, "__camera_motion", MEM_TEXTURE),
attributes_map(device, "__attributes_map", MEM_TEXTURE),
attributes_float(device, "__attributes_float", MEM_TEXTURE),
attributes_float3(device, "__attributes_float3", MEM_TEXTURE),
attributes_uchar4(device, "__attributes_uchar4", MEM_TEXTURE),
light_distribution(device, "__light_distribution", MEM_TEXTURE),
light_data(device, "__light_data", MEM_TEXTURE),
lights(device, "__lights", MEM_TEXTURE),
light_background_marginal_cdf(device, "__light_background_marginal_cdf", MEM_TEXTURE),
light_background_conditional_cdf(device, "__light_background_conditional_cdf", MEM_TEXTURE),
particles(device, "__particles", MEM_TEXTURE),
svm_nodes(device, "__svm_nodes", MEM_TEXTURE),
shader_flag(device, "__shader_flag", MEM_TEXTURE),
object_flag(device, "__object_flag", MEM_TEXTURE),
shaders(device, "__shaders", MEM_TEXTURE),
lookup_table(device, "__lookup_table", MEM_TEXTURE),
sobol_directions(device, "__sobol_directions", MEM_TEXTURE)
{

View File

@ -86,8 +86,13 @@ public:
device_vector<uint> patches;
/* objects */
device_vector<float4> objects;
device_vector<float4> objects_vector;
device_vector<KernelObject> objects;
device_vector<Transform> object_motion_pass;
device_vector<DecomposedTransform> object_motion;
device_vector<uint> object_flag;
/* cameras */
device_vector<DecomposedTransform> camera_motion;
/* attributes */
device_vector<uint4> attributes_map;
@ -96,18 +101,17 @@ public:
device_vector<uchar4> attributes_uchar4;
/* lights */
device_vector<float4> light_distribution;
device_vector<float4> light_data;
device_vector<KernelLightDistribution> light_distribution;
device_vector<KernelLight> lights;
device_vector<float2> light_background_marginal_cdf;
device_vector<float2> light_background_conditional_cdf;
/* particles */
device_vector<float4> particles;
device_vector<KernelParticle> particles;
/* shaders */
device_vector<int4> svm_nodes;
device_vector<uint> shader_flag;
device_vector<uint> object_flag;
device_vector<KernelShader> shaders;
/* lookup tables */
device_vector<float> lookup_table;

View File

@ -656,13 +656,13 @@ DeviceRequestedFeatures Session::get_requested_device_features()
*/
requested_features.use_hair = false;
requested_features.use_object_motion = false;
requested_features.use_camera_motion = scene->camera->use_motion;
requested_features.use_camera_motion = scene->camera->use_motion();
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
if(mesh->num_curves()) {
requested_features.use_hair = true;
}
requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur;
requested_features.use_object_motion |= object->use_motion() | mesh->use_motion_blur;
requested_features.use_camera_motion |= mesh->use_motion_blur;
#ifdef WITH_OPENSUBDIV
if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) {

View File

@ -432,14 +432,12 @@ void ShaderManager::device_update_common(Device *device,
Scene *scene,
Progress& /*progress*/)
{
dscene->shader_flag.free();
dscene->shaders.free();
if(scene->shaders.size() == 0)
return;
uint shader_flag_size = scene->shaders.size()*SHADER_SIZE;
uint *shader_flag = dscene->shader_flag.alloc(shader_flag_size);
uint i = 0;
KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size());
bool has_volumes = false;
bool has_transparent_shadow = false;
@ -487,16 +485,17 @@ void ShaderManager::device_update_common(Device *device,
flag |= SD_HAS_CONSTANT_EMISSION;
/* regular shader */
shader_flag[i++] = flag;
shader_flag[i++] = shader->pass_id;
shader_flag[i++] = __float_as_int(constant_emission.x);
shader_flag[i++] = __float_as_int(constant_emission.y);
shader_flag[i++] = __float_as_int(constant_emission.z);
kshader->flags = flag;
kshader->pass_id = shader->pass_id;
kshader->constant_emission[0] = constant_emission.x;
kshader->constant_emission[1] = constant_emission.y;
kshader->constant_emission[2] = constant_emission.z;
kshader++;
has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
}
dscene->shader_flag.copy_to_device();
dscene->shaders.copy_to_device();
/* lookup tables */
KernelTables *ktables = &dscene->data.tables;
@ -525,7 +524,7 @@ void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *sce
{
scene->lookup_tables->remove_table(&beckmann_table_offset);
dscene->shader_flag.free();
dscene->shaders.free();
}
void ShaderManager::add_default(Scene *scene)

View File

@ -67,6 +67,7 @@ set(SRC_HEADERS
util_param.h
util_path.h
util_progress.h
util_projection.h
util_queue.h
util_rect.h
util_set.h

View File

@ -0,0 +1,177 @@
/*
* Copyright 2011-2018 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __UTIL_PROJECTION_H__
#define __UTIL_PROJECTION_H__
#include "util/util_transform.h"
CCL_NAMESPACE_BEGIN
/* 4x4 projection matrix, perspective or orthographic. */
typedef struct ProjectionTransform {
float4 x, y, z, w; /* rows */
#ifndef __KERNEL_GPU__
ProjectionTransform()
{
}
explicit ProjectionTransform(const Transform& tfm)
: x(tfm.x),
y(tfm.y),
z(tfm.z),
w(make_float4(0.0f, 0.0f, 0.0f, 1.0f))
{
}
#endif
} ProjectionTransform;
typedef struct PerspectiveMotionTransform {
ProjectionTransform pre;
ProjectionTransform post;
} PerspectiveMotionTransform;
/* Functions */
ccl_device_inline float3 transform_perspective(const ProjectionTransform *t, const float3 a)
{
float4 b = make_float4(a.x, a.y, a.z, 1.0f);
float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
float w = dot(t->w, b);
return (w != 0.0f)? c/w: make_float3(0.0f, 0.0f, 0.0f);
}
ccl_device_inline float3 transform_perspective_direction(const ProjectionTransform *t, const float3 a)
{
float3 c = make_float3(
a.x*t->x.x + a.y*t->x.y + a.z*t->x.z,
a.x*t->y.x + a.y*t->y.y + a.z*t->y.z,
a.x*t->z.x + a.y*t->z.y + a.z*t->z.z);
return c;
}
#ifndef __KERNEL_GPU__
ccl_device_inline Transform projection_to_transform(const ProjectionTransform& a)
{
Transform tfm = {a.x, a.y, a.z};
return tfm;
}
ccl_device_inline ProjectionTransform projection_transpose(const ProjectionTransform& a)
{
ProjectionTransform t;
t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
return t;
}
ProjectionTransform projection_inverse(const ProjectionTransform& a);
ccl_device_inline ProjectionTransform make_projection(
float a, float b, float c, float d,
float e, float f, float g, float h,
float i, float j, float k, float l,
float m, float n, float o, float p)
{
ProjectionTransform t;
t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
return t;
}
ccl_device_inline ProjectionTransform projection_identity()
{
return make_projection(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
}
ccl_device_inline ProjectionTransform operator*(const ProjectionTransform& a, const ProjectionTransform& b)
{
ProjectionTransform c = projection_transpose(b);
ProjectionTransform t;
t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
return t;
}
ccl_device_inline ProjectionTransform operator*(const ProjectionTransform& a, const Transform& b)
{
return a * ProjectionTransform(b);
}
ccl_device_inline ProjectionTransform operator*(const Transform& a, const ProjectionTransform& b)
{
return ProjectionTransform(a) * b;
}
ccl_device_inline void print_projection(const char *label, const ProjectionTransform& t)
{
print_float4(label, t.x);
print_float4(label, t.y);
print_float4(label, t.z);
print_float4(label, t.w);
printf("\n");
}
ccl_device_inline ProjectionTransform projection_perspective(float fov, float n, float f)
{
ProjectionTransform persp = make_projection(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, f / (f - n), -f*n / (f - n),
0, 0, 1, 0);
float inv_angle = 1.0f/tanf(0.5f*fov);
Transform scale = transform_scale(inv_angle, inv_angle, 1);
return scale * persp;
}
ccl_device_inline ProjectionTransform projection_orthographic(float znear, float zfar)
{
Transform t =
transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
transform_translate(0.0f, 0.0f, -znear);
return ProjectionTransform(t);
}
#endif /* __KERNEL_GPU__ */
CCL_NAMESPACE_END
#endif /* __UTIL_PROJECTION_H__ */

View File

@ -46,6 +46,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "util/util_projection.h"
#include "util/util_transform.h"
#include "util/util_boundbox.h"
@ -129,9 +130,9 @@ static bool transform_matrix4_gj_inverse(float R[][4], float M[][4])
return true;
}
Transform transform_inverse(const Transform& tfm)
ProjectionTransform projection_inverse(const ProjectionTransform& tfm)
{
Transform tfmR = transform_identity();
ProjectionTransform tfmR = projection_identity();
float M[4][4], R[4][4];
memcpy(R, &tfmR, sizeof(R));
@ -145,7 +146,7 @@ Transform transform_inverse(const Transform& tfm)
M[2][2] += 1e-8f;
if(UNLIKELY(!transform_matrix4_gj_inverse(R, M))) {
return transform_identity();
return projection_identity();
}
}
@ -154,6 +155,19 @@ Transform transform_inverse(const Transform& tfm)
return tfmR;
}
Transform transform_inverse(const Transform& tfm)
{
ProjectionTransform projection(tfm);
return projection_to_transform(projection_inverse(projection));
}
Transform transform_transposed_inverse(const Transform& tfm)
{
ProjectionTransform projection(tfm);
ProjectionTransform iprojection = projection_inverse(projection);
return projection_to_transform(projection_transpose(iprojection));
}
/* Motion Transform */
float4 transform_to_quat(const Transform& tfm)
@ -202,14 +216,14 @@ float4 transform_to_quat(const Transform& tfm)
return qt;
}
static void transform_decompose(Transform *decomp, const Transform *tfm)
static void transform_decompose(DecomposedTransform *decomp, const Transform *tfm)
{
/* extract translation */
decomp->y = make_float4(tfm->x.w, tfm->y.w, tfm->z.w, 0.0f);
/* extract rotation */
Transform M = *tfm;
M.x.w = 0.0f; M.y.w = 0.0f; M.z.w = 0.0f; M.w.w = 1.0f;
M.x.w = 0.0f; M.y.w = 0.0f; M.z.w = 0.0f;
Transform R = M;
float norm;
@ -217,9 +231,9 @@ static void transform_decompose(Transform *decomp, const Transform *tfm)
do {
Transform Rnext;
Transform Rit = transform_inverse(transform_transpose(R));
Transform Rit = transform_transposed_inverse(R);
for(int i = 0; i < 4; i++)
for(int i = 0; i < 3; i++)
for(int j = 0; j < 4; j++)
Rnext[i][j] = 0.5f * (R[i][j] + Rit[i][j]);
@ -247,18 +261,18 @@ static void transform_decompose(Transform *decomp, const Transform *tfm)
decomp->w = make_float4(scale.y.z, scale.z.x, scale.z.y, scale.z.z);
}
void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion, const Transform *mid)
void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size)
{
transform_decompose(&decomp->pre, &motion->pre);
transform_decompose(&decomp->mid, mid);
transform_decompose(&decomp->post, &motion->post);
for(size_t i = 0; i < size; i++) {
transform_decompose(decomp + i, motion + i);
/* ensure rotation around shortest angle, negated quaternions are the same
* but this means we don't have to do the check in quat_interpolate */
if(dot(decomp->pre.x, decomp->mid.x) < 0.0f)
decomp->pre.x = -decomp->pre.x;
if(dot(decomp->mid.x, decomp->post.x) < 0.0f)
decomp->mid.x = -decomp->mid.x;
if(i > 0) {
/* Ensure rotation around shortest angle, negated quaternions are the same
* but this means we don't have to do the check in quat_interpolate */
if(dot(decomp[i-1].x, decomp[i].x) < 0.0f)
decomp[i-1].x = -decomp[i-1].x;
}
}
}
Transform transform_from_viewplane(BoundBox2D& viewplane)

View File

@ -26,10 +26,10 @@
CCL_NAMESPACE_BEGIN
/* Data Types */
/* Affine transformation, stored as 4x3 matrix. */
typedef struct Transform {
float4 x, y, z, w; /* rows */
float4 x, y, z;
#ifndef __KERNEL_GPU__
float4 operator[](int i) const { return *(&x + i); }
@ -37,32 +37,16 @@ typedef struct Transform {
#endif
} Transform;
/* transform decomposed in rotation/translation/scale. we use the same data
/* Transform decomposed in rotation/translation/scale. we use the same data
* structure as Transform, and tightly pack decomposition into it. first the
* rotation (4), then translation (3), then 3x3 scale matrix (9). */
typedef struct ccl_may_alias MotionTransform {
Transform pre;
Transform mid;
Transform post;
} MotionTransform;
typedef struct PerspectiveMotionTransform {
Transform pre;
Transform post;
} PerspectiveMotionTransform;
typedef struct DecomposedTransform {
float4 x, y, z, w;
} DecomposedTransform;
/* Functions */
ccl_device_inline float3 transform_perspective(const Transform *t, const float3 a)
{
float4 b = make_float4(a.x, a.y, a.z, 1.0f);
float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
float w = dot(t->w, b);
return (w != 0.0f)? c/w: make_float3(0.0f, 0.0f, 0.0f);
}
ccl_device_inline float3 transform_point(const Transform *t, const float3 a)
{
/* TODO(sergey): Disabled for now, causes crashes in certain cases. */
@ -73,7 +57,7 @@ ccl_device_inline float3 transform_point(const Transform *t, const float3 a)
x = _mm_loadu_ps(&t->x.x);
y = _mm_loadu_ps(&t->y.x);
z = _mm_loadu_ps(&t->z.x);
w = _mm_loadu_ps(&t->w.x);
w = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
_MM_TRANSPOSE4_PS(x, y, z, w);
@ -129,29 +113,15 @@ ccl_device_inline float3 transform_direction_transposed(const Transform *t, cons
return make_float3(dot(x, a), dot(y, a), dot(z, a));
}
ccl_device_inline Transform transform_transpose(const Transform a)
{
Transform t;
t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
return t;
}
ccl_device_inline Transform make_transform(float a, float b, float c, float d,
float e, float f, float g, float h,
float i, float j, float k, float l,
float m, float n, float o, float p)
float i, float j, float k, float l)
{
Transform t;
t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
return t;
}
@ -165,21 +135,22 @@ ccl_device_inline Transform make_transform_frame(float3 N)
const float3 dy = normalize(cross(N, dx));
return make_transform(dx.x, dx.y, dx.z, 0.0f,
dy.x, dy.y, dy.z, 0.0f,
N.x , N.y, N.z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
N.x , N.y, N.z, 0.0f);
}
#ifndef __KERNEL_GPU__
ccl_device_inline Transform operator*(const Transform a, const Transform b)
{
Transform c = transform_transpose(b);
Transform t;
float4 c_x = make_float4(b.x.x, b.y.x, b.z.x, 0.0f);
float4 c_y = make_float4(b.x.y, b.y.y, b.z.y, 0.0f);
float4 c_z = make_float4(b.x.z, b.y.z, b.z.z, 0.0f);
float4 c_w = make_float4(b.x.w, b.y.w, b.z.w, 1.0f);
t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
Transform t;
t.x = make_float4(dot(a.x, c_x), dot(a.x, c_y), dot(a.x, c_z), dot(a.x, c_w));
t.y = make_float4(dot(a.y, c_x), dot(a.y, c_y), dot(a.y, c_z), dot(a.y, c_w));
t.z = make_float4(dot(a.z, c_x), dot(a.z, c_y), dot(a.z, c_z), dot(a.z, c_w));
return t;
}
@ -189,7 +160,6 @@ ccl_device_inline void print_transform(const char *label, const Transform& t)
print_float4(label, t.x);
print_float4(label, t.y);
print_float4(label, t.z);
print_float4(label, t.w);
printf("\n");
}
@ -198,8 +168,7 @@ ccl_device_inline Transform transform_translate(float3 t)
return make_transform(
1, 0, 0, t.x,
0, 1, 0, t.y,
0, 0, 1, t.z,
0, 0, 0, 1);
0, 0, 1, t.z);
}
ccl_device_inline Transform transform_translate(float x, float y, float z)
@ -212,8 +181,7 @@ ccl_device_inline Transform transform_scale(float3 s)
return make_transform(
s.x, 0, 0, 0,
0, s.y, 0, 0,
0, 0, s.z, 0,
0, 0, 0, 1);
0, 0, s.z, 0);
}
ccl_device_inline Transform transform_scale(float x, float y, float z)
@ -221,21 +189,6 @@ ccl_device_inline Transform transform_scale(float x, float y, float z)
return transform_scale(make_float3(x, y, z));
}
ccl_device_inline Transform transform_perspective(float fov, float n, float f)
{
Transform persp = make_transform(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, f / (f - n), -f*n / (f - n),
0, 0, 1, 0);
float inv_angle = 1.0f/tanf(0.5f*fov);
Transform scale = transform_scale(inv_angle, inv_angle, 1);
return scale * persp;
}
ccl_device_inline Transform transform_rotate(float angle, float3 axis)
{
float s = sinf(angle);
@ -258,9 +211,7 @@ ccl_device_inline Transform transform_rotate(float angle, float3 axis)
axis.z*axis.x*t - s*axis.y,
axis.z*axis.y*t + s*axis.x,
axis.z*axis.z*t + c,
0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
0.0f);
}
/* Euler is assumed to be in XYZ order. */
@ -272,12 +223,6 @@ ccl_device_inline Transform transform_euler(float3 euler)
transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f));
}
ccl_device_inline Transform transform_orthographic(float znear, float zfar)
{
return transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
transform_translate(0.0f, 0.0f, -znear);
}
ccl_device_inline Transform transform_identity()
{
return transform_scale(1.0f, 1.0f, 1.0f);
@ -306,20 +251,20 @@ ccl_device_inline void transform_set_column(Transform *t, int column, float3 val
}
Transform transform_inverse(const Transform& a);
Transform transform_transposed_inverse(const Transform& a);
ccl_device_inline bool transform_uniform_scale(const Transform& tfm, float& scale)
{
/* the epsilon here is quite arbitrary, but this function is only used for
* surface area and bump, where we except it to not be so sensitive */
Transform ttfm = transform_transpose(tfm);
* surface area and bump, where we expect it to not be so sensitive */
float eps = 1e-6f;
float sx = len_squared(float4_to_float3(tfm.x));
float sy = len_squared(float4_to_float3(tfm.y));
float sz = len_squared(float4_to_float3(tfm.z));
float stx = len_squared(float4_to_float3(ttfm.x));
float sty = len_squared(float4_to_float3(ttfm.y));
float stz = len_squared(float4_to_float3(ttfm.z));
float stx = len_squared(transform_get_column(&tfm, 0));
float sty = len_squared(transform_get_column(&tfm, 1));
float stz = len_squared(transform_get_column(&tfm, 2));
if(fabsf(sx - sy) < eps && fabsf(sx - sz) < eps &&
fabsf(sx - stx) < eps && fabsf(sx - sty) < eps &&
@ -355,7 +300,6 @@ ccl_device_inline Transform transform_clear_scale(const Transform& tfm)
ccl_device_inline Transform transform_empty()
{
return make_transform(
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0);
@ -414,12 +358,11 @@ ccl_device_inline Transform transform_quick_inverse(Transform M)
R.x = make_float4(Rx.x, Rx.y, Rx.z, dot(Rx, T));
R.y = make_float4(Ry.x, Ry.y, Ry.z, dot(Ry, T));
R.z = make_float4(Rz.x, Rz.y, Rz.z, dot(Rz, T));
R.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
return R;
}
ccl_device_inline void transform_compose(Transform *tfm, const Transform *decomp)
ccl_device_inline void transform_compose(Transform *tfm, const DecomposedTransform *decomp)
{
/* rotation */
float q0, q1, q2, q3, qda, qdb, qdc, qaa, qab, qac, qbb, qbc, qcc;
@ -452,60 +395,30 @@ ccl_device_inline void transform_compose(Transform *tfm, const Transform *decomp
tfm->x = make_float4(dot(rotation_x, scale_x), dot(rotation_x, scale_y), dot(rotation_x, scale_z), decomp->y.x);
tfm->y = make_float4(dot(rotation_y, scale_x), dot(rotation_y, scale_y), dot(rotation_y, scale_z), decomp->y.y);
tfm->z = make_float4(dot(rotation_z, scale_x), dot(rotation_z, scale_y), dot(rotation_z, scale_z), decomp->y.z);
tfm->w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
}
/* Disabled for now, need arc-length parametrization for constant speed motion.
* #define CURVED_MOTION_INTERPOLATE */
ccl_device void transform_motion_interpolate(Transform *tfm, const MotionTransform *motion, float t)
/* Interpolate from array of decomposed transforms. */
ccl_device void transform_motion_array_interpolate(Transform *tfm,
const ccl_global DecomposedTransform *motion,
uint numsteps,
float time)
{
/* possible optimization: is it worth it adding a check to skip scaling?
* it's probably quite uncommon to have scaling objects. or can we skip
* just shearing perhaps? */
Transform decomp;
/* Figure out which steps we need to interpolate. */
int maxstep = numsteps-1;
int step = min((int)(time*maxstep), maxstep-1);
float t = time*maxstep - step;
#ifdef CURVED_MOTION_INTERPOLATE
/* 3 point bezier curve interpolation for position */
float3 Ppre = float4_to_float3(motion->pre.y);
float3 Pmid = float4_to_float3(motion->mid.y);
float3 Ppost = float4_to_float3(motion->post.y);
const ccl_global DecomposedTransform *a = motion + step;
const ccl_global DecomposedTransform *b = motion + step + 1;
float3 Pcontrol = 2.0f*Pmid - 0.5f*(Ppre + Ppost);
float3 P = Ppre*t*t + Pcontrol*2.0f*t*(1.0f - t) + Ppost*(1.0f - t)*(1.0f - t);
/* Interpolate rotation, translation and scale. */
DecomposedTransform decomp;
decomp.x = quat_interpolate(a->x, b->x, t);
decomp.y = (1.0f - t)*a->y + t*b->y;
decomp.z = (1.0f - t)*a->z + t*b->z;
decomp.w = (1.0f - t)*a->w + t*b->w;
decomp.y.x = P.x;
decomp.y.y = P.y;
decomp.y.z = P.z;
#endif
/* linear interpolation for rotation and scale */
if(t < 0.5f) {
t *= 2.0f;
decomp.x = quat_interpolate(motion->pre.x, motion->mid.x, t);
#ifdef CURVED_MOTION_INTERPOLATE
decomp.y.w = (1.0f - t)*motion->pre.y.w + t*motion->mid.y.w;
#else
decomp.y = (1.0f - t)*motion->pre.y + t*motion->mid.y;
#endif
decomp.z = (1.0f - t)*motion->pre.z + t*motion->mid.z;
decomp.w = (1.0f - t)*motion->pre.w + t*motion->mid.w;
}
else {
t = (t - 0.5f)*2.0f;
decomp.x = quat_interpolate(motion->mid.x, motion->post.x, t);
#ifdef CURVED_MOTION_INTERPOLATE
decomp.y.w = (1.0f - t)*motion->mid.y.w + t*motion->post.y.w;
#else
decomp.y = (1.0f - t)*motion->mid.y + t*motion->post.y;
#endif
decomp.z = (1.0f - t)*motion->mid.z + t*motion->post.z;
decomp.w = (1.0f - t)*motion->mid.w + t*motion->post.w;
}
/* compose rotation, translation, scale into matrix */
/* Compose rotation, translation, scale into matrix. */
transform_compose(tfm, &decomp);
}
@ -513,13 +426,13 @@ ccl_device void transform_motion_interpolate(Transform *tfm, const MotionTransfo
class BoundBox2D;
ccl_device_inline bool operator==(const MotionTransform& A, const MotionTransform& B)
ccl_device_inline bool operator==(const DecomposedTransform& A, const DecomposedTransform& B)
{
return (A.pre == B.pre && A.post == B.post);
return memcmp(&A, &B, sizeof(DecomposedTransform)) == 0;
}
float4 transform_to_quat(const Transform& tfm);
void transform_motion_decompose(MotionTransform *decomp, const MotionTransform *motion, const Transform *mid);
void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size);
Transform transform_from_viewplane(BoundBox2D& viewplane);
#endif

View File

@ -215,6 +215,18 @@ public:
return data_;
}
T* resize(size_t newsize, const T& value)
{
size_t oldsize = size();
resize(newsize);
for(size_t i = oldsize; i < size(); i++) {
data_[i] = value;
}
return data_;
}
void clear()
{
if(data_ != NULL) {

View File

@ -48,6 +48,16 @@
#include <libswscale/swscale.h>
/* Stupid way to distinguish FFmpeg from Libav:
* - FFmpeg's MICRO version starts from 100 and goes up, while
* - Libav's micro is always below 100.
*/
#if LIBAVCODEC_VERSION_MICRO >= 100
# define AV_USING_FFMPEG
#else
# define AV_USING_LIBAV
#endif
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || ((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 105))
# define FFMPEG_HAVE_AVIO 1
#endif
@ -428,8 +438,45 @@ void av_frame_free(AVFrame **frame)
#endif
FFMPEG_INLINE
AVRational av_get_r_frame_rate_compat(const AVStream *stream)
const char* av_get_metadata_key_value(AVDictionary *metadata, const char *key)
{
if (metadata == NULL) {
return NULL;
}
AVDictionaryEntry *tag = NULL;
while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
if (!strcmp(tag->key, key)) {
return tag->value;
}
}
return NULL;
}
FFMPEG_INLINE
bool av_check_encoded_with_ffmpeg(AVFormatContext *ctx)
{
const char* encoder = av_get_metadata_key_value(ctx->metadata, "ENCODER");
if (encoder != NULL && !strncmp(encoder, "Lavf", 4)) {
return true;
}
return false;
}
FFMPEG_INLINE
AVRational av_get_r_frame_rate_compat(AVFormatContext *ctx,
const AVStream *stream)
{
/* If the video is encoded with FFmpeg and we are decoding with FFmpeg
* as well it seems to be more reliable to use r_frame_rate (tbr).
*
* For other cases we fall back to avg_frame_rate (fps) when possible.
*/
#ifdef AV_USING_FFMPEG
if (av_check_encoded_with_ffmpeg(ctx)) {
return stream->r_frame_rate;
}
#endif
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 23, 1)
/* For until r_frame_rate was deprecated use it. */
return stream->r_frame_rate;

@ -1 +1 @@
Subproject commit c93ed11a47b3016cf59711ec16de2e2e94c30e99
Subproject commit 469c949d1ca882be19daa128842f813b72a944d8

@ -1 +1 @@
Subproject commit 371960484a38fc64e0a2635170a41a0d8ab2f6bd
Subproject commit c88411ff7776a2db5d6ef6117a1b2faa42a95611

@ -1 +1 @@
Subproject commit a8515cfdfe9a98127b592f36fcbe51b7e23b969a
Subproject commit 310578043dec1aae382eb6a447ae1d103792d7e6

View File

@ -1521,12 +1521,15 @@ class USERPREF_PT_addons(Panel):
split.operator(
"wm.url_open", text="Documentation", icon='HELP',
).url = info["wiki_url"]
split.operator(
"wm.url_open", text="Report a Bug", icon='URL',
).url = info.get(
"tracker_url",
"https://developer.blender.org/maniphest/task/edit/form/2",
)
# Only add "Report a Bug" button if tracker_url is set
# or the add-on is bundled (use official tracker then).
if info.get("tracker_url") or not user_addon:
split.operator(
"wm.url_open", text="Report a Bug", icon='URL',
).url = info.get(
"tracker_url",
"https://developer.blender.org/maniphest/task/edit/form/2",
)
if user_addon:
split.operator(
"wm.addon_remove", text="Remove", icon='CANCEL',

View File

@ -834,7 +834,6 @@ typedef struct tPoseLib_PreviewData {
bAction *act; /* poselib to use */
TimeMarker *marker; /* 'active' pose */
int selcount; /* number of selected elements to work on */
int totcount; /* total number of elements to work on */
short state; /* state of main loop */
@ -867,7 +866,8 @@ enum {
/* defines for tPoseLib_PreviewData->flag values */
enum {
PL_PREVIEW_FIRSTTIME = (1 << 0),
PL_PREVIEW_SHOWORIGINAL = (1 << 1)
PL_PREVIEW_SHOWORIGINAL = (1 << 1),
PL_PREVIEW_ANY_BONE_SELECTED = (1 << 2),
};
/* ---------------------------- */
@ -887,7 +887,20 @@ static void poselib_backup_posecopy(tPoseLib_PreviewData *pld)
{
bActionGroup *agrp;
bPoseChannel *pchan;
bool selected = false;
/* determine whether any bone is selected. */
LISTBASE_FOREACH (bPoseChannel *, bchan, &pld->pose->chanbase) {
selected = bchan->bone != NULL && bchan->bone->flag & BONE_SELECTED;
if (selected) {
pld->flag |= PL_PREVIEW_ANY_BONE_SELECTED;
break;
}
}
if (!selected) {
pld->flag &= ~PL_PREVIEW_ANY_BONE_SELECTED;
}
/* for each posechannel that has an actionchannel in */
for (agrp = pld->act->groups.first; agrp; agrp = agrp->next) {
/* try to find posechannel */
@ -909,8 +922,6 @@ static void poselib_backup_posecopy(tPoseLib_PreviewData *pld)
BLI_addtail(&pld->backups, plb);
/* mark as being affected */
if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))
pld->selcount++;
pld->totcount++;
}
}
@ -971,6 +982,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
KeyframeEditData ked = {{NULL}};
KeyframeEditFunc group_ok_cb;
int frame = 1;
const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
/* get the frame */
if (pld->marker)
@ -983,8 +995,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
group_ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
ked.f1 = ((float)frame) - 0.5f;
ked.f2 = ((float)frame) + 0.5f;
/* start applying - only those channels which have a key at this point in time! */
for (agrp = act->groups.first; agrp; agrp = agrp->next) {
/* check if group has any keyframes */
@ -996,7 +1007,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
bool ok = 0;
/* check if this bone should get any animation applied */
if (pld->selcount == 0) {
if (!any_bone_selected) {
/* if no bones are selected, then any bone is ok */
ok = 1;
}
@ -1009,7 +1020,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
ok = 1;
}
}
if (ok)
animsys_evaluate_action_group(ptr, act, agrp, NULL, (float)frame);
}
@ -1028,14 +1039,15 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
ListBase dsources = {NULL, NULL};
bool autokey = autokeyframe_cfra_can_key(scene, &pld->ob->id);
const bool any_bone_selected = pld->flag & PL_PREVIEW_ANY_BONE_SELECTED;
/* start tagging/keying */
for (agrp = act->groups.first; agrp; agrp = agrp->next) {
/* only for selected bones unless there aren't any selected, in which case all are included */
pchan = BKE_pose_channel_find_name(pose, agrp->name);
if (pchan) {
if ((pld->selcount == 0) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
if (!any_bone_selected || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
if (autokey) {
/* add datasource override for the PoseChannel, to be used later */
ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan);

View File

@ -3229,7 +3229,7 @@ void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec
vec4 value = texture(tex, cos).rgba;
/* Density is premultiplied for interpolation, divide it out here. */
if (value.a > 0.0)
if (value.a > 1e-8)
value.rgb /= value.a;
outvec = value.rgb;

View File

@ -511,7 +511,7 @@ static int startffmpeg(struct anim *anim)
return -1;
}
frame_rate = av_get_r_frame_rate_compat(pFormatCtx->streams[videoStream]);
frame_rate = av_get_r_frame_rate_compat(pFormatCtx, pFormatCtx->streams[videoStream]);
if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
}
@ -989,7 +989,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
v_st = anim->pFormatCtx->streams[anim->videoStream];
frame_rate = av_q2d(av_get_r_frame_rate_compat(v_st));
frame_rate = av_q2d(av_get_r_frame_rate_compat(anim->pFormatCtx, v_st));
st_time = anim->pFormatCtx->start_time;
pts_time_base = av_q2d(v_st->time_base);

View File

@ -909,7 +909,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
stream_size = avio_size(context->iFormatCtx->pb);
context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iStream));
context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iFormatCtx, context->iStream));
context->pts_time_base = av_q2d(context->iStream->time_base);
while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {

View File

@ -1621,14 +1621,13 @@ static bool exr_has_alpha(MultiPartInputFile& file)
static bool imb_exr_is_multilayer_file(MultiPartInputFile& file)
{
const StringAttribute *comments = file.header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
const ChannelList& channels = file.header(0).channels();
std::set <std::string> layerNames;
/* will not include empty layer names */
channels.layers(layerNames);
if (comments || layerNames.size() > 1)
if (layerNames.size() > 1)
return true;
if (layerNames.size()) {
@ -1667,7 +1666,7 @@ static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
}
else {
*r_singlelayer = false;
*r_multilayer = true;
*r_multilayer = (layerNames.size() > 1);
*r_multiview = false;
return;
}

View File

@ -228,7 +228,7 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
codecCtx->frame_rate_base=1000;
m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base;
#else
m_baseFrameRate = av_q2d(av_get_r_frame_rate_compat(formatCtx->streams[videoStream]));
m_baseFrameRate = av_q2d(av_get_r_frame_rate_compat(formatCtx, formatCtx->streams[videoStream]));
#endif
if (m_baseFrameRate <= 0.0)
m_baseFrameRate = defFrameRate;

@ -1 +1 @@
Subproject commit b11375e89061303401376f7aeae42ac2fd64692a
Subproject commit 7695e14cfc5820ac66546e0e515914d85ab81af3

View File

@ -27,6 +27,7 @@
set(USE_EXPERIMENTAL_TESTS FALSE)
set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests)
set(TEST_DATA_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests_data)
set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests)
# ugh, any better way to do this on testing only?
@ -617,5 +618,14 @@ if(WITH_ALEMBIC)
)
endif()
add_subdirectory(view_layer)
if(WITH_CODEC_FFMPEG)
add_python_test(
ffmpeg_tests
${CMAKE_CURRENT_LIST_DIR}/ffmpeg_tests.py
--blender "$<TARGET_FILE:blender>"
--testdir "${TEST_DATA_SRC_DIR}/ffmpeg"
)
endif()
add_subdirectory(collada)
add_subdirectory(view_layer)

86
tests/python/ffmpeg_tests.py Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env python3
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import argparse
import functools
import shutil
import pathlib
import subprocess
import sys
import tempfile
import unittest
from modules.test_utils import AbstractBlenderRunnerTest
class AbstractFFmpegTest(AbstractBlenderRunnerTest):
@classmethod
def setUpClass(cls):
cls.blender = args.blender
cls.testdir = pathlib.Path(args.testdir)
class AbstractFFmpegSequencerTest(AbstractFFmpegTest):
def get_script_for_file(self, filename: pathlib.Path) -> str:
movie = self.testdir / filename
return \
"import bpy; " \
"bpy.context.scene.sequence_editor_create(); " \
"strip = bpy.context.scene.sequence_editor.sequences.new_movie(" \
"'test_movie', %r, channel=1, frame_start=1); " \
"print(f'fps:{strip.fps}')" % movie.as_posix()
def get_movie_file_fps(self, filename: pathlib.Path) -> float:
script = self.get_script_for_file(filename)
output = self.run_blender('', script)
for line in output.splitlines():
if line.startswith('fps:'):
return float(line.split(':')[1])
return 0.0
class FPSDetectionTest(AbstractFFmpegSequencerTest):
def test_T51153(self):
self.assertAlmostEqual(
self.get_movie_file_fps('T51153_bad_clip_2.mts'),
29.97,
places=2)
def test_T53857(self):
self.assertAlmostEqual(
self.get_movie_file_fps('T53857_2018-01-22_15-30-49.mkv'),
30.0,
places=2)
def test_T54148(self):
self.assertAlmostEqual(
self.get_movie_file_fps('T54148_magn_0.mkv'),
1.0,
places=2)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--blender', required=True)
parser.add_argument('--testdir', required=True)
args, remaining = parser.parse_known_args()
unittest.main(argv=sys.argv[0:1] + remaining)

View File

@ -75,18 +75,24 @@ class AbstractBlenderRunnerTest(unittest.TestCase):
assert self.blender, "Path to Blender binary is to be set in setUpClass()"
assert self.testdir, "Path to tests binary is to be set in setUpClass()"
blendfile = self.testdir / filepath
blendfile = self.testdir / filepath if filepath else ""
command = (
command = [
self.blender,
'--background',
'-noaudio',
'--factory-startup',
'--enable-autoexec',
str(blendfile),
]
if blendfile:
command.append(str(blendfile))
command.extend([
'-E', 'CYCLES',
'--python-exit-code', '47',
'--python-expr', python_script,
]
)
proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,