Cycles API: encapsulate Node socket members

This encapsulates Node socket members behind a set of specific methods;
as such it is no longer possible to directly access Node class members
from exporters and parts of Cycles.

The methods are defined via the NODE_SOCKET_API macros in `graph/
node.h`, and are for getting or setting a specific socket's value, as
well as querying or modifying the state of its update flag.

The setters will check whether the value has changed and tag the socket
as modified appropriately. This will let us know how a Node has changed
and what to update, which is the first concrete step toward a more
granular scene update system.

Since the setters will tag the Node sockets as modified when passed
different data, this patch also removes the various modified methods
on Nodes in favor of Node::is_modified which checks the sockets'
update flags status.

Reviewed By: brecht

Maniphest Tasks: T79174

Differential Revision: https://developer.blender.org/D8544
This commit is contained in:
Kévin Dietrich 2020-11-04 11:17:38 +01:00
parent a4a848d01b
commit 31a620b942
61 changed files with 2391 additions and 1785 deletions

@ -388,18 +388,19 @@ static void blender_camera_sync(Camera *cam,
const char *viewname,
PointerRNA *cscene)
{
/* copy camera to compare later */
Camera prevcam = *cam;
float aspectratio, sensor_size;
/* viewplane */
blender_camera_viewplane(bcam, width, height, &cam->viewplane, &aspectratio, &sensor_size);
BoundBox2D viewplane;
blender_camera_viewplane(bcam, width, height, &viewplane, &aspectratio, &sensor_size);
cam->width = bcam->full_width;
cam->height = bcam->full_height;
cam->set_viewplane_left(viewplane.left);
cam->set_viewplane_right(viewplane.right);
cam->set_viewplane_top(viewplane.top);
cam->set_viewplane_bottom(viewplane.bottom);
cam->full_width = width;
cam->full_height = height;
cam->set_full_width(width);
cam->set_full_height(height);
/* panorama sensor */
if (bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) {
@ -422,85 +423,91 @@ static void blender_camera_sync(Camera *cam,
}
if (horizontal_fit) {
cam->sensorwidth = sensor_size;
cam->sensorheight = sensor_size * fit_yratio / fit_xratio;
cam->set_sensorwidth(sensor_size);
cam->set_sensorheight(sensor_size * fit_yratio / fit_xratio);
}
else {
cam->sensorwidth = sensor_size * fit_xratio / fit_yratio;
cam->sensorheight = sensor_size;
cam->set_sensorwidth(sensor_size * fit_xratio / fit_yratio);
cam->set_sensorheight(sensor_size);
}
}
/* clipping distances */
cam->nearclip = bcam->nearclip;
cam->farclip = bcam->farclip;
cam->set_nearclip(bcam->nearclip);
cam->set_farclip(bcam->farclip);
/* type */
cam->type = bcam->type;
cam->set_camera_type(bcam->type);
/* panorama */
cam->panorama_type = bcam->panorama_type;
cam->fisheye_fov = bcam->fisheye_fov;
cam->fisheye_lens = bcam->fisheye_lens;
cam->latitude_min = bcam->latitude_min;
cam->latitude_max = bcam->latitude_max;
cam->set_panorama_type(bcam->panorama_type);
cam->set_fisheye_fov(bcam->fisheye_fov);
cam->set_fisheye_lens(bcam->fisheye_lens);
cam->set_latitude_min(bcam->latitude_min);
cam->set_latitude_max(bcam->latitude_max);
cam->longitude_min = bcam->longitude_min;
cam->longitude_max = bcam->longitude_max;
cam->set_longitude_min(bcam->longitude_min);
cam->set_longitude_max(bcam->longitude_max);
/* panorama stereo */
cam->interocular_distance = bcam->interocular_distance;
cam->convergence_distance = bcam->convergence_distance;
cam->use_spherical_stereo = bcam->use_spherical_stereo;
cam->set_interocular_distance(bcam->interocular_distance);
cam->set_convergence_distance(bcam->convergence_distance);
cam->set_use_spherical_stereo(bcam->use_spherical_stereo);
if (cam->use_spherical_stereo) {
if (cam->get_use_spherical_stereo()) {
if (strcmp(viewname, "left") == 0)
cam->stereo_eye = Camera::STEREO_LEFT;
cam->set_stereo_eye(Camera::STEREO_LEFT);
else if (strcmp(viewname, "right") == 0)
cam->stereo_eye = Camera::STEREO_RIGHT;
cam->set_stereo_eye(Camera::STEREO_RIGHT);
else
cam->stereo_eye = Camera::STEREO_NONE;
cam->set_stereo_eye(Camera::STEREO_NONE);
}
cam->use_pole_merge = bcam->use_pole_merge;
cam->pole_merge_angle_from = bcam->pole_merge_angle_from;
cam->pole_merge_angle_to = bcam->pole_merge_angle_to;
cam->set_use_pole_merge(bcam->use_pole_merge);
cam->set_pole_merge_angle_from(bcam->pole_merge_angle_from);
cam->set_pole_merge_angle_to(bcam->pole_merge_angle_to);
/* anamorphic lens bokeh */
cam->aperture_ratio = bcam->aperture_ratio;
cam->set_aperture_ratio(bcam->aperture_ratio);
/* perspective */
cam->fov = 2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio);
cam->focaldistance = bcam->focaldistance;
cam->aperturesize = bcam->aperturesize;
cam->blades = bcam->apertureblades;
cam->bladesrotation = bcam->aperturerotation;
cam->set_fov(2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio));
cam->set_focaldistance(bcam->focaldistance);
cam->set_aperturesize(bcam->aperturesize);
cam->set_blades(bcam->apertureblades);
cam->set_bladesrotation(bcam->aperturerotation);
/* transform */
cam->matrix = blender_camera_matrix(bcam->matrix, bcam->type, bcam->panorama_type);
cam->motion.clear();
cam->motion.resize(bcam->motion_steps, cam->matrix);
cam->use_perspective_motion = false;
cam->shuttertime = bcam->shuttertime;
cam->fov_pre = cam->fov;
cam->fov_post = cam->fov;
cam->motion_position = bcam->motion_position;
cam->set_matrix(blender_camera_matrix(bcam->matrix, bcam->type, bcam->panorama_type));
cam->rolling_shutter_type = bcam->rolling_shutter_type;
cam->rolling_shutter_duration = bcam->rolling_shutter_duration;
array<Transform> motion;
motion.resize(bcam->motion_steps, cam->get_matrix());
cam->set_motion(motion);
cam->set_use_perspective_motion(false);
cam->shutter_curve = bcam->shutter_curve;
cam->set_shuttertime(bcam->shuttertime);
cam->set_fov_pre(cam->get_fov());
cam->set_fov_post(cam->get_fov());
cam->set_motion_position(bcam->motion_position);
cam->set_rolling_shutter_type(bcam->rolling_shutter_type);
cam->set_rolling_shutter_duration(bcam->rolling_shutter_duration);
cam->set_shutter_curve(bcam->shutter_curve);
/* border */
cam->border = bcam->border;
cam->viewport_camera_border = bcam->viewport_camera_border;
cam->set_border_left(bcam->border.left);
cam->set_border_right(bcam->border.right);
cam->set_border_top(bcam->border.top);
cam->set_border_bottom(bcam->border.bottom);
cam->set_viewport_camera_border_left(bcam->viewport_camera_border.left);
cam->set_viewport_camera_border_right(bcam->viewport_camera_border.right);
cam->set_viewport_camera_border_top(bcam->viewport_camera_border.top);
cam->set_viewport_camera_border_bottom(bcam->viewport_camera_border.bottom);
bcam->offscreen_dicing_scale = RNA_float_get(cscene, "offscreen_dicing_scale");
cam->offscreen_dicing_scale = bcam->offscreen_dicing_scale;
/* set update flag */
if (cam->modified(prevcam))
cam->tag_update();
cam->set_offscreen_dicing_scale(bcam->offscreen_dicing_scale);
}
/* Sync Render Camera */
@ -582,22 +589,24 @@ void BlenderSync::sync_camera_motion(
Camera *cam = scene->camera;
BL::Array<float, 16> b_ob_matrix;
b_engine.camera_model_matrix(b_ob, cam->use_spherical_stereo, b_ob_matrix);
b_engine.camera_model_matrix(b_ob, cam->get_use_spherical_stereo(), b_ob_matrix);
Transform tfm = get_transform(b_ob_matrix);
tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type);
tfm = blender_camera_matrix(tfm, cam->get_camera_type(), cam->get_panorama_type());
if (motion_time == 0.0f) {
/* When motion blur is not centered in frame, cam->matrix gets reset. */
cam->matrix = tfm;
cam->set_matrix(tfm);
}
/* Set transform in motion array. */
int motion_step = cam->motion_step(motion_time);
if (motion_step >= 0) {
cam->motion[motion_step] = tfm;
array<Transform> motion = cam->get_motion();
motion[motion_step] = tfm;
cam->set_motion(motion);
}
if (cam->type == CAMERA_PERSPECTIVE) {
if (cam->get_camera_type() == CAMERA_PERSPECTIVE) {
BlenderCamera bcam;
float aspectratio, sensor_size;
blender_camera_init(&bcam, b_render);
@ -610,18 +619,18 @@ void BlenderSync::sync_camera_motion(
blender_camera_viewplane(&bcam, width, height, NULL, &aspectratio, &sensor_size);
/* TODO(sergey): De-duplicate calculation with camera sync. */
float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio);
if (fov != cam->fov) {
if (fov != cam->get_fov()) {
VLOG(1) << "Camera " << b_ob.name() << " FOV change detected.";
if (motion_time == 0.0f) {
cam->fov = fov;
cam->set_fov(fov);
}
else if (motion_time == -1.0f) {
cam->fov_pre = fov;
cam->use_perspective_motion = true;
cam->set_fov_pre(fov);
cam->set_use_perspective_motion(true);
}
else if (motion_time == 1.0f) {
cam->fov_post = fov;
cam->use_perspective_motion = true;
cam->set_fov_post(fov);
cam->set_use_perspective_motion(true);
}
}
}

@ -77,7 +77,7 @@ static bool ObtainCacheParticleData(
if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
(b_part.type() == BL::ParticleSettings::type_HAIR)) {
int shader = clamp(b_part.material() - 1, 0, hair->used_shaders.size() - 1);
int shader = clamp(b_part.material() - 1, 0, hair->get_used_shaders().size() - 1);
int display_step = background ? b_part.render_step() : b_part.display_step();
int totparts = b_psys.particles.length();
int totchild = background ? b_psys.child_particles.length() :
@ -307,7 +307,7 @@ static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CDa
VLOG(1) << "Exporting curve segments for mesh " << hair->name;
}
hair->reserve_curves(hair->num_curves() + num_curves, hair->curve_keys.size() + num_keys);
hair->reserve_curves(hair->num_curves() + num_curves, hair->get_curve_keys().size() + num_keys);
num_keys = 0;
num_curves = 0;
@ -350,7 +350,7 @@ static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CDa
}
/* check allocation */
if ((hair->curve_keys.size() != num_keys) || (hair->num_curves() != num_curves)) {
if ((hair->get_curve_keys().size() != num_keys) || (hair->num_curves() != num_curves)) {
VLOG(1) << "Allocation failed, clearing data";
hair->clear(true);
}
@ -402,7 +402,7 @@ static void export_hair_motion_validate_attribute(Hair *hair,
bool have_motion)
{
Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
const int num_keys = hair->curve_keys.size();
const int num_keys = hair->get_curve_keys().size();
if (num_motion_keys != num_keys || !have_motion) {
/* No motion or hair "topology" changed, remove attributes again. */
@ -423,8 +423,8 @@ static void export_hair_motion_validate_attribute(Hair *hair,
float4 *mP = attr_mP->data_float4() + step * num_keys;
for (int key = 0; key < num_keys; key++) {
mP[key] = float3_to_float4(hair->curve_keys[key]);
mP[key].w = hair->curve_radius[key];
mP[key] = float3_to_float4(hair->get_curve_keys()[key]);
mP[key].w = hair->get_curve_radius()[key];
}
}
}
@ -447,7 +447,7 @@ static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int
}
/* export motion vectors for curve keys */
size_t numkeys = hair->curve_keys.size();
size_t numkeys = hair->get_curve_keys().size();
float4 *mP = attr_mP->data_float4() + motion_step * numkeys;
bool have_motion = false;
int i = 0;
@ -458,24 +458,24 @@ static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int
curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys];
curve++) {
/* Curve lengths may not match! Curves can be clipped. */
int curve_key_end = (num_curves + 1 < (int)hair->curve_first_key.size() ?
hair->curve_first_key[num_curves + 1] :
(int)hair->curve_keys.size());
const int num_center_curve_keys = curve_key_end - hair->curve_first_key[num_curves];
int curve_key_end = (num_curves + 1 < (int)hair->get_curve_first_key().size() ?
hair->get_curve_first_key()[num_curves + 1] :
(int)hair->get_curve_keys().size());
const int num_center_curve_keys = curve_key_end - hair->get_curve_first_key()[num_curves];
const int is_num_keys_different = CData->curve_keynum[curve] - num_center_curve_keys;
if (!is_num_keys_different) {
for (int curvekey = CData->curve_firstkey[curve];
curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve];
curvekey++) {
if (i < hair->curve_keys.size()) {
if (i < hair->get_curve_keys().size()) {
mP[i] = CurveSegmentMotionCV(CData, sys, curve, curvekey);
if (!have_motion) {
/* unlike mesh coordinates, these tend to be slightly different
* between frames due to particle transforms into/out of object
* space, so we use an epsilon to detect actual changes */
float4 curve_key = float3_to_float4(hair->curve_keys[i]);
curve_key.w = hair->curve_radius[i];
float4 curve_key = float3_to_float4(hair->get_curve_keys()[i]);
curve_key.w = hair->get_curve_radius()[i];
if (len_squared(mP[i] - curve_key) > 1e-5f * 1e-5f)
have_motion = true;
}
@ -560,7 +560,7 @@ void BlenderSync::sync_particle_hair(
float3 *generated = attr_generated->data_float3();
for (size_t i = 0; i < hair->num_curves(); i++) {
float3 co = hair->curve_keys[hair->get_curve(i).first_key];
float3 co = hair->get_curve_keys()[hair->get_curve(i).first_key];
generated[i] = co * size - loc;
}
}
@ -742,7 +742,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
}
/* Export motion keys. */
const int num_keys = hair->curve_keys.size();
const int num_keys = hair->get_curve_keys().size();
float4 *mP = attr_mP->data_float4() + motion_step * num_keys;
bool have_motion = false;
int num_motion_keys = 0;
@ -769,8 +769,8 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
if (!have_motion) {
/* TODO: use epsilon for comparison? Was needed for particles due to
* transform, but ideally should not happen anymore. */
float4 curve_key = float3_to_float4(hair->curve_keys[i]);
curve_key.w = hair->curve_radius[i];
float4 curve_key = float3_to_float4(hair->get_curve_keys()[i]);
curve_key.w = hair->get_curve_radius()[i];
have_motion = !(mP[i] == curve_key);
}
}
@ -819,36 +819,46 @@ void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motio
void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair)
{
/* Compares curve_keys rather than strands in order to handle quick hair
* adjustments in dynamic BVH - other methods could probably do this better. */
array<float3> oldcurve_keys;
array<float> oldcurve_radius;
oldcurve_keys.steal_data(hair->curve_keys);
oldcurve_radius.steal_data(hair->curve_radius);
hair->clear(true);
Hair new_hair;
new_hair.set_used_shaders(hair->get_used_shaders());
if (view_layer.use_hair) {
if (b_ob.type() == BL::Object::type_HAIR) {
/* Hair object. */
sync_hair(hair, b_ob, false);
sync_hair(&new_hair, b_ob, false);
}
else {
/* Particle hair. */
bool need_undeformed = hair->need_attribute(scene, ATTR_STD_GENERATED);
bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED);
BL::Mesh b_mesh = object_to_mesh(
b_data, b_ob, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
if (b_mesh) {
sync_particle_hair(hair, b_mesh, b_ob, false);
sync_particle_hair(&new_hair, b_mesh, b_ob, false);
free_object_to_mesh(b_data, b_ob, b_mesh);
}
}
}
/* update original sockets */
for (const SocketType &socket : new_hair.type->inputs) {
/* Those sockets are updated in sync_object, so do not modify them. */
if (socket.name == "use_motion_blur" || socket.name == "motion_steps") {
continue;
}
hair->set_value(socket, new_hair, socket);
}
foreach (Attribute &attr, new_hair.attributes.attributes) {
hair->attributes.attributes.push_back(std::move(attr));
}
/* tag update */
const bool rebuild = ((oldcurve_keys != hair->curve_keys) ||
(oldcurve_radius != hair->curve_radius));
/* Compares curve_keys rather than strands in order to handle quick hair
* adjustments in dynamic BVH - other methods could probably do this better. */
const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
hair->tag_update(scene, rebuild);
}

@ -59,7 +59,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
GeometryKey key(b_key_id.ptr.data, geom_type);
/* Find shader indices. */
vector<Shader *> used_shaders;
array<Node *> used_shaders;
BL::Object::material_slots_iterator slot;
for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
@ -76,7 +76,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
if (material_override)
find_shader(material_override, used_shaders, default_shader);
else
used_shaders.push_back(default_shader);
used_shaders.push_back_slow(default_shader);
}
/* Ensure we only sync instanced geometry once. */
@ -114,7 +114,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
}
/* Test if shaders changed, these can be object level so geometry
* does not get tagged for recalc. */
else if (geom->used_shaders != used_shaders) {
else if (geom->get_used_shaders() != used_shaders) {
;
}
else {
@ -122,7 +122,8 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
* because the shader needs different geometry attributes. */
bool attribute_recalc = false;
foreach (Shader *shader, geom->used_shaders) {
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->need_update_geometry) {
attribute_recalc = true;
}
@ -139,7 +140,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
geom->name = ustring(b_ob_data.name().c_str());
/* Store the shaders immediately for the object attribute code. */
geom->used_shaders = used_shaders;
geom->set_used_shaders(used_shaders);
auto sync_func = [=]() mutable {
if (progress.get_cancel())
@ -180,7 +181,7 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
TaskPool *task_pool)
{
/* Ensure we only sync instanced geometry once. */
Geometry *geom = object->geometry;
Geometry *geom = object->get_geometry();
if (geometry_motion_synced.find(geom) != geometry_motion_synced.end())
return;

@ -42,7 +42,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
if (!light_map.add_or_update(&light, b_ob, b_parent, key)) {
Shader *shader;
if (!shader_map.add_or_update(&shader, b_light)) {
if (light->is_portal)
if (light->get_is_portal())
*use_portal = true;
return;
}
@ -52,16 +52,16 @@ void BlenderSync::sync_light(BL::Object &b_parent,
switch (b_light.type()) {
case BL::Light::type_POINT: {
BL::PointLight b_point_light(b_light);
light->size = b_point_light.shadow_soft_size();
light->type = LIGHT_POINT;
light->set_size(b_point_light.shadow_soft_size());
light->set_light_type(LIGHT_POINT);
break;
}
case BL::Light::type_SPOT: {
BL::SpotLight b_spot_light(b_light);
light->size = b_spot_light.shadow_soft_size();
light->type = LIGHT_SPOT;
light->spot_angle = b_spot_light.spot_size();
light->spot_smooth = b_spot_light.spot_blend();
light->set_size(b_spot_light.shadow_soft_size());
light->set_light_type(LIGHT_SPOT);
light->set_spot_angle(b_spot_light.spot_size());
light->set_spot_smooth(b_spot_light.spot_blend());
break;
}
/* Hemi were removed from 2.8 */
@ -72,88 +72,88 @@ void BlenderSync::sync_light(BL::Object &b_parent,
// }
case BL::Light::type_SUN: {
BL::SunLight b_sun_light(b_light);
light->angle = b_sun_light.angle();
light->type = LIGHT_DISTANT;
light->set_angle(b_sun_light.angle());
light->set_light_type(LIGHT_DISTANT);
break;
}
case BL::Light::type_AREA: {
BL::AreaLight b_area_light(b_light);
light->size = 1.0f;
light->axisu = transform_get_column(&tfm, 0);
light->axisv = transform_get_column(&tfm, 1);
light->sizeu = b_area_light.size();
light->set_size(1.0f);
light->set_axisu(transform_get_column(&tfm, 0));
light->set_axisv(transform_get_column(&tfm, 1));
light->set_sizeu(b_area_light.size());
switch (b_area_light.shape()) {
case BL::AreaLight::shape_SQUARE:
light->sizev = light->sizeu;
light->round = false;
light->set_sizev(light->get_sizeu());
light->set_round(false);
break;
case BL::AreaLight::shape_RECTANGLE:
light->sizev = b_area_light.size_y();
light->round = false;
light->set_sizev(b_area_light.size_y());
light->set_round(false);
break;
case BL::AreaLight::shape_DISK:
light->sizev = light->sizeu;
light->round = true;
light->set_sizev(light->get_sizeu());
light->set_round(true);
break;
case BL::AreaLight::shape_ELLIPSE:
light->sizev = b_area_light.size_y();
light->round = true;
light->set_sizev(b_area_light.size_y());
light->set_round(true);
break;
}
light->type = LIGHT_AREA;
light->set_light_type(LIGHT_AREA);
break;
}
}
/* strength */
light->strength = get_float3(b_light.color());
light->strength *= BL::PointLight(b_light).energy();
float3 strength = get_float3(b_light.color()) * BL::PointLight(b_light).energy();
light->set_strength(strength);
/* location and (inverted!) direction */
light->co = transform_get_column(&tfm, 3);
light->dir = -transform_get_column(&tfm, 2);
light->tfm = tfm;
light->set_co(transform_get_column(&tfm, 3));
light->set_dir(-transform_get_column(&tfm, 2));
light->set_tfm(tfm);
/* shader */
vector<Shader *> used_shaders;
array<Node *> used_shaders;
find_shader(b_light, used_shaders, scene->default_light);
light->shader = used_shaders[0];
light->set_shader(static_cast<Shader *>(used_shaders[0]));
/* shadow */
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
light->cast_shadow = get_boolean(clight, "cast_shadow");
light->use_mis = get_boolean(clight, "use_multiple_importance_sampling");
light->set_cast_shadow(get_boolean(clight, "cast_shadow"));
light->set_use_mis(get_boolean(clight, "use_multiple_importance_sampling"));
int samples = get_int(clight, "samples");
if (get_boolean(cscene, "use_square_samples"))
light->samples = samples * samples;
light->set_samples(samples * samples);
else
light->samples = samples;
light->set_samples(samples);
light->max_bounces = get_int(clight, "max_bounces");
light->set_max_bounces(get_int(clight, "max_bounces"));
if (b_ob != b_ob_instance) {
light->random_id = random_id;
light->set_random_id(random_id);
}
else {
light->random_id = hash_uint2(hash_string(b_ob.name().c_str()), 0);
light->set_random_id(hash_uint2(hash_string(b_ob.name().c_str()), 0));
}
if (light->type == LIGHT_AREA)
light->is_portal = get_boolean(clight, "is_portal");
if (light->get_light_type() == LIGHT_AREA)
light->set_is_portal(get_boolean(clight, "is_portal"));
else
light->is_portal = false;
light->set_is_portal(false);
if (light->is_portal)
if (light->get_is_portal())
*use_portal = true;
/* visibility */
uint visibility = object_ray_visibility(b_ob);
light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0;
light->use_glossy = (visibility & PATH_RAY_GLOSSY) != 0;
light->use_transmission = (visibility & PATH_RAY_TRANSMIT) != 0;
light->use_scatter = (visibility & PATH_RAY_VOLUME_SCATTER) != 0;
light->set_use_diffuse((visibility & PATH_RAY_DIFFUSE) != 0);
light->set_use_glossy((visibility & PATH_RAY_GLOSSY) != 0);
light->set_use_transmission((visibility & PATH_RAY_TRANSMIT) != 0);
light->set_use_scatter((visibility & PATH_RAY_VOLUME_SCATTER) != 0);
/* tag */
light->tag_update(scene);
@ -178,25 +178,25 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
if (light_map.add_or_update(&light, b_world, b_world, key) || world_recalc ||
b_world.ptr.data != world_map) {
light->type = LIGHT_BACKGROUND;
light->set_light_type(LIGHT_BACKGROUND);
if (sampling_method == SAMPLING_MANUAL) {
light->map_resolution = get_int(cworld, "sample_map_resolution");
light->set_map_resolution(get_int(cworld, "sample_map_resolution"));
}
else {
light->map_resolution = 0;
light->set_map_resolution(0);
}
light->shader = scene->default_background;
light->use_mis = sample_as_light;
light->max_bounces = get_int(cworld, "max_bounces");
light->set_shader(scene->default_background);
light->set_use_mis(sample_as_light);
light->set_max_bounces(get_int(cworld, "max_bounces"));
/* force enable light again when world is resynced */
light->is_enabled = true;
light->set_is_enabled(true);
int samples = get_int(cworld, "samples");
if (get_boolean(cscene, "use_square_samples"))
light->samples = samples * samples;
light->set_samples(samples * samples);
else
light->samples = samples;
light->set_samples(samples);
light->tag_update(scene);
light_map.set_recalc(b_world);

@ -48,8 +48,8 @@ struct MikkUserData {
float *tangent_sign)
: mesh(mesh), texface(NULL), orco(NULL), tangent(tangent), tangent_sign(tangent_sign)
{
const AttributeSet &attributes = (mesh->subd_faces.size()) ? mesh->subd_attributes :
mesh->attributes;
const AttributeSet &attributes = (mesh->get_num_subd_faces()) ? mesh->subd_attributes :
mesh->attributes;
Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
vertex_normal = attr_vN->data_float3();
@ -85,8 +85,8 @@ struct MikkUserData {
static int mikk_get_num_faces(const SMikkTSpaceContext *context)
{
const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
if (userdata->mesh->subd_faces.size()) {
return userdata->mesh->subd_faces.size();
if (userdata->mesh->get_num_subd_faces()) {
return userdata->mesh->get_num_subd_faces();
}
else {
return userdata->mesh->num_triangles();
@ -96,9 +96,9 @@ static int mikk_get_num_faces(const SMikkTSpaceContext *context)
static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const int face_num)
{
const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
if (userdata->mesh->subd_faces.size()) {
if (userdata->mesh->get_num_subd_faces()) {
const Mesh *mesh = userdata->mesh;
return mesh->subd_faces[face_num].num_corners;
return mesh->get_subd_num_corners()[face_num];
}
else {
return 3;
@ -107,19 +107,19 @@ static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const i
static int mikk_vertex_index(const Mesh *mesh, const int face_num, const int vert_num)
{
if (mesh->subd_faces.size()) {
const Mesh::SubdFace &face = mesh->subd_faces[face_num];
return mesh->subd_face_corners[face.start_corner + vert_num];
if (mesh->get_num_subd_faces()) {
const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
return mesh->get_subd_face_corners()[face.start_corner + vert_num];
}
else {
return mesh->triangles[face_num * 3 + vert_num];
return mesh->get_triangles()[face_num * 3 + vert_num];
}
}
static int mikk_corner_index(const Mesh *mesh, const int face_num, const int vert_num)
{
if (mesh->subd_faces.size()) {
const Mesh::SubdFace &face = mesh->subd_faces[face_num];
if (mesh->get_num_subd_faces()) {
const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
return face.start_corner + vert_num;
}
else {
@ -135,7 +135,7 @@ static void mikk_get_position(const SMikkTSpaceContext *context,
const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
const Mesh *mesh = userdata->mesh;
const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
const float3 vP = mesh->verts[vertex_index];
const float3 vP = mesh->get_verts()[vertex_index];
P[0] = vP.x;
P[1] = vP.y;
P[2] = vP.z;
@ -178,8 +178,8 @@ static void mikk_get_normal(const SMikkTSpaceContext *context,
const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
const Mesh *mesh = userdata->mesh;
float3 vN;
if (mesh->subd_faces.size()) {
const Mesh::SubdFace &face = mesh->subd_faces[face_num];
if (mesh->get_num_subd_faces()) {
const Mesh::SubdFace &face = mesh->get_subd_face(face_num);
if (face.smooth) {
const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
vN = userdata->vertex_normal[vertex_index];
@ -189,13 +189,13 @@ static void mikk_get_normal(const SMikkTSpaceContext *context,
}
}
else {
if (mesh->smooth[face_num]) {
if (mesh->get_smooth()[face_num]) {
const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
vN = userdata->vertex_normal[vertex_index];
}
else {
const Mesh::Triangle tri = mesh->get_triangle(face_num);
vN = tri.compute_normal(&mesh->verts[0]);
vN = tri.compute_normal(&mesh->get_verts()[0]);
}
}
N[0] = vN.x;
@ -222,7 +222,8 @@ static void mikk_compute_tangents(
const BL::Mesh &b_mesh, const char *layer_name, Mesh *mesh, bool need_sign, bool active_render)
{
/* Create tangent attributes. */
AttributeSet &attributes = (mesh->subd_faces.size()) ? mesh->subd_attributes : mesh->attributes;
AttributeSet &attributes = (mesh->get_num_subd_faces()) ? mesh->subd_attributes :
mesh->attributes;
Attribute *attr;
ustring name;
if (layer_name != NULL) {
@ -554,7 +555,7 @@ static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, b
for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
sorted_vert_indeices[vert_index] = vert_index;
}
VertexAverageComparator compare(mesh->verts);
VertexAverageComparator compare(mesh->get_verts());
sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare);
/* This array stores index of the original vertex for the given vertex
* index.
@ -562,12 +563,12 @@ static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, b
vector<int> vert_orig_index(num_verts);
for (int sorted_vert_index = 0; sorted_vert_index < num_verts; ++sorted_vert_index) {
const int vert_index = sorted_vert_indeices[sorted_vert_index];
const float3 &vert_co = mesh->verts[vert_index];
const float3 &vert_co = mesh->get_verts()[vert_index];
bool found = false;
for (int other_sorted_vert_index = sorted_vert_index + 1; other_sorted_vert_index < num_verts;
++other_sorted_vert_index) {
const int other_vert_index = sorted_vert_indeices[other_sorted_vert_index];
const float3 &other_vert_co = mesh->verts[other_vert_index];
const float3 &other_vert_co = mesh->get_verts()[other_vert_index];
/* We are too far away now, we wouldn't have duplicate. */
if ((other_vert_co.x + other_vert_co.y + other_vert_co.z) -
(vert_co.x + vert_co.y + vert_co.z) >
@ -732,7 +733,7 @@ static void attr_create_random_per_island(Scene *scene,
static void create_mesh(Scene *scene,
Mesh *mesh,
BL::Mesh &b_mesh,
const vector<Shader *> &used_shaders,
const array<Node *> &used_shaders,
bool subdivision = false,
bool subdivide_uvs = true)
{
@ -743,7 +744,7 @@ static void create_mesh(Scene *scene,
int numcorners = 0;
int numngons = 0;
bool use_loop_normals = b_mesh.use_auto_smooth() &&
(mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK);
(mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK);
/* If no faces, create empty mesh. */
if (numfaces == 0) {
@ -762,8 +763,11 @@ static void create_mesh(Scene *scene,
}
/* allocate memory */
if (subdivision) {
mesh->reserve_subd_faces(numfaces, numngons, numcorners);
}
mesh->reserve_mesh(numverts, numtris);
mesh->reserve_subd_faces(numfaces, numngons, numcorners);
/* create vertex coordinates and normals */
BL::Mesh::vertices_iterator v;
@ -875,7 +879,7 @@ static void create_subd_mesh(Scene *scene,
Mesh *mesh,
BL::Object &b_ob,
BL::Mesh &b_mesh,
const vector<Shader *> &used_shaders,
const array<Node *> &used_shaders,
float dicing_rate,
int max_subdivisions)
{
@ -894,31 +898,21 @@ static void create_subd_mesh(Scene *scene,
}
}
mesh->subd_creases.resize(num_creases);
mesh->reserve_subd_creases(num_creases);
Mesh::SubdEdgeCrease *crease = mesh->subd_creases.data();
for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
if (e->crease() != 0.0f) {
crease->v[0] = e->vertices()[0];
crease->v[1] = e->vertices()[1];
crease->crease = e->crease();
crease++;
mesh->add_crease(e->vertices()[0], e->vertices()[1], e->crease());
}
}
/* set subd params */
if (!mesh->subd_params) {
mesh->subd_params = new SubdParams(mesh);
}
SubdParams &sdparams = *mesh->subd_params;
PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
float subd_dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
sdparams.dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
sdparams.max_level = max_subdivisions;
sdparams.objecttoworld = get_transform(b_ob.matrix_world());
mesh->set_subd_dicing_rate(subd_dicing_rate);
mesh->set_subd_max_level(max_subdivisions);
mesh->set_subd_objecttoworld(get_transform(b_ob.matrix_world()));
}
/* Sync */
@ -955,14 +949,14 @@ static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *me
return;
}
const size_t numverts = mesh->verts.size();
const size_t numverts = mesh->get_verts().size();
if (b_mesh_cache.vertex_velocities.length() != numverts) {
return;
}
/* Find or add attribute */
float3 *P = &mesh->verts[0];
float3 *P = &mesh->get_verts()[0];
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (!attr_mP) {
@ -996,11 +990,11 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
return;
/* If the mesh has modifiers following the fluid domain we can't export motion. */
if (b_fluid_domain.mesh_vertices.length() != mesh->verts.size())
if (b_fluid_domain.mesh_vertices.length() != mesh->get_verts().size())
return;
/* Find or add attribute */
float3 *P = &mesh->verts[0];
float3 *P = &mesh->get_verts()[0];
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (!attr_mP) {
@ -1011,7 +1005,7 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
float motion_times[2] = {-1.0f, 1.0f};
for (int step = 0; step < 2; step++) {
float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f;
float3 *mP = attr_mP->data_float3() + step * mesh->verts.size();
float3 *mP = attr_mP->data_float3() + step * mesh->get_verts().size();
BL::FluidDomainSettings::mesh_vertices_iterator svi;
int i = 0;
@ -1025,50 +1019,70 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh)
{
array<int> oldtriangles;
array<Mesh::SubdFace> oldsubd_faces;
array<int> oldsubd_face_corners;
oldtriangles.steal_data(mesh->triangles);
oldsubd_faces.steal_data(mesh->subd_faces);
oldsubd_face_corners.steal_data(mesh->subd_face_corners);
mesh->clear(true);
mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
Mesh new_mesh;
new_mesh.set_used_shaders(mesh->get_used_shaders());
if (view_layer.use_surfaces) {
/* Adaptive subdivision setup. Not for baking since that requires
* exact mapping to the Blender mesh. */
if (!scene->bake_manager->get_baking()) {
mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
new_mesh.set_subdivision_type(object_subdivision_type(b_ob, preview, experimental));
}
/* For some reason, meshes do not need this... */
bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
bool need_undeformed = new_mesh.need_attribute(scene, ATTR_STD_GENERATED);
BL::Mesh b_mesh = object_to_mesh(
b_data, b_ob, b_depsgraph, need_undeformed, mesh->subdivision_type);
b_data, b_ob, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type());
if (b_mesh) {
/* Sync mesh itself. */
if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE)
create_subd_mesh(
scene, mesh, b_ob, b_mesh, mesh->used_shaders, dicing_rate, max_subdivisions);
if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE)
create_subd_mesh(scene,
&new_mesh,
b_ob,
b_mesh,
new_mesh.get_used_shaders(),
dicing_rate,
max_subdivisions);
else
create_mesh(scene, mesh, b_mesh, mesh->used_shaders, false);
create_mesh(scene, &new_mesh, b_mesh, new_mesh.get_used_shaders(), false);
free_object_to_mesh(b_data, b_ob, b_mesh);
}
}
/* cached velocities (e.g. from alembic archive) */
sync_mesh_cached_velocities(b_ob, scene, mesh);
sync_mesh_cached_velocities(b_ob, scene, &new_mesh);
/* mesh fluid motion mantaflow */
sync_mesh_fluid_motion(b_ob, scene, mesh);
sync_mesh_fluid_motion(b_ob, scene, &new_mesh);
/* update original sockets */
for (const SocketType &socket : new_mesh.type->inputs) {
/* Those sockets are updated in sync_object, so do not modify them. */
if (socket.name == "use_motion_blur" || socket.name == "motion_steps") {
continue;
}
mesh->set_value(socket, new_mesh, socket);
}
foreach (Attribute &attr, new_mesh.attributes.attributes) {
mesh->attributes.attributes.push_back(std::move(attr));
}
foreach (Attribute &attr, new_mesh.subd_attributes.attributes) {
mesh->subd_attributes.attributes.push_back(std::move(attr));
}
mesh->set_num_subd_faces(new_mesh.get_num_subd_faces());
/* tag update */
bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) ||
(oldsubd_face_corners != mesh->subd_face_corners);
bool rebuild = (mesh->triangles_is_modified()) || (mesh->subd_num_corners_is_modified()) ||
(mesh->subd_shader_is_modified()) || (mesh->subd_smooth_is_modified()) ||
(mesh->subd_ptex_offset_is_modified()) ||
(mesh->subd_start_corner_is_modified()) ||
(mesh->subd_face_corners_is_modified());
mesh->tag_update(scene, rebuild);
}
@ -1091,7 +1105,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
}
/* Skip if no vertices were exported. */
size_t numverts = mesh->verts.size();
size_t numverts = mesh->get_verts().size();
if (numverts == 0) {
return;
}
@ -1136,7 +1150,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
if (new_attribute) {
/* In case of new attribute, we verify if there really was any motion. */
if (b_mesh.vertices.length() != numverts ||
memcmp(mP, &mesh->verts[0], sizeof(float3) * numverts) == 0) {
memcmp(mP, &mesh->get_verts()[0], sizeof(float3) * numverts) == 0) {
/* no motion, remove attributes again */
if (b_mesh.vertices.length() != numverts) {
VLOG(1) << "Topology differs, disabling motion blur for object " << b_ob.name();
@ -1152,7 +1166,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
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 *P = &mesh->get_verts()[0];
float3 *N = (attr_N) ? attr_N->data_float3() : NULL;
for (int step = 0; step < motion_step; step++) {
memcpy(attr_mP->data_float3() + step * numverts, P, sizeof(float3) * numverts);
@ -1165,7 +1179,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
if (b_mesh.vertices.length() != numverts) {
VLOG(1) << "Topology differs, discarding motion blur for object " << b_ob.name()
<< " at time " << motion_step;
memcpy(mP, &mesh->verts[0], sizeof(float3) * numverts);
memcpy(mP, &mesh->get_verts()[0], sizeof(float3) * numverts);
if (mN != NULL) {
memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts);
}

@ -199,11 +199,13 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
/* Set transform at matching motion time step. */
int time_index = object->motion_step(motion_time);
if (time_index >= 0) {
object->motion[time_index] = tfm;
array<Transform> motion = object->get_motion();
motion[time_index] = tfm;
object->set_motion(motion);
}
/* mesh deformation */
if (object->geometry)
if (object->get_geometry())
sync_geometry_motion(b_depsgraph,
b_ob_instance,
object,
@ -225,12 +227,13 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
/* b_ob is owned by the iterator and will go out of scope at the end of the block.
* b_ob_instance is the original object and will remain valid for deferred geometry
* sync. */
object->geometry = sync_geometry(b_depsgraph,
b_ob_instance,
b_ob_instance,
object_updated,
use_particle_hair,
object_geom_task_pool);
Geometry *geometry = sync_geometry(b_depsgraph,
b_ob_instance,
b_ob_instance,
object_updated,
use_particle_hair,
object_geom_task_pool);
object->set_geometry(geometry);
/* special case not tracked by object update flags */
@ -239,28 +242,18 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
}
/* holdout */
if (use_holdout != object->use_holdout) {
object->use_holdout = use_holdout;
object->set_use_holdout(use_holdout);
if (object->use_holdout_is_modified()) {
scene->object_manager->tag_update(scene);
object_updated = true;
}
if (visibility != object->visibility) {
object->visibility = visibility;
object_updated = true;
}
object->set_visibility(visibility);
bool is_shadow_catcher = get_boolean(cobject, "is_shadow_catcher");
if (is_shadow_catcher != object->is_shadow_catcher) {
object->is_shadow_catcher = is_shadow_catcher;
object_updated = true;
}
object->set_is_shadow_catcher(is_shadow_catcher);
float shadow_terminator_offset = get_float(cobject, "shadow_terminator_offset");
if (shadow_terminator_offset != object->shadow_terminator_offset) {
object->shadow_terminator_offset = shadow_terminator_offset;
object_updated = true;
}
object->set_shadow_terminator_offset(shadow_terminator_offset);
/* sync the asset name for Cryptomatte */
BL::Object parent = b_ob.parent();
@ -274,48 +267,49 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
else {
parent_name = b_ob.name();
}
if (object->asset_name != parent_name) {
object->asset_name = parent_name;
object_updated = true;
}
object->set_asset_name(parent_name);
/* object sync
* transform comparison should not be needed, but duplis don't work perfect
* in the depsgraph and may not signal changes, so this is a workaround */
if (object_updated || (object->geometry && object->geometry->need_update) ||
tfm != object->tfm) {
if (object->is_modified() || object_updated ||
(object->get_geometry() && object->get_geometry()->is_modified()) ||
tfm != object->get_tfm()) {
object->name = b_ob.name().c_str();
object->pass_id = b_ob.pass_index();
object->color = get_float3(b_ob.color());
object->tfm = tfm;
object->motion.clear();
object->set_pass_id(b_ob.pass_index());
object->set_color(get_float3(b_ob.color()));
object->set_tfm(tfm);
array<Transform> motion;
object->set_motion(motion);
/* motion blur */
Scene::MotionType need_motion = scene->need_motion();
if (need_motion != Scene::MOTION_NONE && object->geometry) {
Geometry *geom = object->geometry;
geom->use_motion_blur = false;
geom->motion_steps = 0;
if (need_motion != Scene::MOTION_NONE && object->get_geometry()) {
Geometry *geom = object->get_geometry();
geom->set_use_motion_blur(false);
geom->set_motion_steps(0);
uint motion_steps;
if (need_motion == Scene::MOTION_BLUR) {
motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
geom->motion_steps = motion_steps;
geom->set_motion_steps(motion_steps);
if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
geom->use_motion_blur = true;
geom->set_use_motion_blur(true);
}
}
else {
motion_steps = 3;
geom->motion_steps = motion_steps;
geom->set_motion_steps(motion_steps);
}
object->motion.clear();
object->motion.resize(motion_steps, transform_empty());
motion.resize(motion_steps, transform_empty());
if (motion_steps) {
object->motion[motion_steps / 2] = tfm;
motion[motion_steps / 2] = tfm;
/* update motion socket before trying to access object->motion_time */
object->set_motion(motion);
for (size_t step = 0; step < motion_steps; step++) {
motion_times.insert(object->motion_time(step));
@ -325,15 +319,15 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
/* dupli texture coordinates and random_id */
if (is_instance) {
object->dupli_generated = 0.5f * get_float3(b_instance.orco()) -
make_float3(0.5f, 0.5f, 0.5f);
object->dupli_uv = get_float2(b_instance.uv());
object->random_id = b_instance.random_id();
object->set_dupli_generated(0.5f * get_float3(b_instance.orco()) -
make_float3(0.5f, 0.5f, 0.5f));
object->set_dupli_uv(get_float2(b_instance.uv()));
object->set_random_id(b_instance.random_id());
}
else {
object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f);
object->dupli_uv = make_float2(0.0f, 0.0f);
object->random_id = hash_uint2(hash_string(object->name.c_str()), 0);
object->set_dupli_generated(make_float3(0.0f, 0.0f, 0.0f));
object->set_dupli_uv(make_float2(0.0f, 0.0f));
object->set_random_id(hash_uint2(hash_string(object->name.c_str()), 0));
}
object->tag_update(scene);
@ -421,7 +415,7 @@ static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance,
bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object)
{
/* Find which attributes are needed. */
AttributeRequestSet requests = object->geometry->needed_attributes();
AttributeRequestSet requests = object->get_geometry()->needed_attributes();
/* Delete attributes that became unnecessary. */
vector<ParamValue> &attributes = object->attributes;
@ -591,20 +585,18 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
if (b_override)
b_cam = b_override;
Camera prevcam = *(scene->camera);
int frame_center = b_scene.frame_current();
float subframe_center = b_scene.frame_subframe();
float frame_center_delta = 0.0f;
if (scene->need_motion() != Scene::MOTION_PASS &&
scene->camera->motion_position != Camera::MOTION_POSITION_CENTER) {
float shuttertime = scene->camera->shuttertime;
if (scene->camera->motion_position == Camera::MOTION_POSITION_END) {
scene->camera->get_motion_position() != Camera::MOTION_POSITION_CENTER) {
float shuttertime = scene->camera->get_shuttertime();
if (scene->camera->get_motion_position() == Camera::MOTION_POSITION_END) {
frame_center_delta = -shuttertime * 0.5f;
}
else {
assert(scene->camera->motion_position == Camera::MOTION_POSITION_START);
assert(scene->camera->get_motion_position() == Camera::MOTION_POSITION_START);
frame_center_delta = shuttertime * 0.5f;
}
@ -665,10 +657,6 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
python_thread_state_restore(python_thread_state);
b_engine.frame_set(frame_center, subframe_center);
python_thread_state_save(python_thread_state);
/* tag camera for motion update */
if (scene->camera->motion_modified(prevcam))
scene->camera->tag_update();
}
CCL_NAMESPACE_END

@ -34,10 +34,10 @@ BlenderObjectCulling::BlenderObjectCulling(Scene *scene, BL::Scene &b_scene)
if (b_scene.render().use_simplify()) {
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
use_scene_camera_cull_ = scene->camera->type != CAMERA_PANORAMA &&
use_scene_camera_cull_ = scene->camera->get_camera_type() != CAMERA_PANORAMA &&
!b_scene.render().use_multiview() &&
get_boolean(cscene, "use_camera_cull");
use_scene_distance_cull_ = scene->camera->type != CAMERA_PANORAMA &&
use_scene_distance_cull_ = scene->camera->get_camera_type() != CAMERA_PANORAMA &&
!b_scene.render().use_multiview() &&
get_boolean(cscene, "use_distance_cull");
@ -123,7 +123,7 @@ bool BlenderObjectCulling::test_camera(Scene *scene, float3 bb[8])
bool BlenderObjectCulling::test_distance(Scene *scene, float3 bb[8])
{
float3 camera_position = transform_get_column(&scene->camera->matrix, 3);
float3 camera_position = transform_get_column(&scene->camera->get_matrix(), 3);
float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);

@ -36,10 +36,10 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
if (!b_psys)
return false;
object->hide_on_missing_motion = true;
object->set_hide_on_missing_motion(true);
/* test if we need particle data */
if (!object->geometry->need_attribute(scene, ATTR_STD_PARTICLE))
if (!object->get_geometry()->need_attribute(scene, ATTR_STD_PARTICLE))
return false;
/* don't handle child particles yet */
@ -56,7 +56,8 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
bool need_update = particle_system_map.add_or_update(&psys, b_ob, b_instance.object(), key);
/* no update needed? */
if (!need_update && !object->geometry->need_update && !scene->object_manager->need_update)
if (!need_update && !object->get_geometry()->is_modified() &&
!scene->object_manager->need_update)
return true;
/* first time used in this sync loop? clear and tag update */
@ -80,10 +81,11 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
psys->particles.push_back_slow(pa);
if (object->particle_index != psys->particles.size() - 1)
object->set_particle_system(psys);
object->set_particle_index(psys->particles.size() - 1);
if (object->particle_index_is_modified())
scene->object_manager->tag_update(scene);
object->particle_system = psys;
object->particle_index = psys->particles.size() - 1;
/* return that this object has particle data */
return true;

@ -442,17 +442,17 @@ void BlenderSession::stamp_view_layer_metadata(Scene *scene, const string &view_
}
/* Write cryptomatte metadata. */
if (scene->film->cryptomatte_passes & CRYPT_OBJECT) {
if (scene->film->get_cryptomatte_passes() & CRYPT_OBJECT) {
add_cryptomatte_layer(b_rr,
view_layer_name + ".CryptoObject",
scene->object_manager->get_cryptomatte_objects(scene));
}
if (scene->film->cryptomatte_passes & CRYPT_MATERIAL) {
if (scene->film->get_cryptomatte_passes() & CRYPT_MATERIAL) {
add_cryptomatte_layer(b_rr,
view_layer_name + ".CryptoMaterial",
scene->shader_manager->get_cryptomatte_materials(scene));
}
if (scene->film->cryptomatte_passes & CRYPT_ASSET) {
if (scene->film->get_cryptomatte_passes() & CRYPT_ASSET) {
add_cryptomatte_layer(b_rr,
view_layer_name + ".CryptoAsset",
scene->object_manager->get_cryptomatte_assets(scene));
@ -508,9 +508,9 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
/* Set buffer params, using film settings from sync_render_passes. */
buffer_params.passes = passes;
buffer_params.denoising_data_pass = scene->film->denoising_data_pass;
buffer_params.denoising_clean_pass = scene->film->denoising_clean_pass;
buffer_params.denoising_prefiltered_pass = scene->film->denoising_prefiltered_pass;
buffer_params.denoising_data_pass = scene->film->get_denoising_data_pass();
buffer_params.denoising_clean_pass = scene->film->get_denoising_clean_pass();
buffer_params.denoising_prefiltered_pass = scene->film->get_denoising_prefiltered_pass();
BL::RenderResult::views_iterator b_view_iter;
@ -547,8 +547,9 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
/* Make sure all views have different noise patterns. - hardcoded value just to make it random
*/
if (view_index != 0) {
scene->integrator->seed += hash_uint2(scene->integrator->seed,
hash_uint2(view_index * 0xdeadbeef, 0));
int seed = scene->integrator->get_seed();
seed += hash_uint2(seed, hash_uint2(view_index * 0xdeadbeef, 0));
scene->integrator->set_seed(seed);
scene->integrator->tag_update(scene);
}
@ -720,7 +721,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderLayer &b_rlay,
if (!buffers->copy_from_device())
return;
float exposure = scene->film->exposure;
float exposure = scene->film->get_exposure();
vector<float> pixels(rtile.w * rtile.h * 4);
@ -837,10 +838,7 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
session->set_denoising(session_params.denoising);
/* Update film if denoising data was enabled or disabled. */
if (scene->film->denoising_data_pass != buffer_params.denoising_data_pass) {
scene->film->denoising_data_pass = buffer_params.denoising_data_pass;
scene->film->tag_update(scene);
}
scene->film->set_denoising_data_pass(buffer_params.denoising_data_pass);
/* reset if needed */
if (scene->need_reset()) {
@ -899,7 +897,7 @@ bool BlenderSession::draw(int w, int h)
sync->sync_view(b_v3d, b_rv3d, width, height);
if (scene->camera->need_update)
if (scene->camera->is_modified())
reset = true;
session->scene->mutex.unlock();
@ -1114,8 +1112,11 @@ void BlenderSession::update_resumable_tile_manager(int num_samples)
VLOG(1) << "Samples range start is " << range_start_sample << ", "
<< "number of samples to render is " << range_num_samples;
scene->integrator->start_sample = rounded_range_start_sample;
scene->integrator->tag_update(scene);
scene->integrator->set_start_sample(rounded_range_start_sample);
if (scene->integrator->is_modified()) {
scene->integrator->tag_update(scene);
}
session->tile_manager.range_start_sample = rounded_range_start_sample;
session->tile_manager.range_num_samples = rounded_range_num_samples;

@ -42,11 +42,11 @@ typedef map<string, ConvertNode *> ProxyMap;
/* Find */
void BlenderSync::find_shader(BL::ID &id, vector<Shader *> &used_shaders, Shader *default_shader)
void BlenderSync::find_shader(BL::ID &id, array<Node *> &used_shaders, Shader *default_shader)
{
Shader *shader = (id) ? shader_map.find(id) : default_shader;
used_shaders.push_back(shader);
used_shaders.push_back_slow(shader);
shader->tag_used(scene);
}
@ -241,19 +241,19 @@ static void set_default_value(ShaderInput *input,
}
}
static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping &b_mapping)
static void get_tex_mapping(TextureNode *mapping, BL::TexMapping &b_mapping)
{
if (!b_mapping)
return;
mapping->translation = get_float3(b_mapping.translation());
mapping->rotation = get_float3(b_mapping.rotation());
mapping->scale = get_float3(b_mapping.scale());
mapping->type = (TextureMapping::Type)b_mapping.vector_type();
mapping->set_tex_mapping_translation(get_float3(b_mapping.translation()));
mapping->set_tex_mapping_rotation(get_float3(b_mapping.rotation()));
mapping->set_tex_mapping_scale(get_float3(b_mapping.scale()));
mapping->set_tex_mapping_type((TextureMapping::Type)b_mapping.vector_type());
mapping->x_mapping = (TextureMapping::Mapping)b_mapping.mapping_x();
mapping->y_mapping = (TextureMapping::Mapping)b_mapping.mapping_y();
mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z();
mapping->set_tex_mapping_x_mapping((TextureMapping::Mapping)b_mapping.mapping_x());
mapping->set_tex_mapping_y_mapping((TextureMapping::Mapping)b_mapping.mapping_y());
mapping->set_tex_mapping_z_mapping((TextureMapping::Mapping)b_mapping.mapping_z());
}
static ShaderNode *add_node(Scene *scene,
@ -272,34 +272,48 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeRGBCurve b_curve_node(b_node);
BL::CurveMapping mapping(b_curve_node.mapping());
RGBCurvesNode *curves = graph->create_node<RGBCurvesNode>();
curvemapping_color_to_array(mapping, curves->curves, RAMP_TABLE_SIZE, true);
curvemapping_minmax(mapping, true, &curves->min_x, &curves->max_x);
array<float3> curve_mapping_curves;
float min_x, max_x;
curvemapping_color_to_array(mapping, curve_mapping_curves, RAMP_TABLE_SIZE, true);
curvemapping_minmax(mapping, true, &min_x, &max_x);
curves->set_min_x(min_x);
curves->set_max_x(max_x);
curves->set_curves(curve_mapping_curves);
node = curves;
}
if (b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
BL::ShaderNodeVectorCurve b_curve_node(b_node);
BL::CurveMapping mapping(b_curve_node.mapping());
VectorCurvesNode *curves = graph->create_node<VectorCurvesNode>();
curvemapping_color_to_array(mapping, curves->curves, RAMP_TABLE_SIZE, false);
curvemapping_minmax(mapping, false, &curves->min_x, &curves->max_x);
array<float3> curve_mapping_curves;
float min_x, max_x;
curvemapping_color_to_array(mapping, curve_mapping_curves, RAMP_TABLE_SIZE, false);
curvemapping_minmax(mapping, false, &min_x, &max_x);
curves->set_min_x(min_x);
curves->set_max_x(max_x);
curves->set_curves(curve_mapping_curves);
node = curves;
}
else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) {
RGBRampNode *ramp = graph->create_node<RGBRampNode>();
BL::ShaderNodeValToRGB b_ramp_node(b_node);
BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp());
colorramp_to_array(b_color_ramp, ramp->ramp, ramp->ramp_alpha, RAMP_TABLE_SIZE);
ramp->interpolate = b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT;
array<float3> ramp_values;
array<float> ramp_alpha;
colorramp_to_array(b_color_ramp, ramp_values, ramp_alpha, RAMP_TABLE_SIZE);
ramp->set_ramp(ramp_values);
ramp->set_ramp_alpha(ramp_alpha);
ramp->set_interpolate(b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT);
node = ramp;
}
else if (b_node.is_a(&RNA_ShaderNodeRGB)) {
ColorNode *color = graph->create_node<ColorNode>();
color->value = get_node_output_rgba(b_node, "Color");
color->set_value(get_node_output_rgba(b_node, "Color"));
node = color;
}
else if (b_node.is_a(&RNA_ShaderNodeValue)) {
ValueNode *value = graph->create_node<ValueNode>();
value->value = get_node_output_value(b_node, "Value");
value->set_value(get_node_output_value(b_node, "Value"));
node = value;
}
else if (b_node.is_a(&RNA_ShaderNodeCameraData)) {
@ -317,8 +331,8 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeMixRGB)) {
BL::ShaderNodeMixRGB b_mix_node(b_node);
MixNode *mix = graph->create_node<MixNode>();
mix->type = (NodeMix)b_mix_node.blend_type();
mix->use_clamp = b_mix_node.use_clamp();
mix->set_mix_type((NodeMix)b_mix_node.blend_type());
mix->set_use_clamp(b_mix_node.use_clamp());
node = mix;
}
else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
@ -348,43 +362,45 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeMapRange)) {
BL::ShaderNodeMapRange b_map_range_node(b_node);
MapRangeNode *map_range_node = graph->create_node<MapRangeNode>();
map_range_node->clamp = b_map_range_node.clamp();
map_range_node->type = (NodeMapRangeType)b_map_range_node.interpolation_type();
map_range_node->set_clamp(b_map_range_node.clamp());
map_range_node->set_range_type((NodeMapRangeType)b_map_range_node.interpolation_type());
node = map_range_node;
}
else if (b_node.is_a(&RNA_ShaderNodeClamp)) {
BL::ShaderNodeClamp b_clamp_node(b_node);
ClampNode *clamp_node = graph->create_node<ClampNode>();
clamp_node->type = (NodeClampType)b_clamp_node.clamp_type();
clamp_node->set_clamp_type((NodeClampType)b_clamp_node.clamp_type());
node = clamp_node;
}
else if (b_node.is_a(&RNA_ShaderNodeMath)) {
BL::ShaderNodeMath b_math_node(b_node);
MathNode *math_node = graph->create_node<MathNode>();
math_node->type = (NodeMathType)b_math_node.operation();
math_node->use_clamp = b_math_node.use_clamp();
math_node->set_math_type((NodeMathType)b_math_node.operation());
math_node->set_use_clamp(b_math_node.use_clamp());
node = math_node;
}
else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
VectorMathNode *vector_math_node = graph->create_node<VectorMathNode>();
vector_math_node->type = (NodeVectorMathType)b_vector_math_node.operation();
vector_math_node->set_math_type((NodeVectorMathType)b_vector_math_node.operation());
node = vector_math_node;
}
else if (b_node.is_a(&RNA_ShaderNodeVectorRotate)) {
BL::ShaderNodeVectorRotate b_vector_rotate_node(b_node);
VectorRotateNode *vector_rotate_node = graph->create_node<VectorRotateNode>();
vector_rotate_node->type = (NodeVectorRotateType)b_vector_rotate_node.rotation_type();
vector_rotate_node->invert = b_vector_rotate_node.invert();
vector_rotate_node->set_rotate_type(
(NodeVectorRotateType)b_vector_rotate_node.rotation_type());
vector_rotate_node->set_invert(b_vector_rotate_node.invert());
node = vector_rotate_node;
}
else if (b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
VectorTransformNode *vtransform = graph->create_node<VectorTransformNode>();
vtransform->type = (NodeVectorTransformType)b_vector_transform_node.vector_type();
vtransform->convert_from = (NodeVectorTransformConvertSpace)
b_vector_transform_node.convert_from();
vtransform->convert_to = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to();
vtransform->set_transform_type((NodeVectorTransformType)b_vector_transform_node.vector_type());
vtransform->set_convert_from(
(NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from());
vtransform->set_convert_to(
(NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to());
node = vtransform;
}
else if (b_node.is_a(&RNA_ShaderNodeNormal)) {
@ -392,13 +408,13 @@ static ShaderNode *add_node(Scene *scene,
b_node.outputs.begin(out_it);
NormalNode *norm = graph->create_node<NormalNode>();
norm->direction = get_node_output_vector(b_node, "Normal");
norm->set_direction(get_node_output_vector(b_node, "Normal"));
node = norm;
}
else if (b_node.is_a(&RNA_ShaderNodeMapping)) {
BL::ShaderNodeMapping b_mapping_node(b_node);
MappingNode *mapping = graph->create_node<MappingNode>();
mapping->type = (NodeMappingType)b_mapping_node.vector_type();
mapping->set_mapping_type((NodeMappingType)b_mapping_node.vector_type());
node = mapping;
}
else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {
@ -416,8 +432,8 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeAttribute)) {
BL::ShaderNodeAttribute b_attr_node(b_node);
AttributeNode *attr = graph->create_node<AttributeNode>();
attr->attribute = blender_attribute_name_add_type(b_attr_node.attribute_name(),
b_attr_node.attribute_type());
attr->set_attribute(blender_attribute_name_add_type(b_attr_node.attribute_name(),
b_attr_node.attribute_type()));
node = attr;
}
else if (b_node.is_a(&RNA_ShaderNodeBackground)) {
@ -432,16 +448,16 @@ static ShaderNode *add_node(Scene *scene,
switch (b_aniso_node.distribution()) {
case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
aniso->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
break;
case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
aniso->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
break;
case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
aniso->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
break;
case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
aniso->set_distribution(CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
break;
}
@ -457,16 +473,16 @@ static ShaderNode *add_node(Scene *scene,
switch (b_subsurface_node.falloff()) {
case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
subsurface->falloff = CLOSURE_BSSRDF_CUBIC_ID;
subsurface->set_falloff(CLOSURE_BSSRDF_CUBIC_ID);
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
subsurface->falloff = CLOSURE_BSSRDF_GAUSSIAN_ID;
subsurface->set_falloff(CLOSURE_BSSRDF_GAUSSIAN_ID);
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
subsurface->falloff = CLOSURE_BSSRDF_BURLEY_ID;
subsurface->set_falloff(CLOSURE_BSSRDF_BURLEY_ID);
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK:
subsurface->falloff = CLOSURE_BSSRDF_RANDOM_WALK_ID;
subsurface->set_falloff(CLOSURE_BSSRDF_RANDOM_WALK_ID);
break;
}
@ -478,19 +494,19 @@ static ShaderNode *add_node(Scene *scene,
switch (b_glossy_node.distribution()) {
case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
glossy->distribution = CLOSURE_BSDF_REFLECTION_ID;
glossy->set_distribution(CLOSURE_BSDF_REFLECTION_ID);
break;
case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
glossy->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
glossy->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
break;
case BL::ShaderNodeBsdfGlossy::distribution_GGX:
glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
glossy->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
break;
case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
glossy->set_distribution(CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
break;
case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
glossy->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
break;
}
node = glossy;
@ -500,16 +516,16 @@ static ShaderNode *add_node(Scene *scene,
GlassBsdfNode *glass = graph->create_node<GlassBsdfNode>();
switch (b_glass_node.distribution()) {
case BL::ShaderNodeBsdfGlass::distribution_SHARP:
glass->distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
glass->set_distribution(CLOSURE_BSDF_SHARP_GLASS_ID);
break;
case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
glass->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID;
glass->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
break;
case BL::ShaderNodeBsdfGlass::distribution_GGX:
glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
glass->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
break;
case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX:
glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
glass->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
break;
}
node = glass;
@ -519,13 +535,13 @@ static ShaderNode *add_node(Scene *scene,
RefractionBsdfNode *refraction = graph->create_node<RefractionBsdfNode>();
switch (b_refraction_node.distribution()) {
case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
refraction->distribution = CLOSURE_BSDF_REFRACTION_ID;
refraction->set_distribution(CLOSURE_BSDF_REFRACTION_ID);
break;
case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
refraction->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
refraction->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
break;
case BL::ShaderNodeBsdfRefraction::distribution_GGX:
refraction->distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
refraction->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
break;
}
node = refraction;
@ -535,10 +551,10 @@ static ShaderNode *add_node(Scene *scene,
ToonBsdfNode *toon = graph->create_node<ToonBsdfNode>();
switch (b_toon_node.component()) {
case BL::ShaderNodeBsdfToon::component_DIFFUSE:
toon->component = CLOSURE_BSDF_DIFFUSE_TOON_ID;
toon->set_component(CLOSURE_BSDF_DIFFUSE_TOON_ID);
break;
case BL::ShaderNodeBsdfToon::component_GLOSSY:
toon->component = CLOSURE_BSDF_GLOSSY_TOON_ID;
toon->set_component(CLOSURE_BSDF_GLOSSY_TOON_ID);
break;
}
node = toon;
@ -548,10 +564,10 @@ static ShaderNode *add_node(Scene *scene,
HairBsdfNode *hair = graph->create_node<HairBsdfNode>();
switch (b_hair_node.component()) {
case BL::ShaderNodeBsdfHair::component_Reflection:
hair->component = CLOSURE_BSDF_HAIR_REFLECTION_ID;
hair->set_component(CLOSURE_BSDF_HAIR_REFLECTION_ID);
break;
case BL::ShaderNodeBsdfHair::component_Transmission:
hair->component = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
hair->set_component(CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
break;
}
node = hair;
@ -559,11 +575,11 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeBsdfHairPrincipled)) {
BL::ShaderNodeBsdfHairPrincipled b_principled_hair_node(b_node);
PrincipledHairBsdfNode *principled_hair = graph->create_node<PrincipledHairBsdfNode>();
principled_hair->parametrization = (NodePrincipledHairParametrization)get_enum(
b_principled_hair_node.ptr,
"parametrization",
NODE_PRINCIPLED_HAIR_NUM,
NODE_PRINCIPLED_HAIR_REFLECTANCE);
principled_hair->set_parametrization(
(NodePrincipledHairParametrization)get_enum(b_principled_hair_node.ptr,
"parametrization",
NODE_PRINCIPLED_HAIR_NUM,
NODE_PRINCIPLED_HAIR_REFLECTANCE));
node = principled_hair;
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) {
@ -571,18 +587,18 @@ static ShaderNode *add_node(Scene *scene,
PrincipledBsdfNode *principled = graph->create_node<PrincipledBsdfNode>();
switch (b_principled_node.distribution()) {
case BL::ShaderNodeBsdfPrincipled::distribution_GGX:
principled->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
principled->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
break;
case BL::ShaderNodeBsdfPrincipled::distribution_MULTI_GGX:
principled->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
principled->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
break;
}
switch (b_principled_node.subsurface_method()) {
case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY:
principled->subsurface_method = CLOSURE_BSSRDF_PRINCIPLED_ID;
principled->set_subsurface_method(CLOSURE_BSSRDF_PRINCIPLED_ID);
break;
case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK:
principled->subsurface_method = CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID;
principled->set_subsurface_method(CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID);
break;
}
node = principled;
@ -602,9 +618,9 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
BL::ShaderNodeAmbientOcclusion b_ao_node(b_node);
AmbientOcclusionNode *ao = graph->create_node<AmbientOcclusionNode>();
ao->samples = b_ao_node.samples();
ao->inside = b_ao_node.inside();
ao->only_local = b_ao_node.only_local();
ao->set_samples(b_ao_node.samples());
ao->set_inside(b_ao_node.inside());
ao->set_only_local(b_ao_node.only_local());
node = ao;
}
else if (b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
@ -623,7 +639,7 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeWireframe)) {
BL::ShaderNodeWireframe b_wireframe_node(b_node);
WireframeNode *wire = graph->create_node<WireframeNode>();
wire->use_pixel_size = b_wireframe_node.use_pixel_size();
wire->set_use_pixel_size(b_wireframe_node.use_pixel_size());
node = wire;
}
else if (b_node.is_a(&RNA_ShaderNodeWavelength)) {
@ -653,13 +669,13 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeVertexColor)) {
BL::ShaderNodeVertexColor b_vertex_color_node(b_node);
VertexColorNode *vertex_color_node = graph->create_node<VertexColorNode>();
vertex_color_node->layer_name = b_vertex_color_node.layer_name();
vertex_color_node->set_layer_name(ustring(b_vertex_color_node.layer_name()));
node = vertex_color_node;
}
else if (b_node.is_a(&RNA_ShaderNodeBump)) {
BL::ShaderNodeBump b_bump_node(b_node);
BumpNode *bump = graph->create_node<BumpNode>();
bump->invert = b_bump_node.invert();
bump->set_invert(b_bump_node.invert());
node = bump;
}
else if (b_node.is_a(&RNA_ShaderNodeScript)) {
@ -692,25 +708,26 @@ static ShaderNode *add_node(Scene *scene,
BL::ImageUser b_image_user(b_image_node.image_user());
ImageTextureNode *image = graph->create_node<ImageTextureNode>();
image->interpolation = get_image_interpolation(b_image_node);
image->extension = get_image_extension(b_image_node);
image->projection = (NodeImageProjection)b_image_node.projection();
image->projection_blend = b_image_node.projection_blend();
image->set_interpolation(get_image_interpolation(b_image_node));
image->set_extension(get_image_extension(b_image_node));
image->set_projection((NodeImageProjection)b_image_node.projection());
image->set_projection_blend(b_image_node.projection_blend());
BL::TexMapping b_texture_mapping(b_image_node.texture_mapping());
get_tex_mapping(&image->tex_mapping, b_texture_mapping);
get_tex_mapping(image, b_texture_mapping);
if (b_image) {
PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
image->colorspace = get_enum_identifier(colorspace_ptr, "name");
image->set_colorspace(ustring(get_enum_identifier(colorspace_ptr, "name")));
image->animated = b_image_node.image_user().use_auto_refresh();
image->alpha_type = get_image_alpha_type(b_image);
image->set_animated(b_image_node.image_user().use_auto_refresh());
image->set_alpha_type(get_image_alpha_type(b_image));
image->tiles.clear();
array<int> tiles;
BL::Image::tiles_iterator b_iter;
for (b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) {
image->tiles.push_back(b_iter->number());
tiles.push_back_slow(b_iter->number());
}
image->set_tiles(tiles);
/* builtin images will use callback-based reading because
* they could only be loaded correct from blender side
@ -732,8 +749,9 @@ static ShaderNode *add_node(Scene *scene,
new BlenderImageLoader(b_image, image_frame), image->image_params());
}
else {
image->filename = image_user_file_path(
b_image_user, b_image, b_scene.frame_current(), true);
ustring filename = ustring(
image_user_file_path(b_image_user, b_image, b_scene.frame_current(), true));
image->set_filename(filename);
}
}
node = image;
@ -744,17 +762,17 @@ static ShaderNode *add_node(Scene *scene,
BL::ImageUser b_image_user(b_env_node.image_user());
EnvironmentTextureNode *env = graph->create_node<EnvironmentTextureNode>();
env->interpolation = get_image_interpolation(b_env_node);
env->projection = (NodeEnvironmentProjection)b_env_node.projection();
env->set_interpolation(get_image_interpolation(b_env_node));
env->set_projection((NodeEnvironmentProjection)b_env_node.projection());
BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
get_tex_mapping(&env->tex_mapping, b_texture_mapping);
get_tex_mapping(env, b_texture_mapping);
if (b_image) {
PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
env->colorspace = get_enum_identifier(colorspace_ptr, "name");
env->set_colorspace(ustring(get_enum_identifier(colorspace_ptr, "name")));
env->animated = b_env_node.image_user().use_auto_refresh();
env->alpha_type = get_image_alpha_type(b_image);
env->set_animated(b_env_node.image_user().use_auto_refresh());
env->set_alpha_type(get_image_alpha_type(b_image));
bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED ||
b_image.source() == BL::Image::source_MOVIE ||
@ -767,8 +785,8 @@ static ShaderNode *add_node(Scene *scene,
env->image_params());
}
else {
env->filename = image_user_file_path(
b_image_user, b_image, b_scene.frame_current(), false);
env->set_filename(
ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current(), false)));
}
}
node = env;
@ -776,103 +794,103 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeTexGradient)) {
BL::ShaderNodeTexGradient b_gradient_node(b_node);
GradientTextureNode *gradient = graph->create_node<GradientTextureNode>();
gradient->type = (NodeGradientType)b_gradient_node.gradient_type();
gradient->set_gradient_type((NodeGradientType)b_gradient_node.gradient_type());
BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping());
get_tex_mapping(&gradient->tex_mapping, b_texture_mapping);
get_tex_mapping(gradient, b_texture_mapping);
node = gradient;
}
else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
VoronoiTextureNode *voronoi = graph->create_node<VoronoiTextureNode>();
voronoi->dimensions = b_voronoi_node.voronoi_dimensions();
voronoi->feature = (NodeVoronoiFeature)b_voronoi_node.feature();
voronoi->metric = (NodeVoronoiDistanceMetric)b_voronoi_node.distance();
voronoi->set_dimensions(b_voronoi_node.voronoi_dimensions());
voronoi->set_feature((NodeVoronoiFeature)b_voronoi_node.feature());
voronoi->set_metric((NodeVoronoiDistanceMetric)b_voronoi_node.distance());
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping);
get_tex_mapping(voronoi, b_texture_mapping);
node = voronoi;
}
else if (b_node.is_a(&RNA_ShaderNodeTexMagic)) {
BL::ShaderNodeTexMagic b_magic_node(b_node);
MagicTextureNode *magic = graph->create_node<MagicTextureNode>();
magic->depth = b_magic_node.turbulence_depth();
magic->set_depth(b_magic_node.turbulence_depth());
BL::TexMapping b_texture_mapping(b_magic_node.texture_mapping());
get_tex_mapping(&magic->tex_mapping, b_texture_mapping);
get_tex_mapping(magic, b_texture_mapping);
node = magic;
}
else if (b_node.is_a(&RNA_ShaderNodeTexWave)) {
BL::ShaderNodeTexWave b_wave_node(b_node);
WaveTextureNode *wave = graph->create_node<WaveTextureNode>();
wave->type = (NodeWaveType)b_wave_node.wave_type();
wave->bands_direction = (NodeWaveBandsDirection)b_wave_node.bands_direction();
wave->rings_direction = (NodeWaveRingsDirection)b_wave_node.rings_direction();
wave->profile = (NodeWaveProfile)b_wave_node.wave_profile();
wave->set_wave_type((NodeWaveType)b_wave_node.wave_type());
wave->set_bands_direction((NodeWaveBandsDirection)b_wave_node.bands_direction());
wave->set_rings_direction((NodeWaveRingsDirection)b_wave_node.rings_direction());
wave->set_profile((NodeWaveProfile)b_wave_node.wave_profile());
BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping());
get_tex_mapping(&wave->tex_mapping, b_texture_mapping);
get_tex_mapping(wave, b_texture_mapping);
node = wave;
}
else if (b_node.is_a(&RNA_ShaderNodeTexChecker)) {
BL::ShaderNodeTexChecker b_checker_node(b_node);
CheckerTextureNode *checker = graph->create_node<CheckerTextureNode>();
BL::TexMapping b_texture_mapping(b_checker_node.texture_mapping());
get_tex_mapping(&checker->tex_mapping, b_texture_mapping);
get_tex_mapping(checker, b_texture_mapping);
node = checker;
}
else if (b_node.is_a(&RNA_ShaderNodeTexBrick)) {
BL::ShaderNodeTexBrick b_brick_node(b_node);
BrickTextureNode *brick = graph->create_node<BrickTextureNode>();
brick->offset = b_brick_node.offset();
brick->offset_frequency = b_brick_node.offset_frequency();
brick->squash = b_brick_node.squash();
brick->squash_frequency = b_brick_node.squash_frequency();
brick->set_offset(b_brick_node.offset());
brick->set_offset_frequency(b_brick_node.offset_frequency());
brick->set_squash(b_brick_node.squash());
brick->set_squash_frequency(b_brick_node.squash_frequency());
BL::TexMapping b_texture_mapping(b_brick_node.texture_mapping());
get_tex_mapping(&brick->tex_mapping, b_texture_mapping);
get_tex_mapping(brick, b_texture_mapping);
node = brick;
}
else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) {
BL::ShaderNodeTexNoise b_noise_node(b_node);
NoiseTextureNode *noise = graph->create_node<NoiseTextureNode>();
noise->dimensions = b_noise_node.noise_dimensions();
noise->set_dimensions(b_noise_node.noise_dimensions());
BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping());
get_tex_mapping(&noise->tex_mapping, b_texture_mapping);
get_tex_mapping(noise, b_texture_mapping);
node = noise;
}
else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
MusgraveTextureNode *musgrave_node = graph->create_node<MusgraveTextureNode>();
musgrave_node->type = (NodeMusgraveType)b_musgrave_node.musgrave_type();
musgrave_node->dimensions = b_musgrave_node.musgrave_dimensions();
musgrave_node->set_musgrave_type((NodeMusgraveType)b_musgrave_node.musgrave_type());
musgrave_node->set_dimensions(b_musgrave_node.musgrave_dimensions());
BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
get_tex_mapping(&musgrave_node->tex_mapping, b_texture_mapping);
get_tex_mapping(musgrave_node, b_texture_mapping);
node = musgrave_node;
}
else if (b_node.is_a(&RNA_ShaderNodeTexCoord)) {
BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
TextureCoordinateNode *tex_coord = graph->create_node<TextureCoordinateNode>();
tex_coord->from_dupli = b_tex_coord_node.from_instancer();
tex_coord->set_from_dupli(b_tex_coord_node.from_instancer());
if (b_tex_coord_node.object()) {
tex_coord->use_transform = true;
tex_coord->ob_tfm = get_transform(b_tex_coord_node.object().matrix_world());
tex_coord->set_use_transform(true);
tex_coord->set_ob_tfm(get_transform(b_tex_coord_node.object().matrix_world()));
}
node = tex_coord;
}
else if (b_node.is_a(&RNA_ShaderNodeTexSky)) {
BL::ShaderNodeTexSky b_sky_node(b_node);
SkyTextureNode *sky = graph->create_node<SkyTextureNode>();
sky->type = (NodeSkyType)b_sky_node.sky_type();
sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction()));
sky->turbidity = b_sky_node.turbidity();
sky->ground_albedo = b_sky_node.ground_albedo();
sky->sun_disc = b_sky_node.sun_disc();
sky->sun_size = b_sky_node.sun_size();
sky->sun_intensity = b_sky_node.sun_intensity();
sky->sun_elevation = b_sky_node.sun_elevation();
sky->sun_rotation = b_sky_node.sun_rotation();
sky->altitude = 1000.0f * b_sky_node.altitude();
sky->air_density = b_sky_node.air_density();
sky->dust_density = b_sky_node.dust_density();
sky->ozone_density = b_sky_node.ozone_density();
sky->set_sky_type((NodeSkyType)b_sky_node.sky_type());
sky->set_sun_direction(normalize(get_float3(b_sky_node.sun_direction())));
sky->set_turbidity(b_sky_node.turbidity());
sky->set_ground_albedo(b_sky_node.ground_albedo());
sky->set_sun_disc(b_sky_node.sun_disc());
sky->set_sun_size(b_sky_node.sun_size());
sky->set_sun_intensity(b_sky_node.sun_intensity());
sky->set_sun_elevation(b_sky_node.sun_elevation());
sky->set_sun_rotation(b_sky_node.sun_rotation());
sky->set_altitude(1000.0f * b_sky_node.altitude());
sky->set_air_density(b_sky_node.air_density());
sky->set_dust_density(b_sky_node.dust_density());
sky->set_ozone_density(b_sky_node.ozone_density());
BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping());
get_tex_mapping(&sky->tex_mapping, b_texture_mapping);
get_tex_mapping(sky, b_texture_mapping);
node = sky;
}
else if (b_node.is_a(&RNA_ShaderNodeTexIES)) {
@ -880,13 +898,14 @@ static ShaderNode *add_node(Scene *scene,
IESLightNode *ies = graph->create_node<IESLightNode>();
switch (b_ies_node.mode()) {
case BL::ShaderNodeTexIES::mode_EXTERNAL:
ies->filename = blender_absolute_path(b_data, b_ntree, b_ies_node.filepath());
ies->set_filename(ustring(blender_absolute_path(b_data, b_ntree, b_ies_node.filepath())));
break;
case BL::ShaderNodeTexIES::mode_INTERNAL:
ies->ies = get_text_datablock_content(b_ies_node.ies().ptr);
if (ies->ies.empty()) {
ies->ies = "\n";
ustring ies_content = ustring(get_text_datablock_content(b_ies_node.ies().ptr));
if (ies_content.empty()) {
ies_content = "\n";
}
ies->set_ies(ies_content);
break;
}
node = ies;
@ -894,36 +913,36 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeTexWhiteNoise)) {
BL::ShaderNodeTexWhiteNoise b_tex_white_noise_node(b_node);
WhiteNoiseTextureNode *white_noise_node = graph->create_node<WhiteNoiseTextureNode>();
white_noise_node->dimensions = b_tex_white_noise_node.noise_dimensions();
white_noise_node->set_dimensions(b_tex_white_noise_node.noise_dimensions());
node = white_noise_node;
}
else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) {
BL::ShaderNodeNormalMap b_normal_map_node(b_node);
NormalMapNode *nmap = graph->create_node<NormalMapNode>();
nmap->space = (NodeNormalMapSpace)b_normal_map_node.space();
nmap->attribute = b_normal_map_node.uv_map();
nmap->set_space((NodeNormalMapSpace)b_normal_map_node.space());
nmap->set_attribute(ustring(b_normal_map_node.uv_map()));
node = nmap;
}
else if (b_node.is_a(&RNA_ShaderNodeTangent)) {
BL::ShaderNodeTangent b_tangent_node(b_node);
TangentNode *tangent = graph->create_node<TangentNode>();
tangent->direction_type = (NodeTangentDirectionType)b_tangent_node.direction_type();
tangent->axis = (NodeTangentAxis)b_tangent_node.axis();
tangent->attribute = b_tangent_node.uv_map();
tangent->set_direction_type((NodeTangentDirectionType)b_tangent_node.direction_type());
tangent->set_axis((NodeTangentAxis)b_tangent_node.axis());
tangent->set_attribute(ustring(b_tangent_node.uv_map()));
node = tangent;
}
else if (b_node.is_a(&RNA_ShaderNodeUVMap)) {
BL::ShaderNodeUVMap b_uvmap_node(b_node);
UVMapNode *uvm = graph->create_node<UVMapNode>();
uvm->attribute = b_uvmap_node.uv_map();
uvm->from_dupli = b_uvmap_node.from_instancer();
uvm->set_attribute(ustring(b_uvmap_node.uv_map()));
uvm->set_from_dupli(b_uvmap_node.from_instancer());
node = uvm;
}
else if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
PointDensityTextureNode *point_density = graph->create_node<PointDensityTextureNode>();
point_density->space = (NodeTexVoxelSpace)b_point_density_node.space();
point_density->interpolation = get_image_interpolation(b_point_density_node);
point_density->set_space((NodeTexVoxelSpace)b_point_density_node.space());
point_density->set_interpolation(get_image_interpolation(b_point_density_node));
point_density->handle = scene->image_manager->add_image(
new BlenderPointDensityLoader(b_depsgraph, b_point_density_node),
point_density->image_params());
@ -940,33 +959,33 @@ static ShaderNode *add_node(Scene *scene,
if (b_ob) {
float3 loc, size;
point_density_texture_space(b_depsgraph, b_point_density_node, loc, size);
point_density->tfm = transform_translate(-loc) * transform_scale(size) *
transform_inverse(get_transform(b_ob.matrix_world()));
point_density->set_tfm(transform_translate(-loc) * transform_scale(size) *
transform_inverse(get_transform(b_ob.matrix_world())));
}
}
else if (b_node.is_a(&RNA_ShaderNodeBevel)) {
BL::ShaderNodeBevel b_bevel_node(b_node);
BevelNode *bevel = graph->create_node<BevelNode>();
bevel->samples = b_bevel_node.samples();
bevel->set_samples(b_bevel_node.samples());
node = bevel;
}
else if (b_node.is_a(&RNA_ShaderNodeDisplacement)) {
BL::ShaderNodeDisplacement b_disp_node(b_node);
DisplacementNode *disp = graph->create_node<DisplacementNode>();
disp->space = (NodeNormalMapSpace)b_disp_node.space();
disp->set_space((NodeNormalMapSpace)b_disp_node.space());
node = disp;
}
else if (b_node.is_a(&RNA_ShaderNodeVectorDisplacement)) {
BL::ShaderNodeVectorDisplacement b_disp_node(b_node);
VectorDisplacementNode *disp = graph->create_node<VectorDisplacementNode>();
disp->space = (NodeNormalMapSpace)b_disp_node.space();
disp->attribute = "";
disp->set_space((NodeNormalMapSpace)b_disp_node.space());
disp->set_attribute(ustring(""));
node = disp;
}
else if (b_node.is_a(&RNA_ShaderNodeOutputAOV)) {
BL::ShaderNodeOutputAOV b_aov_node(b_node);
OutputAOVNode *aov = graph->create_node<OutputAOVNode>();
aov->name = b_aov_node.name();
aov->set_name(ustring(b_aov_node.name()));
node = aov;
}
@ -1293,7 +1312,7 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
ShaderGraph *graph = new ShaderGraph();
shader->name = b_mat.name().c_str();
shader->pass_id = b_mat.pass_index();
shader->set_pass_id(b_mat.pass_index());
/* create nodes */
if (b_mat.use_nodes() && b_mat.node_tree()) {
@ -1303,7 +1322,7 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
}
else {
DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
diffuse->color = get_float3(b_mat.diffuse_color());
diffuse->set_color(get_float3(b_mat.diffuse_color()));
graph->add(diffuse);
ShaderNode *out = graph->output();
@ -1312,13 +1331,13 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
/* settings */
PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles");
shader->use_mis = get_boolean(cmat, "sample_as_light");
shader->use_transparent_shadow = get_boolean(cmat, "use_transparent_shadow");
shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume");
shader->volume_sampling_method = get_volume_sampling(cmat);
shader->volume_interpolation_method = get_volume_interpolation(cmat);
shader->volume_step_rate = get_float(cmat, "volume_step_rate");
shader->displacement_method = get_displacement_method(cmat);
shader->set_use_mis(get_boolean(cmat, "sample_as_light"));
shader->set_use_transparent_shadow(get_boolean(cmat, "use_transparent_shadow"));
shader->set_heterogeneous_volume(!get_boolean(cmat, "homogeneous_volume"));
shader->set_volume_sampling_method(get_volume_sampling(cmat));
shader->set_volume_interpolation_method(get_volume_interpolation(cmat));
shader->set_volume_step_rate(get_float(cmat, "volume_step_rate"));
shader->set_displacement_method(get_displacement_method(cmat));
shader->set_graph(graph);
@ -1359,7 +1378,6 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all)
{
Background *background = scene->background;
Background prevbackground = *background;
BL::World b_world = b_scene.world();
@ -1379,14 +1397,14 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
/* volume */
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
shader->heterogeneous_volume = !get_boolean(cworld, "homogeneous_volume");
shader->volume_sampling_method = get_volume_sampling(cworld);
shader->volume_interpolation_method = get_volume_interpolation(cworld);
shader->volume_step_rate = get_float(cworld, "volume_step_size");
shader->set_heterogeneous_volume(!get_boolean(cworld, "homogeneous_volume"));
shader->set_volume_sampling_method(get_volume_sampling(cworld));
shader->set_volume_interpolation_method(get_volume_interpolation(cworld));
shader->set_volume_step_rate(get_float(cworld, "volume_step_size"));
}
else if (new_viewport_parameters.use_scene_world && b_world) {
BackgroundNode *background = graph->create_node<BackgroundNode>();
background->color = get_float3(b_world.color());
background->set_color(get_float3(b_world.color()));
graph->add(background);
ShaderNode *out = graph->output();
@ -1408,29 +1426,32 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
graph->add(light_path);
MixNode *mix_scene_with_background = graph->create_node<MixNode>();
mix_scene_with_background->color2 = world_color;
mix_scene_with_background->set_color2(world_color);
graph->add(mix_scene_with_background);
EnvironmentTextureNode *texture_environment = graph->create_node<EnvironmentTextureNode>();
texture_environment->tex_mapping.type = TextureMapping::VECTOR;
texture_environment->tex_mapping.rotation[2] = new_viewport_parameters.studiolight_rotate_z;
texture_environment->filename = new_viewport_parameters.studiolight_path;
texture_environment->set_tex_mapping_type(TextureMapping::VECTOR);
float3 rotation_z = texture_environment->get_tex_mapping_rotation();
rotation_z[2] = new_viewport_parameters.studiolight_rotate_z;
texture_environment->set_tex_mapping_rotation(rotation_z);
texture_environment->set_filename(new_viewport_parameters.studiolight_path);
graph->add(texture_environment);
MixNode *mix_intensity = graph->create_node<MixNode>();
mix_intensity->type = NODE_MIX_MUL;
mix_intensity->fac = 1.0f;
mix_intensity->color2 = make_float3(new_viewport_parameters.studiolight_intensity,
new_viewport_parameters.studiolight_intensity,
new_viewport_parameters.studiolight_intensity);
mix_intensity->set_mix_type(NODE_MIX_MUL);
mix_intensity->set_fac(1.0f);
mix_intensity->set_color2(make_float3(new_viewport_parameters.studiolight_intensity,
new_viewport_parameters.studiolight_intensity,
new_viewport_parameters.studiolight_intensity));
graph->add(mix_intensity);
TextureCoordinateNode *texture_coordinate = graph->create_node<TextureCoordinateNode>();
graph->add(texture_coordinate);
MixNode *mix_background_with_environment = graph->create_node<MixNode>();
mix_background_with_environment->fac = new_viewport_parameters.studiolight_background_alpha;
mix_background_with_environment->color1 = world_color;
mix_background_with_environment->set_fac(
new_viewport_parameters.studiolight_background_alpha);
mix_background_with_environment->set_color1(world_color);
graph->add(mix_background_with_environment);
ShaderNode *out = graph->output();
@ -1452,9 +1473,9 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
/* AO */
BL::WorldLighting b_light = b_world.light_settings();
background->use_ao = b_light.use_ambient_occlusion();
background->ao_factor = b_light.ao_factor();
background->ao_distance = b_light.distance();
background->set_use_ao(b_light.use_ambient_occlusion());
background->set_ao_factor(b_light.ao_factor());
background->set_ao_distance(b_light.distance());
/* visibility */
PointerRNA cvisibility = RNA_pointer_get(&b_world.ptr, "cycles_visibility");
@ -1466,12 +1487,12 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
visibility |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0;
visibility |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0;
background->visibility = visibility;
background->set_visibility(visibility);
}
else {
background->use_ao = false;
background->ao_factor = 0.0f;
background->ao_distance = FLT_MAX;
background->set_use_ao(false);
background->set_ao_factor(0.0f);
background->set_ao_distance(FLT_MAX);
}
shader->set_graph(graph);
@ -1480,22 +1501,23 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
}
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
background->transparent = b_scene.render().film_transparent();
background->set_transparent(b_scene.render().film_transparent());
if (background->transparent) {
background->transparent_glass = get_boolean(cscene, "film_transparent_glass");
background->transparent_roughness_threshold = get_float(cscene, "film_transparent_roughness");
if (background->get_transparent()) {
background->set_transparent_glass(get_boolean(cscene, "film_transparent_glass"));
background->set_transparent_roughness_threshold(
get_float(cscene, "film_transparent_roughness"));
}
else {
background->transparent_glass = false;
background->transparent_roughness_threshold = 0.0f;
background->set_transparent_glass(false);
background->set_transparent_roughness_threshold(0.0f);
}
background->use_shader = view_layer.use_background_shader |
viewport_parameters.custom_viewport_parameters();
background->use_ao = background->use_ao && view_layer.use_background_ao;
background->set_use_shader(view_layer.use_background_shader |
viewport_parameters.custom_viewport_parameters());
background->set_use_ao(background->get_use_ao() && view_layer.use_background_ao);
if (background->modified(prevbackground))
if (background->is_modified())
background->tag_update(scene);
}
@ -1528,8 +1550,8 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
}
else {
EmissionNode *emission = graph->create_node<EmissionNode>();
emission->color = make_float3(1.0f, 1.0f, 1.0f);
emission->strength = 1.0f;
emission->set_color(make_float3(1.0f, 1.0f, 1.0f));
emission->set_strength(1.0f);
graph->add(emission);
ShaderNode *out = graph->output();

@ -118,9 +118,9 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
if (dicing_prop_changed) {
for (const pair<const GeometryKey, Geometry *> &iter : geometry_map.key_to_scene_data()) {
Geometry *geom = iter.second;
if (geom->type == Geometry::MESH) {
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) {
if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
PointerRNA id_ptr;
RNA_id_pointer_create((::ID *)iter.first.id, &id_ptr);
geometry_map.set_recalc(BL::ID(id_ptr));
@ -238,7 +238,7 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
geometry_synced.clear(); /* use for objects and motion sync */
if (scene->need_motion() == Scene::MOTION_PASS || scene->need_motion() == Scene::MOTION_NONE ||
scene->camera->motion_position == Camera::MOTION_POSITION_CENTER) {
scene->camera->get_motion_position() == Camera::MOTION_POSITION_CENTER) {
sync_objects(b_depsgraph, b_v3d);
}
sync_motion(b_render, b_depsgraph, b_v3d, b_override, width, height, python_thread_state);
@ -264,70 +264,75 @@ void BlenderSync::sync_integrator()
experimental = (get_enum(cscene, "feature_set") != 0);
Integrator *integrator = scene->integrator;
Integrator previntegrator = *integrator;
integrator->min_bounce = get_int(cscene, "min_light_bounces");
integrator->max_bounce = get_int(cscene, "max_bounces");
integrator->set_min_bounce(get_int(cscene, "min_light_bounces"));
integrator->set_max_bounce(get_int(cscene, "max_bounces"));
integrator->max_diffuse_bounce = get_int(cscene, "diffuse_bounces");
integrator->max_glossy_bounce = get_int(cscene, "glossy_bounces");
integrator->max_transmission_bounce = get_int(cscene, "transmission_bounces");
integrator->max_volume_bounce = get_int(cscene, "volume_bounces");
integrator->set_max_diffuse_bounce(get_int(cscene, "diffuse_bounces"));
integrator->set_max_glossy_bounce(get_int(cscene, "glossy_bounces"));
integrator->set_max_transmission_bounce(get_int(cscene, "transmission_bounces"));
integrator->set_max_volume_bounce(get_int(cscene, "volume_bounces"));
integrator->transparent_min_bounce = get_int(cscene, "min_transparent_bounces");
integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces");
integrator->set_transparent_min_bounce(get_int(cscene, "min_transparent_bounces"));
integrator->set_transparent_max_bounce(get_int(cscene, "transparent_max_bounces"));
integrator->volume_max_steps = get_int(cscene, "volume_max_steps");
integrator->volume_step_rate = (preview) ? get_float(cscene, "volume_preview_step_rate") :
get_float(cscene, "volume_step_rate");
integrator->set_volume_max_steps(get_int(cscene, "volume_max_steps"));
float volume_step_rate = (preview) ? get_float(cscene, "volume_preview_step_rate") :
get_float(cscene, "volume_step_rate");
integrator->set_volume_step_rate(volume_step_rate);
integrator->caustics_reflective = get_boolean(cscene, "caustics_reflective");
integrator->caustics_refractive = get_boolean(cscene, "caustics_refractive");
integrator->filter_glossy = get_float(cscene, "blur_glossy");
integrator->set_caustics_reflective(get_boolean(cscene, "caustics_reflective"));
integrator->set_caustics_refractive(get_boolean(cscene, "caustics_refractive"));
integrator->set_filter_glossy(get_float(cscene, "blur_glossy"));
integrator->seed = get_int(cscene, "seed");
int seed = get_int(cscene, "seed");
if (get_boolean(cscene, "use_animated_seed")) {
integrator->seed = hash_uint2(b_scene.frame_current(), get_int(cscene, "seed"));
seed = hash_uint2(b_scene.frame_current(), get_int(cscene, "seed"));
if (b_scene.frame_subframe() != 0.0f) {
/* TODO(sergey): Ideally should be some sort of hash_merge,
* but this is good enough for now.
*/
integrator->seed += hash_uint2((int)(b_scene.frame_subframe() * (float)INT_MAX),
get_int(cscene, "seed"));
seed += hash_uint2((int)(b_scene.frame_subframe() * (float)INT_MAX),
get_int(cscene, "seed"));
}
}
integrator->sampling_pattern = (SamplingPattern)get_enum(
integrator->set_seed(seed);
integrator->set_sample_clamp_direct(get_float(cscene, "sample_clamp_direct"));
integrator->set_sample_clamp_indirect(get_float(cscene, "sample_clamp_indirect"));
if (!preview) {
if (integrator->get_motion_blur() != r.use_motion_blur()) {
scene->object_manager->tag_update(scene);
scene->camera->tag_modified();
}
integrator->set_motion_blur(r.use_motion_blur());
}
integrator->set_method((Integrator::Method)get_enum(
cscene, "progressive", Integrator::NUM_METHODS, Integrator::PATH));
integrator->set_sample_all_lights_direct(get_boolean(cscene, "sample_all_lights_direct"));
integrator->set_sample_all_lights_indirect(get_boolean(cscene, "sample_all_lights_indirect"));
integrator->set_light_sampling_threshold(get_float(cscene, "light_sampling_threshold"));
SamplingPattern sampling_pattern = (SamplingPattern)get_enum(
cscene, "sampling_pattern", SAMPLING_NUM_PATTERNS, SAMPLING_PATTERN_SOBOL);
integrator->sample_clamp_direct = get_float(cscene, "sample_clamp_direct");
integrator->sample_clamp_indirect = get_float(cscene, "sample_clamp_indirect");
if (!preview) {
if (integrator->motion_blur != r.use_motion_blur()) {
scene->object_manager->tag_update(scene);
scene->camera->tag_update();
}
integrator->motion_blur = r.use_motion_blur();
}
integrator->method = (Integrator::Method)get_enum(
cscene, "progressive", Integrator::NUM_METHODS, Integrator::PATH);
integrator->sample_all_lights_direct = get_boolean(cscene, "sample_all_lights_direct");
integrator->sample_all_lights_indirect = get_boolean(cscene, "sample_all_lights_indirect");
integrator->light_sampling_threshold = get_float(cscene, "light_sampling_threshold");
int adaptive_min_samples = INT_MAX;
if (RNA_boolean_get(&cscene, "use_adaptive_sampling")) {
integrator->sampling_pattern = SAMPLING_PATTERN_PMJ;
integrator->adaptive_min_samples = get_int(cscene, "adaptive_min_samples");
integrator->adaptive_threshold = get_float(cscene, "adaptive_threshold");
sampling_pattern = SAMPLING_PATTERN_PMJ;
adaptive_min_samples = get_int(cscene, "adaptive_min_samples");
integrator->set_adaptive_threshold(get_float(cscene, "adaptive_threshold"));
}
else {
integrator->adaptive_min_samples = INT_MAX;
integrator->adaptive_threshold = 0.0f;
integrator->set_adaptive_threshold(0.0f);
}
integrator->set_sampling_pattern(sampling_pattern);
int diffuse_samples = get_int(cscene, "diffuse_samples");
int glossy_samples = get_int(cscene, "glossy_samples");
int transmission_samples = get_int(cscene, "transmission_samples");
@ -337,39 +342,40 @@ void BlenderSync::sync_integrator()
int volume_samples = get_int(cscene, "volume_samples");
if (get_boolean(cscene, "use_square_samples")) {
integrator->diffuse_samples = diffuse_samples * diffuse_samples;
integrator->glossy_samples = glossy_samples * glossy_samples;
integrator->transmission_samples = transmission_samples * transmission_samples;
integrator->ao_samples = ao_samples * ao_samples;
integrator->mesh_light_samples = mesh_light_samples * mesh_light_samples;
integrator->subsurface_samples = subsurface_samples * subsurface_samples;
integrator->volume_samples = volume_samples * volume_samples;
integrator->adaptive_min_samples = min(
integrator->adaptive_min_samples * integrator->adaptive_min_samples, INT_MAX);
integrator->set_diffuse_samples(diffuse_samples * diffuse_samples);
integrator->set_glossy_samples(glossy_samples * glossy_samples);
integrator->set_transmission_samples(transmission_samples * transmission_samples);
integrator->set_ao_samples(ao_samples * ao_samples);
integrator->set_mesh_light_samples(mesh_light_samples * mesh_light_samples);
integrator->set_subsurface_samples(subsurface_samples * subsurface_samples);
integrator->set_volume_samples(volume_samples * volume_samples);
adaptive_min_samples = min(adaptive_min_samples * adaptive_min_samples, INT_MAX);
}
else {
integrator->diffuse_samples = diffuse_samples;
integrator->glossy_samples = glossy_samples;
integrator->transmission_samples = transmission_samples;
integrator->ao_samples = ao_samples;
integrator->mesh_light_samples = mesh_light_samples;
integrator->subsurface_samples = subsurface_samples;
integrator->volume_samples = volume_samples;
integrator->set_diffuse_samples(diffuse_samples);
integrator->set_glossy_samples(glossy_samples);
integrator->set_transmission_samples(transmission_samples);
integrator->set_ao_samples(ao_samples);
integrator->set_mesh_light_samples(mesh_light_samples);
integrator->set_subsurface_samples(subsurface_samples);
integrator->set_volume_samples(volume_samples);
}
integrator->set_adaptive_min_samples(adaptive_min_samples);
if (b_scene.render().use_simplify()) {
if (preview) {
integrator->ao_bounces = get_int(cscene, "ao_bounces");
integrator->set_ao_bounces(get_int(cscene, "ao_bounces"));
}
else {
integrator->ao_bounces = get_int(cscene, "ao_bounces_render");
integrator->set_ao_bounces(get_int(cscene, "ao_bounces_render"));
}
}
else {
integrator->ao_bounces = 0;
integrator->set_ao_bounces(0);
}
if (integrator->modified(previntegrator))
if (integrator->is_modified())
integrator->tag_update(scene);
}
@ -380,46 +386,42 @@ void BlenderSync::sync_film(BL::SpaceView3D &b_v3d)
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
Film *film = scene->film;
Film prevfilm = *film;
vector<Pass> prevpasses = scene->passes;
if (b_v3d) {
film->display_pass = update_viewport_display_passes(b_v3d, scene->passes);
film->set_display_pass(update_viewport_display_passes(b_v3d, scene->passes));
}
film->exposure = get_float(cscene, "film_exposure");
film->filter_type = (FilterType)get_enum(
cscene, "pixel_filter_type", FILTER_NUM_TYPES, FILTER_BLACKMAN_HARRIS);
film->filter_width = (film->filter_type == FILTER_BOX) ? 1.0f :
get_float(cscene, "filter_width");
film->set_exposure(get_float(cscene, "film_exposure"));
film->set_filter_type(
(FilterType)get_enum(cscene, "pixel_filter_type", FILTER_NUM_TYPES, FILTER_BLACKMAN_HARRIS));
float filter_width = (film->get_filter_type() == FILTER_BOX) ? 1.0f :
get_float(cscene, "filter_width");
film->set_filter_width(filter_width);
if (b_scene.world()) {
BL::WorldMistSettings b_mist = b_scene.world().mist_settings();
film->mist_start = b_mist.start();
film->mist_depth = b_mist.depth();
film->set_mist_start(b_mist.start());
film->set_mist_depth(b_mist.depth());
switch (b_mist.falloff()) {
case BL::WorldMistSettings::falloff_QUADRATIC:
film->mist_falloff = 2.0f;
film->set_mist_falloff(2.0f);
break;
case BL::WorldMistSettings::falloff_LINEAR:
film->mist_falloff = 1.0f;
film->set_mist_falloff(1.0f);
break;
case BL::WorldMistSettings::falloff_INVERSE_QUADRATIC:
film->mist_falloff = 0.5f;
film->set_mist_falloff(0.5f);
break;
}
}
if (film->modified(prevfilm)) {
film->tag_update(scene);
}
if (!Pass::equals(prevpasses, scene->passes)) {
film->tag_passes_update(scene, prevpasses, false);
film->tag_update(scene);
film->tag_modified();
}
}
@ -585,7 +587,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
BL::RenderPass b_pass(*b_pass_iter);
PassType pass_type = get_pass_type(b_pass);
if (pass_type == PASS_MOTION && scene->integrator->motion_blur)
if (pass_type == PASS_MOTION && scene->integrator->get_motion_blur())
continue;
if (pass_type != PASS_NONE)
Pass::add(pass_type, passes, b_pass.name().c_str());
@ -593,12 +595,12 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
scene->film->denoising_flags = 0;
int denoising_flags = 0;
if (denoising.use || denoising.store_passes) {
if (denoising.type == DENOISER_NLM) {
#define MAP_OPTION(name, flag) \
if (!get_boolean(crl, name)) { \
scene->film->denoising_flags |= flag; \
denoising_flags |= flag; \
} \
((void)0)
MAP_OPTION("denoising_diffuse_direct", DENOISING_CLEAN_DIFFUSE_DIR);
@ -611,6 +613,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
}
b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
}
scene->film->set_denoising_flags(denoising_flags);
if (denoising.store_passes) {
b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
@ -622,7 +625,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
b_engine.add_pass("Denoising Intensity", 1, "X", b_view_layer.name().c_str());
}
if (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES) {
if (scene->film->get_denoising_flags() & DENOISING_CLEAN_ALL_PASSES) {
b_engine.add_pass("Denoising Clean", 3, "RGB", b_view_layer.name().c_str());
}
}
@ -665,16 +668,15 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
/* Cryptomatte stores two ID/weight pairs per RGBA layer.
* User facing parameter is the number of pairs. */
int crypto_depth = divide_up(min(16, get_int(crl, "pass_crypto_depth")), 2);
scene->film->cryptomatte_depth = crypto_depth;
scene->film->cryptomatte_passes = CRYPT_NONE;
scene->film->set_cryptomatte_depth(crypto_depth);
CryptomatteType cryptomatte_passes = CRYPT_NONE;
if (get_boolean(crl, "use_pass_crypto_object")) {
for (int i = 0; i < crypto_depth; i++) {
string passname = cryptomatte_prefix + string_printf("Object%02d", i);
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
}
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes |
CRYPT_OBJECT);
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_OBJECT);
}
if (get_boolean(crl, "use_pass_crypto_material")) {
for (int i = 0; i < crypto_depth; i++) {
@ -682,8 +684,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
}
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes |
CRYPT_MATERIAL);
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_MATERIAL);
}
if (get_boolean(crl, "use_pass_crypto_asset")) {
for (int i = 0; i < crypto_depth; i++) {
@ -691,13 +692,12 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
}
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes |
CRYPT_ASSET);
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ASSET);
}
if (get_boolean(crl, "pass_crypto_accurate") && scene->film->cryptomatte_passes != CRYPT_NONE) {
scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes |
CRYPT_ACCURATE);
if (get_boolean(crl, "pass_crypto_accurate") && cryptomatte_passes != CRYPT_NONE) {
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ACCURATE);
}
scene->film->set_cryptomatte_passes(cryptomatte_passes);
if (adaptive_sampling) {
Pass::add(PASS_ADAPTIVE_AUX_BUFFER, passes);
@ -721,14 +721,14 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay,
}
RNA_END;
scene->film->denoising_data_pass = denoising.use || denoising.store_passes;
scene->film->denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES);
scene->film->denoising_prefiltered_pass = denoising.store_passes &&
denoising.type == DENOISER_NLM;
scene->film->set_denoising_data_pass(denoising.use || denoising.store_passes);
scene->film->set_denoising_clean_pass(scene->film->get_denoising_flags() &
DENOISING_CLEAN_ALL_PASSES);
scene->film->set_denoising_prefiltered_pass(denoising.store_passes &&
denoising.type == DENOISER_NLM);
scene->film->pass_alpha_threshold = b_view_layer.pass_alpha_threshold();
scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
scene->film->tag_passes_update(scene, passes);
scene->film->tag_update(scene);
scene->integrator->tag_update(scene);
return passes;

@ -207,7 +207,7 @@ class BlenderSync {
void free_data_after_sync(BL::Depsgraph &b_depsgraph);
/* util */
void find_shader(BL::ID &id, vector<Shader *> &used_shaders, Shader *default_shader);
void find_shader(BL::ID &id, array<Node *> &used_shaders, Shader *default_shader);
bool BKE_object_is_modified(BL::Object &b_ob);
bool object_is_geometry(BL::Object &b_ob);
bool object_is_light(BL::Object &b_ob);

@ -202,7 +202,7 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Volume *volume, fl
continue;
}
volume->clipping = b_domain.clipping();
volume->set_clipping(b_domain.clipping());
Attribute *attr = volume->attributes.add(std);
@ -262,9 +262,9 @@ static void sync_volume_object(BL::BlendData &b_data,
BL::VolumeRender b_render(b_volume.render());
volume->clipping = b_render.clipping();
volume->step_size = b_render.step_size();
volume->object_space = (b_render.space() == BL::VolumeRender::space_OBJECT);
volume->set_clipping(b_render.clipping());
volume->set_step_size(b_render.step_size());
volume->set_object_space((b_render.space() == BL::VolumeRender::space_OBJECT));
/* Find grid with matching name. */
BL::Volume::grids_iterator b_grid_iter;

@ -209,30 +209,30 @@ void BVH::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility)
/* Primitives. */
if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
/* Curves. */
const Hair *hair = static_cast<const Hair *>(ob->geometry);
const Hair *hair = static_cast<const Hair *>(ob->get_geometry());
int prim_offset = (params.top_level) ? hair->prim_offset : 0;
Hair::Curve curve = hair->get_curve(pidx - prim_offset);
int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
curve.bounds_grow(k, &hair->curve_keys[0], &hair->curve_radius[0], bbox);
curve.bounds_grow(k, &hair->get_curve_keys()[0], &hair->get_curve_radius()[0], bbox);
/* Motion curves. */
if (hair->use_motion_blur) {
if (hair->get_use_motion_blur()) {
Attribute *attr = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (attr) {
size_t hair_size = hair->curve_keys.size();
size_t steps = hair->motion_steps - 1;
size_t hair_size = hair->get_curve_keys().size();
size_t steps = hair->get_motion_steps() - 1;
float3 *key_steps = attr->data_float3();
for (size_t i = 0; i < steps; i++)
curve.bounds_grow(k, key_steps + i * hair_size, &hair->curve_radius[0], bbox);
curve.bounds_grow(k, key_steps + i * hair_size, &hair->get_curve_radius()[0], bbox);
}
}
}
else {
/* Triangles. */
const Mesh *mesh = static_cast<const Mesh *>(ob->geometry);
const Mesh *mesh = static_cast<const Mesh *>(ob->get_geometry());
int prim_offset = (params.top_level) ? mesh->prim_offset : 0;
Mesh::Triangle triangle = mesh->get_triangle(pidx - prim_offset);
const float3 *vpos = &mesh->verts[0];
@ -264,7 +264,7 @@ void BVH::pack_triangle(int idx, float4 tri_verts[3])
{
int tob = pack.prim_object[idx];
assert(tob >= 0 && tob < objects.size());
const Mesh *mesh = static_cast<const Mesh *>(objects[tob]->geometry);
const Mesh *mesh = static_cast<const Mesh *>(objects[tob]->get_geometry());
int tidx = pack.prim_index[idx];
Mesh::Triangle t = mesh->get_triangle(tidx);
@ -329,7 +329,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
*/
for (size_t i = 0; i < pack.prim_index.size(); i++) {
if (pack.prim_index[i] != -1) {
pack.prim_index[i] += objects[pack.prim_object[i]]->geometry->prim_offset;
pack.prim_index[i] += objects[pack.prim_object[i]]->get_geometry()->prim_offset;
}
}
@ -390,7 +390,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
/* merge */
foreach (Object *ob, objects) {
Geometry *geom = ob->geometry;
Geometry *geom = ob->get_geometry();
/* We assume that if mesh doesn't need own BVH it was already included
* into a top-level BVH and no packing here is needed.

@ -169,12 +169,12 @@ void BVHBuild::add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair
const size_t num_curves = hair->num_curves();
for (uint j = 0; j < num_curves; j++) {
const Hair::Curve curve = hair->get_curve(j);
const float *curve_radius = &hair->curve_radius[0];
const float *curve_radius = &hair->get_curve_radius()[0];
for (int k = 0; k < curve.num_keys - 1; k++) {
if (curve_attr_mP == NULL) {
/* Really simple logic for static hair. */
BoundBox bounds = BoundBox::empty;
curve.bounds_grow(k, &hair->curve_keys[0], curve_radius, bounds);
curve.bounds_grow(k, &hair->get_curve_keys()[0], curve_radius, bounds);
if (bounds.valid()) {
int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
references.push_back(BVHReference(bounds, j, i, packed_type));
@ -189,9 +189,9 @@ void BVHBuild::add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair
*/
/* TODO(sergey): Support motion steps for spatially split BVH. */
BoundBox bounds = BoundBox::empty;
curve.bounds_grow(k, &hair->curve_keys[0], curve_radius, bounds);
const size_t num_keys = hair->curve_keys.size();
const size_t num_steps = hair->motion_steps;
curve.bounds_grow(k, &hair->get_curve_keys()[0], curve_radius, bounds);
const size_t num_keys = hair->get_curve_keys().size();
const size_t num_steps = hair->get_motion_steps();
const float3 *key_steps = curve_attr_mP->data_float3();
for (size_t step = 0; step < num_steps - 1; step++) {
curve.bounds_grow(k, key_steps + step * num_keys, curve_radius, bounds);
@ -210,10 +210,10 @@ void BVHBuild::add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair
*/
const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1;
const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
const size_t num_steps = hair->motion_steps;
const float3 *curve_keys = &hair->curve_keys[0];
const size_t num_steps = hair->get_motion_steps();
const float3 *curve_keys = &hair->get_curve_keys()[0];
const float3 *key_steps = curve_attr_mP->data_float3();
const size_t num_keys = hair->curve_keys.size();
const size_t num_keys = hair->get_curve_keys().size();
/* Calculate bounding box of the previous time step.
* Will be reused later to avoid duplicated work on
* calculating BVH time step boundbox.
@ -270,11 +270,11 @@ void BVHBuild::add_reference_curves(BoundBox &root, BoundBox &center, Hair *hair
void BVHBuild::add_reference_geometry(BoundBox &root, BoundBox &center, Geometry *geom, int i)
{
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
add_reference_triangles(root, center, mesh, i);
}
else if (geom->type == Geometry::HAIR) {
else if (geom->geometry_type == Geometry::HAIR) {
Hair *hair = static_cast<Hair *>(geom);
add_reference_curves(root, center, hair, i);
}
@ -299,11 +299,11 @@ static size_t count_curve_segments(Hair *hair)
static size_t count_primitives(Geometry *geom)
{
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
return mesh->num_triangles();
}
else if (geom->type == Geometry::HAIR) {
else if (geom->geometry_type == Geometry::HAIR) {
Hair *hair = static_cast<Hair *>(geom);
return count_curve_segments(hair);
}
@ -321,14 +321,14 @@ void BVHBuild::add_references(BVHRange &root)
if (!ob->is_traceable()) {
continue;
}
if (!ob->geometry->is_instanced()) {
num_alloc_references += count_primitives(ob->geometry);
if (!ob->get_geometry()->is_instanced()) {
num_alloc_references += count_primitives(ob->get_geometry());
}
else
num_alloc_references++;
}
else {
num_alloc_references += count_primitives(ob->geometry);
num_alloc_references += count_primitives(ob->get_geometry());
}
}
@ -344,13 +344,13 @@ void BVHBuild::add_references(BVHRange &root)
++i;
continue;
}
if (!ob->geometry->is_instanced())
add_reference_geometry(bounds, center, ob->geometry, i);
if (!ob->get_geometry()->is_instanced())
add_reference_geometry(bounds, center, ob->get_geometry(), i);
else
add_reference_object(bounds, center, ob, i);
}
else
add_reference_geometry(bounds, center, ob->geometry, i);
add_reference_geometry(bounds, center, ob->get_geometry(), i);
i++;

@ -300,11 +300,11 @@ static bool rtc_progress_func(void *user_ptr, const double n)
static size_t count_primitives(Geometry *geom)
{
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
return mesh->num_triangles();
}
else if (geom->type == Geometry::HAIR) {
else if (geom->geometry_type == Geometry::HAIR) {
Hair *hair = static_cast<Hair *>(geom);
return hair->num_segments();
}
@ -402,15 +402,15 @@ void BVHEmbree::build(Progress &progress, Stats *stats_)
if (!ob->is_traceable()) {
continue;
}
if (!ob->geometry->is_instanced()) {
prim_count += count_primitives(ob->geometry);
if (!ob->get_geometry()->is_instanced()) {
prim_count += count_primitives(ob->get_geometry());
}
else {
++prim_count;
}
}
else {
prim_count += count_primitives(ob->geometry);
prim_count += count_primitives(ob->get_geometry());
}
}
@ -429,7 +429,7 @@ void BVHEmbree::build(Progress &progress, Stats *stats_)
++i;
continue;
}
if (!ob->geometry->is_instanced()) {
if (!ob->get_geometry()->is_instanced()) {
add_object(ob, i);
}
else {
@ -480,15 +480,15 @@ BVHNode *BVHEmbree::widen_children_nodes(const BVHNode * /*root*/)
void BVHEmbree::add_object(Object *ob, int i)
{
Geometry *geom = ob->geometry;
Geometry *geom = ob->get_geometry();
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->num_triangles() > 0) {
add_triangles(ob, mesh, i);
}
}
else if (geom->type == Geometry::HAIR) {
else if (geom->geometry_type == Geometry::HAIR) {
Hair *hair = static_cast<Hair *>(geom);
if (hair->num_curves() > 0) {
add_curves(ob, hair, i);
@ -498,17 +498,17 @@ void BVHEmbree::add_object(Object *ob, int i)
void BVHEmbree::add_instance(Object *ob, int i)
{
if (!ob || !ob->geometry) {
if (!ob || !ob->get_geometry()) {
assert(0);
return;
}
BVHEmbree *instance_bvh = (BVHEmbree *)(ob->geometry->bvh);
BVHEmbree *instance_bvh = (BVHEmbree *)(ob->get_geometry()->bvh);
if (instance_bvh->top_level != this) {
instance_bvh->top_level = this;
}
const size_t num_object_motion_steps = ob->use_motion() ? ob->motion.size() : 1;
const size_t num_object_motion_steps = ob->use_motion() ? ob->get_motion().size() : 1;
const size_t num_motion_steps = min(num_object_motion_steps, RTC_MAX_TIME_STEP_COUNT);
assert(num_object_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
@ -517,8 +517,8 @@ void BVHEmbree::add_instance(Object *ob, int i)
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
if (ob->use_motion()) {
array<DecomposedTransform> decomp(ob->motion.size());
transform_motion_decompose(decomp.data(), ob->motion.data(), ob->motion.size());
array<DecomposedTransform> decomp(ob->get_motion().size());
transform_motion_decompose(decomp.data(), ob->get_motion().data(), ob->get_motion().size());
for (size_t step = 0; step < num_motion_steps; ++step) {
RTCQuaternionDecomposition rtc_decomp;
rtcInitQuaternionDecomposition(&rtc_decomp);
@ -534,7 +534,8 @@ void BVHEmbree::add_instance(Object *ob, int i)
}
}
else {
rtcSetGeometryTransform(geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float *)&ob->tfm);
rtcSetGeometryTransform(
geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (const float *)&ob->get_tfm());
}
pack.prim_index.push_back_slow(-1);
@ -558,7 +559,7 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
if (mesh->has_motion_blur()) {
attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (attr_mP) {
num_geometry_motion_steps = mesh->motion_steps;
num_geometry_motion_steps = mesh->get_motion_steps();
}
}
@ -620,7 +621,7 @@ void BVHEmbree::set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, con
if (mesh->has_motion_blur()) {
attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (attr_mP) {
num_motion_steps = mesh->motion_steps;
num_motion_steps = mesh->get_motion_steps();
t_mid = (num_motion_steps - 1) / 2;
if (num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
assert(0);
@ -672,7 +673,7 @@ void BVHEmbree::set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, c
if (hair->has_motion_blur()) {
attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (attr_mP) {
num_motion_steps = hair->motion_steps;
num_motion_steps = hair->get_motion_steps();
}
}
@ -689,11 +690,11 @@ void BVHEmbree::set_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair, c
/* Copy the CV data to Embree */
const int t_mid = (num_motion_steps - 1) / 2;
const float *curve_radius = &hair->curve_radius[0];
const float *curve_radius = &hair->get_curve_radius()[0];
for (int t = 0; t < num_motion_steps; ++t) {
const float3 *verts;
if (t == t_mid || attr_mP == NULL) {
verts = &hair->curve_keys[0];
verts = &hair->get_curve_keys()[0];
}
else {
int t_ = (t > t_mid) ? (t - 1) : t;
@ -741,7 +742,7 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
if (hair->has_motion_blur()) {
attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (attr_mP) {
num_geometry_motion_steps = hair->motion_steps;
num_geometry_motion_steps = hair->get_motion_steps();
}
}
@ -826,7 +827,7 @@ void BVHEmbree::pack_nodes(const BVHNode *)
for (size_t i = 0; i < pack.prim_index.size(); ++i) {
if (pack.prim_index[i] != -1) {
pack.prim_index[i] += objects[pack.prim_object[i]]->geometry->prim_offset;
pack.prim_index[i] += objects[pack.prim_object[i]]->get_geometry()->prim_offset;
}
}
@ -843,7 +844,7 @@ void BVHEmbree::pack_nodes(const BVHNode *)
map<Geometry *, int> geometry_map;
foreach (Object *ob, objects) {
Geometry *geom = ob->geometry;
Geometry *geom = ob->get_geometry();
BVH *bvh = geom->bvh;
if (geom->need_build_bvh(BVH_LAYOUT_EMBREE)) {
@ -873,7 +874,7 @@ void BVHEmbree::pack_nodes(const BVHNode *)
/* merge */
foreach (Object *ob, objects) {
Geometry *geom = ob->geometry;
Geometry *geom = ob->get_geometry();
/* We assume that if mesh doesn't need own BVH it was already included
* into a top-level BVH and no packing here is needed.
@ -948,10 +949,10 @@ void BVHEmbree::refit_nodes()
/* Update all vertex buffers, then tell Embree to rebuild/-fit the BVHs. */
unsigned geom_id = 0;
foreach (Object *ob, objects) {
if (!params.top_level || (ob->is_traceable() && !ob->geometry->is_instanced())) {
Geometry *geom = ob->geometry;
if (!params.top_level || (ob->is_traceable() && !ob->get_geometry()->is_instanced())) {
Geometry *geom = ob->get_geometry();
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->num_triangles() > 0) {
RTCGeometry geom = rtcGetGeometry(scene, geom_id);
@ -959,7 +960,7 @@ void BVHEmbree::refit_nodes()
rtcCommitGeometry(geom);
}
}
else if (geom->type == Geometry::HAIR) {
else if (geom->geometry_type == Geometry::HAIR) {
Hair *hair = static_cast<Hair *>(geom);
if (hair->num_curves() > 0) {
RTCGeometry geom = rtcGetGeometry(scene, geom_id + 1);

@ -69,7 +69,7 @@ void BVHOptiX::pack_blas()
assert(geometry.size() == 1 && objects.size() == 1); // These are built per-mesh
Geometry *const geom = geometry[0];
if (geom->type == Geometry::HAIR) {
if (geom->geometry_type == Geometry::HAIR) {
Hair *const hair = static_cast<Hair *const>(geom);
if (hair->num_curves() > 0) {
const size_t num_curves = hair->num_curves();
@ -80,7 +80,7 @@ void BVHOptiX::pack_blas()
// 'pack.prim_time' is only used in geom_curve_intersect.h
// It is not needed because of OPTIX_MOTION_FLAG_[START|END]_VANISH
uint type = (hair->use_motion_blur &&
uint type = (hair->get_use_motion_blur() &&
hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) ?
((hair->curve_shape == CURVE_RIBBON) ? PRIMITIVE_MOTION_CURVE_RIBBON :
PRIMITIVE_MOTION_CURVE_THICK) :
@ -98,7 +98,7 @@ void BVHOptiX::pack_blas()
}
}
}
else if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
else if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *const mesh = static_cast<Mesh *const>(geom);
if (mesh->num_triangles() > 0) {
const size_t num_triangles = mesh->num_triangles();
@ -107,7 +107,7 @@ void BVHOptiX::pack_blas()
pack.prim_object.reserve(pack.prim_object.size() + num_triangles);
uint type = PRIMITIVE_TRIANGLE;
if (mesh->use_motion_blur && mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION))
if (mesh->get_use_motion_blur() && mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION))
type = PRIMITIVE_MOTION_TRIANGLE;
for (size_t k = 0; k < num_triangles; ++k) {
@ -119,14 +119,14 @@ void BVHOptiX::pack_blas()
}
// Initialize visibility to zero and later update it during top-level build
uint prev_visibility = objects[0]->visibility;
objects[0]->visibility = 0;
uint prev_visibility = objects[0]->get_visibility();
objects[0]->set_visibility(0);
// Update 'pack.prim_tri_index', 'pack.prim_tri_verts' and 'pack.prim_visibility'
pack_primitives();
// Reset visibility after packing
objects[0]->visibility = prev_visibility;
objects[0]->set_visibility(prev_visibility);
}
void BVHOptiX::pack_tlas()
@ -170,7 +170,7 @@ void BVHOptiX::pack_tlas()
int object_index = 0; // Unused for instanced geometry
int object_visibility = 0;
foreach (Object *ob, objects) {
if (ob->geometry == geom) {
if (ob->get_geometry() == geom) {
object_visibility |= ob->visibility_for_tracing();
if (!geom->is_instanced()) {
object_index = ob->get_device_index();

@ -392,8 +392,8 @@ void BVHSpatialSplit::split_curve_primitive(const Hair *hair,
Hair::Curve curve = hair->get_curve(prim_index);
const int k0 = curve.first_key + segment_index;
const int k1 = k0 + 1;
float3 v0 = hair->curve_keys[k0];
float3 v1 = hair->curve_keys[k1];
float3 v0 = hair->get_curve_keys()[k0];
float3 v1 = hair->get_curve_keys()[k1];
if (tfm != NULL) {
v0 = transform_point(tfm, v0);
@ -456,21 +456,22 @@ void BVHSpatialSplit::split_curve_reference(const BVHReference &ref,
void BVHSpatialSplit::split_object_reference(
const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds)
{
Geometry *geom = object->geometry;
Geometry *geom = object->get_geometry();
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
for (int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) {
split_triangle_primitive(mesh, &object->tfm, tri_idx, dim, pos, left_bounds, right_bounds);
split_triangle_primitive(
mesh, &object->get_tfm(), tri_idx, dim, pos, left_bounds, right_bounds);
}
}
else if (geom->type == Geometry::HAIR) {
else if (geom->geometry_type == Geometry::HAIR) {
Hair *hair = static_cast<Hair *>(geom);
for (int curve_idx = 0; curve_idx < hair->num_curves(); ++curve_idx) {
Hair::Curve curve = hair->get_curve(curve_idx);
for (int segment_idx = 0; segment_idx < curve.num_keys - 1; ++segment_idx) {
split_curve_primitive(
hair, &object->tfm, curve_idx, segment_idx, dim, pos, left_bounds, right_bounds);
hair, &object->get_tfm(), curve_idx, segment_idx, dim, pos, left_bounds, right_bounds);
}
}
}
@ -491,11 +492,11 @@ void BVHSpatialSplit::split_reference(const BVHBuild &builder,
const Object *ob = builder.objects[ref.prim_object()];
if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
Mesh *mesh = static_cast<Mesh *>(ob->geometry);
Mesh *mesh = static_cast<Mesh *>(ob->get_geometry());
split_triangle_reference(ref, mesh, dim, pos, left_bounds, right_bounds);
}
else if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
Hair *hair = static_cast<Hair *>(ob->geometry);
Hair *hair = static_cast<Hair *>(ob->get_geometry());
split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds);
}
else {

@ -72,10 +72,10 @@ bool BVHUnaligned::compute_aligned_space(const BVHReference &ref, Transform *ali
if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
const int curve_index = ref.prim_index();
const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
const Hair *hair = static_cast<const Hair *>(object->geometry);
const Hair *hair = static_cast<const Hair *>(object->get_geometry());
const Hair::Curve &curve = hair->get_curve(curve_index);
const int key = curve.first_key + segment;
const float3 v1 = hair->curve_keys[key], v2 = hair->curve_keys[key + 1];
const float3 v1 = hair->get_curve_keys()[key], v2 = hair->get_curve_keys()[key + 1];
float length;
const float3 axis = normalize_len(v2 - v1, &length);
if (length > 1e-6f) {
@ -98,10 +98,10 @@ BoundBox BVHUnaligned::compute_aligned_prim_boundbox(const BVHReference &prim,
if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
const int curve_index = prim.prim_index();
const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
const Hair *hair = static_cast<const Hair *>(object->geometry);
const Hair *hair = static_cast<const Hair *>(object->get_geometry());
const Hair::Curve &curve = hair->get_curve(curve_index);
curve.bounds_grow(
segment, &hair->curve_keys[0], &hair->curve_radius[0], aligned_space, bounds);
segment, &hair->get_curve_keys()[0], &hair->get_curve_radius()[0], aligned_space, bounds);
}
else {
bounds = prim.bounds().transformed(&aligned_space);

@ -1211,7 +1211,7 @@ class OptiXDevice : public CUDADevice {
// Note: Always keep this logic in sync with bvh_optix.cpp!
for (Object *ob : bvh->objects) {
// Skip geometry for which acceleration structure already exists
Geometry *geom = ob->geometry;
Geometry *geom = ob->get_geometry();
if (geometry.find(geom) != geometry.end())
continue;
@ -1230,9 +1230,9 @@ class OptiXDevice : public CUDADevice {
operation = OPTIX_BUILD_OPERATION_BUILD;
}
if (geom->type == Geometry::HAIR) {
if (geom->geometry_type == Geometry::HAIR) {
// Build BLAS for curve primitives
Hair *const hair = static_cast<Hair *const>(ob->geometry);
Hair *const hair = static_cast<Hair *const>(ob->get_geometry());
if (hair->num_curves() == 0) {
continue;
}
@ -1241,8 +1241,8 @@ class OptiXDevice : public CUDADevice {
size_t num_motion_steps = 1;
Attribute *motion_keys = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (motion_blur && hair->use_motion_blur && motion_keys) {
num_motion_steps = hair->motion_steps;
if (motion_blur && hair->get_use_motion_blur() && motion_keys) {
num_motion_steps = hair->get_motion_steps();
}
device_vector<OptixAabb> aabb_data(this, "temp_aabb_data", MEM_READ_ONLY);
@ -1262,16 +1262,19 @@ class OptiXDevice : public CUDADevice {
// Get AABBs for each motion step
for (size_t step = 0; step < num_motion_steps; ++step) {
// The center step for motion vertices is not stored in the attribute
const float3 *keys = hair->curve_keys.data();
const float3 *keys = hair->get_curve_keys().data();
size_t center_step = (num_motion_steps - 1) / 2;
if (step != center_step) {
size_t attr_offset = (step > center_step) ? step - 1 : step;
// Technically this is a float4 array, but sizeof(float3) is the same as sizeof(float4)
keys = motion_keys->data_float3() + attr_offset * hair->curve_keys.size();
keys = motion_keys->data_float3() + attr_offset * hair->get_curve_keys().size();
}
for (size_t j = 0, i = 0; j < hair->num_curves(); ++j) {
const Hair::Curve curve = hair->get_curve(j);
# if OPTIX_ABI_VERSION >= 36
const array<float> &curve_radius = hair->get_curve_radius();
# endif
for (int segment = 0; segment < curve.num_segments(); ++segment, ++i) {
# if OPTIX_ABI_VERSION >= 36
@ -1284,10 +1287,8 @@ class OptiXDevice : public CUDADevice {
const float4 px = make_float4(keys[ka].x, keys[k0].x, keys[k1].x, keys[kb].x);
const float4 py = make_float4(keys[ka].y, keys[k0].y, keys[k1].y, keys[kb].y);
const float4 pz = make_float4(keys[ka].z, keys[k0].z, keys[k1].z, keys[kb].z);
const float4 pw = make_float4(hair->curve_radius[ka],
hair->curve_radius[k0],
hair->curve_radius[k1],
hair->curve_radius[kb]);
const float4 pw = make_float4(
curve_radius[ka], curve_radius[k0], curve_radius[k1], curve_radius[kb]);
// Convert Catmull-Rom data to Bezier spline
static const float4 cr2bsp0 = make_float4(+7, -4, +5, -2) / 6.f;
@ -1310,7 +1311,7 @@ class OptiXDevice : public CUDADevice {
# endif
{
BoundBox bounds = BoundBox::empty;
curve.bounds_grow(segment, keys, hair->curve_radius.data(), bounds);
curve.bounds_grow(segment, keys, hair->get_curve_radius().data(), bounds);
const size_t index = step * num_segments + i;
aabb_data[index].minX = bounds.min.x;
@ -1394,7 +1395,7 @@ class OptiXDevice : public CUDADevice {
// Allocate memory for new BLAS and build it
if (build_optix_bvh(build_input, num_motion_steps, handle, out_data, operation)) {
geometry.insert({ob->geometry, handle});
geometry.insert({ob->get_geometry(), handle});
static_cast<BVHOptiX *>(geom->bvh)->optix_data_handle = out_data;
static_cast<BVHOptiX *>(geom->bvh)->optix_handle = handle;
static_cast<BVHOptiX *>(geom->bvh)->do_refit = false;
@ -1403,29 +1404,31 @@ class OptiXDevice : public CUDADevice {
return false;
}
}
else if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
else if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
// Build BLAS for triangle primitives
Mesh *const mesh = static_cast<Mesh *const>(ob->geometry);
Mesh *const mesh = static_cast<Mesh *const>(ob->get_geometry());
if (mesh->num_triangles() == 0) {
continue;
}
const size_t num_verts = mesh->verts.size();
const size_t num_verts = mesh->get_verts().size();
size_t num_motion_steps = 1;
Attribute *motion_keys = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if (motion_blur && mesh->use_motion_blur && motion_keys) {
num_motion_steps = mesh->motion_steps;
if (motion_blur && mesh->get_use_motion_blur() && motion_keys) {
num_motion_steps = mesh->get_motion_steps();
}
device_vector<int> index_data(this, "temp_index_data", MEM_READ_ONLY);
index_data.alloc(mesh->triangles.size());
memcpy(index_data.data(), mesh->triangles.data(), mesh->triangles.size() * sizeof(int));
index_data.alloc(mesh->get_triangles().size());
memcpy(index_data.data(),
mesh->get_triangles().data(),
mesh->get_triangles().size() * sizeof(int));
device_vector<float3> vertex_data(this, "temp_vertex_data", MEM_READ_ONLY);
vertex_data.alloc(num_verts * num_motion_steps);
for (size_t step = 0; step < num_motion_steps; ++step) {
const float3 *verts = mesh->verts.data();
const float3 *verts = mesh->get_verts().data();
size_t center_step = (num_motion_steps - 1) / 2;
// The center step for motion vertices is not stored in the attribute
@ -1468,7 +1471,7 @@ class OptiXDevice : public CUDADevice {
// Allocate memory for new BLAS and build it
if (build_optix_bvh(build_input, num_motion_steps, handle, out_data, operation)) {
geometry.insert({ob->geometry, handle});
geometry.insert({ob->get_geometry(), handle});
static_cast<BVHOptiX *>(geom->bvh)->optix_data_handle = out_data;
static_cast<BVHOptiX *>(geom->bvh)->optix_handle = handle;
static_cast<BVHOptiX *>(geom->bvh)->do_refit = false;
@ -1493,7 +1496,7 @@ class OptiXDevice : public CUDADevice {
continue;
// Create separate instance for triangle/curve meshes of an object
const auto handle_it = geometry.find(ob->geometry);
const auto handle_it = geometry.find(ob->get_geometry());
if (handle_it == geometry.end()) {
continue;
}
@ -1523,18 +1526,19 @@ class OptiXDevice : public CUDADevice {
// Have to have at least one bit in the mask, or else instance would always be culled
instance.visibilityMask = 1;
if (ob->geometry->has_volume) {
if (ob->get_geometry()->has_volume) {
// Volumes have a special bit set in the visibility mask so a trace can mask only volumes
instance.visibilityMask |= 2;
}
if (ob->geometry->type == Geometry::HAIR) {
if (ob->get_geometry()->geometry_type == Geometry::HAIR) {
// Same applies to curves (so they can be skipped in local trace calls)
instance.visibilityMask |= 4;
# if OPTIX_ABI_VERSION >= 36
if (motion_blur && ob->geometry->has_motion_blur() && DebugFlags().optix.curves_api &&
static_cast<const Hair *>(ob->geometry)->curve_shape == CURVE_THICK) {
if (motion_blur && ob->get_geometry()->has_motion_blur() &&
DebugFlags().optix.curves_api &&
static_cast<const Hair *>(ob->get_geometry())->curve_shape == CURVE_THICK) {
// Select between motion blur and non-motion blur built-in intersection module
instance.sbtOffset = PG_HITD_MOTION - PG_HITD;
}
@ -1543,7 +1547,7 @@ class OptiXDevice : public CUDADevice {
// Insert motion traversable if object has motion
if (motion_blur && ob->use_motion()) {
size_t motion_keys = max(ob->motion.size(), 2) - 2;
size_t motion_keys = max(ob->get_motion().size(), 2) - 2;
size_t motion_transform_size = sizeof(OptixSRTMotionTransform) +
motion_keys * sizeof(OptixSRTData);
@ -1557,16 +1561,17 @@ class OptiXDevice : public CUDADevice {
OptixSRTMotionTransform &motion_transform = *reinterpret_cast<OptixSRTMotionTransform *>(
new uint8_t[motion_transform_size]);
motion_transform.child = handle;
motion_transform.motionOptions.numKeys = ob->motion.size();
motion_transform.motionOptions.numKeys = ob->get_motion().size();
motion_transform.motionOptions.flags = OPTIX_MOTION_FLAG_NONE;
motion_transform.motionOptions.timeBegin = 0.0f;
motion_transform.motionOptions.timeEnd = 1.0f;
OptixSRTData *const srt_data = motion_transform.srtData;
array<DecomposedTransform> decomp(ob->motion.size());
transform_motion_decompose(decomp.data(), ob->motion.data(), ob->motion.size());
array<DecomposedTransform> decomp(ob->get_motion().size());
transform_motion_decompose(
decomp.data(), ob->get_motion().data(), ob->get_motion().size());
for (size_t i = 0; i < ob->motion.size(); ++i) {
for (size_t i = 0; i < ob->get_motion().size(); ++i) {
// Scale
srt_data[i].sx = decomp[i].y.w; // scale.x.x
srt_data[i].sy = decomp[i].z.w; // scale.y.y
@ -1613,9 +1618,9 @@ class OptiXDevice : public CUDADevice {
else {
instance.traversableHandle = handle;
if (ob->geometry->is_instanced()) {
if (ob->get_geometry()->is_instanced()) {
// Set transform matrix
memcpy(instance.transform, &ob->tfm, sizeof(instance.transform));
memcpy(instance.transform, &ob->get_tfm(), sizeof(instance.transform));
}
else {
// Disable instance transform if geometry already has it applied to vertex data

@ -52,11 +52,6 @@ Node::~Node()
{
}
template<typename T> static T &get_socket_value(const Node *node, const SocketType &socket)
{
return (T &)*(((char *)node) + socket.struct_offset);
}
#ifndef NDEBUG
static bool is_socket_float3(const SocketType &socket)
{
@ -387,6 +382,87 @@ void Node::copy_value(const SocketType &socket, const Node &other, const SocketT
}
}
void Node::set_value(const SocketType &socket, const Node &other, const SocketType &other_socket)
{
assert(socket.type == other_socket.type);
(void)other_socket;
if (socket.is_array()) {
switch (socket.type) {
case SocketType::BOOLEAN_ARRAY:
set(socket, get_socket_value<array<bool>>(&other, socket));
break;
case SocketType::FLOAT_ARRAY:
set(socket, get_socket_value<array<float>>(&other, socket));
break;
case SocketType::INT_ARRAY:
set(socket, get_socket_value<array<int>>(&other, socket));
break;
case SocketType::COLOR_ARRAY:
case SocketType::VECTOR_ARRAY:
case SocketType::POINT_ARRAY:
case SocketType::NORMAL_ARRAY:
set(socket, get_socket_value<array<float3>>(&other, socket));
break;
case SocketType::POINT2_ARRAY:
set(socket, get_socket_value<array<float2>>(&other, socket));
break;
case SocketType::STRING_ARRAY:
set(socket, get_socket_value<array<ustring>>(&other, socket));
break;
case SocketType::TRANSFORM_ARRAY:
set(socket, get_socket_value<array<Transform>>(&other, socket));
break;
case SocketType::NODE_ARRAY:
set(socket, get_socket_value<array<Node *>>(&other, socket));
break;
default:
assert(0);
break;
}
}
else {
switch (socket.type) {
case SocketType::BOOLEAN:
set(socket, get_socket_value<bool>(&other, socket));
break;
case SocketType::FLOAT:
set(socket, get_socket_value<float>(&other, socket));
break;
case SocketType::INT:
set(socket, get_socket_value<int>(&other, socket));
break;
case SocketType::UINT:
set(socket, get_socket_value<uint>(&other, socket));
break;
case SocketType::COLOR:
case SocketType::VECTOR:
case SocketType::POINT:
case SocketType::NORMAL:
set(socket, get_socket_value<float3>(&other, socket));
break;
case SocketType::POINT2:
set(socket, get_socket_value<float2>(&other, socket));
break;
case SocketType::STRING:
set(socket, get_socket_value<ustring>(&other, socket));
break;
case SocketType::ENUM:
set(socket, get_socket_value<int>(&other, socket));
break;
case SocketType::TRANSFORM:
set(socket, get_socket_value<Transform>(&other, socket));
break;
case SocketType::NODE:
set(socket, get_socket_value<Node *>(&other, socket));
break;
default:
assert(0);
break;
}
}
}
template<typename T>
static bool is_array_equal(const Node *node, const Node *other, const SocketType &socket)
{

@ -29,6 +29,66 @@ struct Node;
struct NodeType;
struct Transform;
/* Note: in the following macros we use "type const &" instead of "const type &"
* to avoid issues when pasting a pointer type. */
#define NODE_SOCKET_API_BASE_METHODS(type_, name, string_name) \
const SocketType *get_##name##_socket() const \
{ \
static const SocketType *socket = type->find_input(ustring(string_name)); \
return socket; \
} \
bool name##_is_modified() const \
{ \
const SocketType *socket = get_##name##_socket(); \
return socket_is_modified(*socket); \
} \
void tag_##name##_modified() \
{ \
const SocketType *socket = get_##name##_socket(); \
socket_modified |= socket->modified_flag_bit; \
} \
type_ const &get_##name() const \
{ \
const SocketType *socket = get_##name##_socket(); \
return get_socket_value<type_>(this, *socket); \
}
#define NODE_SOCKET_API_BASE(type_, name, string_name) \
protected: \
type_ name; \
\
public: \
NODE_SOCKET_API_BASE_METHODS(type_, name, string_name)
#define NODE_SOCKET_API(type_, name) \
NODE_SOCKET_API_BASE(type_, name, #name) \
void set_##name(type_ value) \
{ \
const SocketType *socket = get_##name##_socket(); \
this->set(*socket, value); \
}
#define NODE_SOCKET_API_ARRAY(type_, name) \
NODE_SOCKET_API_BASE(type_, name, #name) \
void set_##name(type_ &value) \
{ \
const SocketType *socket = get_##name##_socket(); \
this->set(*socket, value); \
} \
type_ &get_##name() \
{ \
const SocketType *socket = get_##name##_socket(); \
return get_socket_value<type_>(this, *socket); \
}
#define NODE_SOCKET_API_STRUCT_MEMBER(type_, name, member) \
NODE_SOCKET_API_BASE_METHODS(type_, name##_##member, #name "." #member) \
void set_##name##_##member(type_ value) \
{ \
const SocketType *socket = get_##name##_##member##_socket(); \
this->set(*socket, value); \
}
/* Node */
struct NodeOwner {
@ -88,6 +148,7 @@ struct Node {
void set_default_value(const SocketType &input);
bool equals_value(const Node &other, const SocketType &input) const;
void copy_value(const SocketType &input, const Node &other, const SocketType &other_input);
void set_value(const SocketType &input, const Node &other, const SocketType &other_input);
/* equals */
bool equals(const Node &other) const;
@ -119,6 +180,11 @@ struct Node {
protected:
const NodeOwner *owner;
template<typename T> static T &get_socket_value(const Node *node, const SocketType &socket)
{
return (T &)*(((char *)node) + socket.struct_offset);
}
SocketModifiedFlags socket_modified;
template<typename T> void set_if_different(const SocketType &input, T value);

@ -167,62 +167,62 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
size = 1;
break;
case ATTR_ELEMENT_VERTEX:
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
size = mesh->verts.size() + mesh->num_ngons;
size = mesh->get_verts().size() + mesh->get_num_ngons();
if (prim == ATTR_PRIM_SUBD) {
size -= mesh->num_subd_verts;
size -= mesh->get_num_subd_verts();
}
}
break;
case ATTR_ELEMENT_VERTEX_MOTION:
if (geom->type == Geometry::MESH) {
if (geom->geometry_type == Geometry::MESH) {
Mesh *mesh = static_cast<Mesh *>(geom);
size = (mesh->verts.size() + mesh->num_ngons) * (mesh->motion_steps - 1);
size = (mesh->get_verts().size() + mesh->get_num_ngons()) * (mesh->get_motion_steps() - 1);
if (prim == ATTR_PRIM_SUBD) {
size -= mesh->num_subd_verts * (mesh->motion_steps - 1);
size -= mesh->get_num_subd_verts() * (mesh->get_motion_steps() - 1);
}
}
break;
case ATTR_ELEMENT_FACE:
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (prim == ATTR_PRIM_GEOMETRY) {
size = mesh->num_triangles();
}
else {
size = mesh->subd_faces.size() + mesh->num_ngons;
size = mesh->get_num_subd_faces() + mesh->get_num_ngons();
}
}
break;
case ATTR_ELEMENT_CORNER:
case ATTR_ELEMENT_CORNER_BYTE:
if (geom->type == Geometry::MESH) {
if (geom->geometry_type == Geometry::MESH) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (prim == ATTR_PRIM_GEOMETRY) {
size = mesh->num_triangles() * 3;
}
else {
size = mesh->subd_face_corners.size() + mesh->num_ngons;
size = mesh->get_subd_face_corners().size() + mesh->get_num_ngons();
}
}
break;
case ATTR_ELEMENT_CURVE:
if (geom->type == Geometry::HAIR) {
if (geom->geometry_type == Geometry::HAIR) {
Hair *hair = static_cast<Hair *>(geom);
size = hair->num_curves();
}
break;
case ATTR_ELEMENT_CURVE_KEY:
if (geom->type == Geometry::HAIR) {
if (geom->geometry_type == Geometry::HAIR) {
Hair *hair = static_cast<Hair *>(geom);
size = hair->curve_keys.size();
size = hair->get_curve_keys().size();
}
break;
case ATTR_ELEMENT_CURVE_KEY_MOTION:
if (geom->type == Geometry::HAIR) {
if (geom->geometry_type == Geometry::HAIR) {
Hair *hair = static_cast<Hair *>(geom);
size = hair->curve_keys.size() * (hair->motion_steps - 1);
size = hair->get_curve_keys().size() * (hair->get_motion_steps() - 1);
}
break;
default:
@ -445,7 +445,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
if (name == ustring())
name = Attribute::standard_name(std);
if (geometry->type == Geometry::MESH) {
if (geometry->geometry_type == Geometry::MESH) {
switch (std) {
case ATTR_STD_VERTEX_NORMAL:
attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
@ -496,7 +496,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
break;
}
}
else if (geometry->type == Geometry::VOLUME) {
else if (geometry->geometry_type == Geometry::VOLUME) {
switch (std) {
case ATTR_STD_VERTEX_NORMAL:
attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
@ -521,7 +521,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
break;
}
}
else if (geometry->type == Geometry::HAIR) {
else if (geometry->geometry_type == Geometry::HAIR) {
switch (std) {
case ATTR_STD_UV:
attr = add(name, TypeFloat2, ATTR_ELEMENT_CURVE);

@ -54,7 +54,6 @@ NODE_DEFINE(Background)
Background::Background() : Node(node_type)
{
need_update = true;
shader = NULL;
}
@ -64,7 +63,7 @@ Background::~Background()
void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene)
{
if (!need_update)
if (!is_modified())
return;
scoped_callback_timer timer([scene](double time) {
@ -102,7 +101,7 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene
else
kbackground->volume_shader = SHADER_NONE;
kbackground->volume_step_size = volume_step_size * scene->integrator->volume_step_rate;
kbackground->volume_step_size = volume_step_size * scene->integrator->get_volume_step_rate();
/* No background node, make world shader invisible to all rays, to skip evaluation in kernel. */
if (bg_shader->graph->nodes.size() <= 1) {
@ -122,22 +121,17 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene
kbackground->surface_shader |= SHADER_EXCLUDE_CAMERA;
}
need_update = false;
clear_modified();
}
void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
{
}
bool Background::modified(const Background &background)
{
return !Node::equals(background);
}
void Background::tag_update(Scene *scene)
{
scene->integrator->tag_update(scene);
need_update = true;
tag_modified();
}
Shader *Background::get_shader(const Scene *scene)

@ -32,22 +32,20 @@ class Background : public Node {
public:
NODE_DECLARE
float ao_factor;
float ao_distance;
NODE_SOCKET_API(float, ao_factor)
NODE_SOCKET_API(float, ao_distance)
bool use_shader;
bool use_ao;
NODE_SOCKET_API(bool, use_shader)
NODE_SOCKET_API(bool, use_ao)
uint visibility;
Shader *shader;
NODE_SOCKET_API(uint, visibility)
NODE_SOCKET_API(Shader *, shader)
bool transparent;
bool transparent_glass;
float transparent_roughness_threshold;
NODE_SOCKET_API(bool, transparent)
NODE_SOCKET_API(bool, transparent_glass)
NODE_SOCKET_API(float, transparent_roughness_threshold)
float volume_step_size;
bool need_update;
NODE_SOCKET_API(float, volume_step_size)
Background();
~Background();
@ -55,7 +53,6 @@ class Background : public Node {
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene);
bool modified(const Background &background);
void tag_update(Scene *scene);
Shader *get_shader(const Scene *scene);

@ -33,10 +33,11 @@ static int aa_samples(Scene *scene, Object *object, ShaderEvalType type)
}
else if (type == SHADER_EVAL_NORMAL) {
/* Only antialias normal if mesh has bump mapping. */
if (object->geometry) {
foreach (Shader *shader, object->geometry->used_shaders) {
if (object->get_geometry()) {
foreach (Node *node, object->get_geometry()->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->has_bump) {
return scene->integrator->aa_samples;
return scene->integrator->get_aa_samples();
}
}
}
@ -44,7 +45,7 @@ static int aa_samples(Scene *scene, Object *object, ShaderEvalType type)
return 1;
}
else {
return scene->integrator->aa_samples;
return scene->integrator->get_aa_samples();
}
}
@ -112,7 +113,7 @@ void BakeManager::set(Scene *scene,
}
/* create device and update scene */
scene->film->tag_update(scene);
scene->film->tag_modified();
scene->integrator->tag_update(scene);
need_update = true;
@ -140,8 +141,8 @@ void BakeManager::device_update(Device * /*device*/,
int object_index = 0;
foreach (Object *object, scene->objects) {
const Geometry *geom = object->geometry;
if (object->name == object_name && geom->type == Geometry::MESH) {
const Geometry *geom = object->get_geometry();
if (object->name == object_name && geom->geometry_type == Geometry::MESH) {
kbake->object_index = object_index;
kbake->tri_offset = geom->prim_offset;
kintegrator->aa_samples = aa_samples(scene, object, type);

@ -98,7 +98,7 @@ NODE_DEFINE(Camera)
type_enum.insert("perspective", CAMERA_PERSPECTIVE);
type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC);
type_enum.insert("panorama", CAMERA_PANORAMA);
SOCKET_ENUM(type, "Type", type_enum, CAMERA_PERSPECTIVE);
SOCKET_ENUM(camera_type, "Type", type_enum, CAMERA_PERSPECTIVE);
static NodeEnum panorama_type_enum;
panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR);
@ -148,8 +148,18 @@ NODE_DEFINE(Camera)
SOCKET_FLOAT(border.bottom, "Border Bottom", 0);
SOCKET_FLOAT(border.top, "Border Top", 0);
SOCKET_FLOAT(viewport_camera_border.left, "Viewport Border Left", 0);
SOCKET_FLOAT(viewport_camera_border.right, "Viewport Border Right", 0);
SOCKET_FLOAT(viewport_camera_border.bottom, "Viewport Border Bottom", 0);
SOCKET_FLOAT(viewport_camera_border.top, "Viewport Border Top", 0);
SOCKET_FLOAT(offscreen_dicing_scale, "Offscreen Dicing Scale", 1.0f);
SOCKET_INT(full_width, "Full Width", 1024);
SOCKET_INT(full_height, "Full Height", 512);
SOCKET_BOOLEAN(use_perspective_motion, "Use Perspective Motion", false);
return type;
}
@ -182,7 +192,6 @@ Camera::Camera() : Node(node_type)
dx = make_float3(0.0f, 0.0f, 0.0f);
dy = make_float3(0.0f, 0.0f, 0.0f);
need_update = true;
need_device_update = true;
need_flags_update = true;
previous_need_motion = -1;
@ -196,7 +205,7 @@ Camera::~Camera()
void Camera::compute_auto_viewplane()
{
if (type == CAMERA_PANORAMA) {
if (camera_type == CAMERA_PANORAMA) {
viewplane.left = 0.0f;
viewplane.right = 1.0f;
viewplane.bottom = 0.0f;
@ -230,7 +239,7 @@ void Camera::update(Scene *scene)
need_device_update = true;
}
if (!need_update)
if (!is_modified())
return;
scoped_callback_timer timer([scene](double time) {
@ -257,9 +266,9 @@ void Camera::update(Scene *scene)
/* screen to camera */
ProjectionTransform cameratoscreen;
if (type == CAMERA_PERSPECTIVE)
if (camera_type == CAMERA_PERSPECTIVE)
cameratoscreen = projection_perspective(fov, nearclip, farclip);
else if (type == CAMERA_ORTHOGRAPHIC)
else if (camera_type == CAMERA_ORTHOGRAPHIC)
cameratoscreen = projection_orthographic(nearclip, farclip);
else
cameratoscreen = projection_identity();
@ -284,13 +293,13 @@ void Camera::update(Scene *scene)
worldtoraster = ndctoraster * worldtondc;
/* differentials */
if (type == CAMERA_ORTHOGRAPHIC) {
if (camera_type == CAMERA_ORTHOGRAPHIC) {
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) {
else if (camera_type == CAMERA_PERSPECTIVE) {
dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
transform_perspective(&rastertocamera, make_float3(0, 0, 0));
dy = transform_perspective(&rastertocamera, make_float3(0, 1, 0)) -
@ -310,7 +319,7 @@ void Camera::update(Scene *scene)
full_dx = transform_direction(&cameratoworld, full_dx);
full_dy = transform_direction(&cameratoworld, full_dy);
if (type == CAMERA_PERSPECTIVE) {
if (camera_type == CAMERA_PERSPECTIVE) {
float3 v = transform_perspective(&full_rastertocamera,
make_float3(full_width, full_height, 1.0f));
frustum_right_normal = normalize(make_float3(v.z, 0.0f, -v.x));
@ -348,7 +357,7 @@ void Camera::update(Scene *scene)
if (need_motion == Scene::MOTION_PASS) {
/* TODO(sergey): Support perspective (zoom, fov) motion. */
if (type == CAMERA_PANORAMA) {
if (camera_type == CAMERA_PANORAMA) {
if (have_motion) {
kcam->motion_pass_pre = transform_inverse(motion[0]);
kcam->motion_pass_post = transform_inverse(motion[motion.size() - 1]);
@ -377,7 +386,7 @@ void Camera::update(Scene *scene)
}
/* TODO(sergey): Support other types of camera. */
if (use_perspective_motion && type == CAMERA_PERSPECTIVE) {
if (use_perspective_motion && camera_type == CAMERA_PERSPECTIVE) {
/* TODO(sergey): Move to an utility function and de-duplicate with
* calculation above.
*/
@ -402,7 +411,7 @@ void Camera::update(Scene *scene)
kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime : -1.0f;
/* type */
kcam->type = type;
kcam->type = camera_type;
/* anamorphic lens bokeh */
kcam->inv_aperture_ratio = 1.0f / aperture_ratio;
@ -464,7 +473,7 @@ void Camera::update(Scene *scene)
kcam->rolling_shutter_duration = rolling_shutter_duration;
/* Set further update flags */
need_update = false;
clear_modified();
need_device_update = true;
need_flags_update = true;
previous_need_motion = need_motion;
@ -527,7 +536,7 @@ void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scen
[&](const blocked_range<size_t> &r) {
for (size_t i = r.begin(); i != r.end(); i++) {
Object *object = scene->objects[i];
if (object->geometry->has_volume &&
if (object->get_geometry()->has_volume &&
viewplane_boundbox.intersects(object->bounds)) {
/* TODO(sergey): Consider adding more grained check. */
VLOG(1) << "Detected camera inside volume.";
@ -553,25 +562,10 @@ void Camera::device_free(Device * /*device*/, DeviceScene *dscene, Scene *scene)
dscene->camera_motion.free();
}
bool Camera::modified(const Camera &cam)
{
return !Node::equals(cam);
}
bool Camera::motion_modified(const Camera &cam)
{
return !((motion == cam.motion) && (use_perspective_motion == cam.use_perspective_motion));
}
void Camera::tag_update()
{
need_update = true;
}
float3 Camera::transform_raster_to_world(float raster_x, float raster_y)
{
float3 D, P;
if (type == CAMERA_PERSPECTIVE) {
if (camera_type == CAMERA_PERSPECTIVE) {
D = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
float3 Pclip = normalize(D);
P = make_float3(0.0f, 0.0f, 0.0f);
@ -584,7 +578,7 @@ float3 Camera::transform_raster_to_world(float raster_x, float raster_y)
*/
P += nearclip * D / Pclip.z;
}
else if (type == CAMERA_ORTHOGRAPHIC) {
else if (camera_type == CAMERA_ORTHOGRAPHIC) {
D = make_float3(0.0f, 0.0f, 1.0f);
/* TODO(sergey): Aperture support? */
P = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
@ -603,7 +597,7 @@ BoundBox Camera::viewplane_bounds_get()
* checks we need in a more clear and smart fashion? */
BoundBox bounds = BoundBox::empty;
if (type == CAMERA_PANORAMA) {
if (camera_type == CAMERA_PANORAMA) {
if (use_spherical_stereo == false) {
bounds.grow(make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w));
}
@ -628,7 +622,7 @@ BoundBox Camera::viewplane_bounds_get()
bounds.grow(transform_raster_to_world(0.0f, (float)height));
bounds.grow(transform_raster_to_world((float)width, (float)height));
bounds.grow(transform_raster_to_world((float)width, 0.0f));
if (type == CAMERA_PERSPECTIVE) {
if (camera_type == CAMERA_PERSPECTIVE) {
/* Center point has the most distance in local Z axis,
* use it to construct bounding box/
*/
@ -642,7 +636,7 @@ float Camera::world_to_raster_size(float3 P)
{
float res = 1.0f;
if (type == CAMERA_ORTHOGRAPHIC) {
if (camera_type == CAMERA_ORTHOGRAPHIC) {
res = min(len(full_dx), len(full_dy));
if (offscreen_dicing_scale > 1.0f) {
@ -668,7 +662,7 @@ float Camera::world_to_raster_size(float3 P)
}
}
}
else if (type == CAMERA_PERSPECTIVE) {
else if (camera_type == CAMERA_PERSPECTIVE) {
/* Calculate as if point is directly ahead of the camera. */
float3 raster = make_float3(0.5f * full_width, 0.5f * full_height, 0.0f);
float3 Pcamera = transform_perspective(&full_rastertocamera, raster);
@ -743,7 +737,7 @@ float Camera::world_to_raster_size(float3 P)
}
}
}
else if (type == CAMERA_PANORAMA) {
else if (camera_type == CAMERA_PANORAMA) {
float3 D = transform_point(&worldtocamera, P);
float dist = len(D);
@ -794,6 +788,16 @@ bool Camera::use_motion() const
return motion.size() > 1;
}
void Camera::set_screen_size_and_resolution(int width_, int height_, int resolution_)
{
if (width_ != width || height_ != height || resolution_ != resolution) {
width = width_;
height = height_;
resolution = resolution_;
tag_modified();
}
}
float Camera::motion_time(int step) const
{
return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;

@ -73,78 +73,92 @@ class Camera : public Node {
};
/* motion blur */
float shuttertime;
MotionPosition motion_position;
array<float> shutter_curve;
NODE_SOCKET_API(float, shuttertime)
NODE_SOCKET_API(MotionPosition, motion_position)
NODE_SOCKET_API_ARRAY(array<float>, shutter_curve)
size_t shutter_table_offset;
/* ** Rolling shutter effect. ** */
/* Defines rolling shutter effect type. */
RollingShutterType rolling_shutter_type;
NODE_SOCKET_API(RollingShutterType, rolling_shutter_type)
/* Specifies exposure time of scanlines when using
* rolling shutter effect.
*/
float rolling_shutter_duration;
NODE_SOCKET_API(float, rolling_shutter_duration)
/* depth of field */
float focaldistance;
float aperturesize;
uint blades;
float bladesrotation;
NODE_SOCKET_API(float, focaldistance)
NODE_SOCKET_API(float, aperturesize)
NODE_SOCKET_API(uint, blades)
NODE_SOCKET_API(float, bladesrotation)
/* type */
CameraType type;
float fov;
NODE_SOCKET_API(CameraType, camera_type)
NODE_SOCKET_API(float, fov)
/* panorama */
PanoramaType panorama_type;
float fisheye_fov;
float fisheye_lens;
float latitude_min;
float latitude_max;
float longitude_min;
float longitude_max;
NODE_SOCKET_API(PanoramaType, panorama_type)
NODE_SOCKET_API(float, fisheye_fov)
NODE_SOCKET_API(float, fisheye_lens)
NODE_SOCKET_API(float, latitude_min)
NODE_SOCKET_API(float, latitude_max)
NODE_SOCKET_API(float, longitude_min)
NODE_SOCKET_API(float, longitude_max)
/* panorama stereo */
StereoEye stereo_eye;
bool use_spherical_stereo;
float interocular_distance;
float convergence_distance;
bool use_pole_merge;
float pole_merge_angle_from;
float pole_merge_angle_to;
NODE_SOCKET_API(StereoEye, stereo_eye)
NODE_SOCKET_API(bool, use_spherical_stereo)
NODE_SOCKET_API(float, interocular_distance)
NODE_SOCKET_API(float, convergence_distance)
NODE_SOCKET_API(bool, use_pole_merge)
NODE_SOCKET_API(float, pole_merge_angle_from)
NODE_SOCKET_API(float, pole_merge_angle_to)
/* anamorphic lens bokeh */
float aperture_ratio;
NODE_SOCKET_API(float, aperture_ratio)
/* sensor */
float sensorwidth;
float sensorheight;
NODE_SOCKET_API(float, sensorwidth)
NODE_SOCKET_API(float, sensorheight)
/* clipping */
float nearclip;
float farclip;
NODE_SOCKET_API(float, nearclip)
NODE_SOCKET_API(float, farclip)
/* screen */
int width, height;
int resolution;
BoundBox2D viewplane;
NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, left)
NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, right)
NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, bottom)
NODE_SOCKET_API_STRUCT_MEMBER(float, viewplane, top)
/* width and height change during preview, so we need these for calculating dice rates. */
int full_width, full_height;
NODE_SOCKET_API(int, full_width)
NODE_SOCKET_API(int, full_height)
/* controls how fast the dicing rate falls off for geometry out side of view */
float offscreen_dicing_scale;
NODE_SOCKET_API(float, offscreen_dicing_scale)
/* border */
BoundBox2D border;
NODE_SOCKET_API_STRUCT_MEMBER(float, border, left)
NODE_SOCKET_API_STRUCT_MEMBER(float, border, right)
NODE_SOCKET_API_STRUCT_MEMBER(float, border, bottom)
NODE_SOCKET_API_STRUCT_MEMBER(float, border, top)
BoundBox2D viewport_camera_border;
NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, left)
NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, right)
NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, bottom)
NODE_SOCKET_API_STRUCT_MEMBER(float, viewport_camera_border, top)
/* transformation */
Transform matrix;
NODE_SOCKET_API(Transform, matrix)
/* motion */
array<Transform> motion;
bool use_perspective_motion;
float fov_pre, fov_post;
NODE_SOCKET_API_ARRAY(array<Transform>, motion)
NODE_SOCKET_API(bool, use_perspective_motion)
NODE_SOCKET_API(float, fov_pre)
NODE_SOCKET_API(float, fov_post)
/* computed camera parameters */
ProjectionTransform screentoworld;
@ -174,7 +188,6 @@ class Camera : public Node {
float3 frustum_bottom_normal;
/* update */
bool need_update;
bool need_device_update;
bool need_flags_update;
int previous_need_motion;
@ -183,6 +196,12 @@ class Camera : public Node {
KernelCamera kernel_camera;
array<DecomposedTransform> kernel_camera_motion;
private:
int width;
int height;
int resolution;
public:
/* functions */
Camera();
~Camera();
@ -195,10 +214,6 @@ class Camera : public Node {
void device_update_volume(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
bool modified(const Camera &cam);
bool motion_modified(const Camera &cam);
void tag_update();
/* Public utility functions. */
BoundBox viewplane_bounds_get();
@ -210,6 +225,8 @@ class Camera : public Node {
int motion_step(float time) const;
bool use_motion() const;
void set_screen_size_and_resolution(int width_, int height_, int resolution_);
private:
/* Private utility functions. */
float3 transform_raster_to_world(float raster_x, float raster_y);

@ -40,10 +40,8 @@ static bool compare_pass_order(const Pass &a, const Pass &b)
return (a.components > b.components);
}
NODE_DEFINE(Pass)
static NodeEnum *get_pass_type_enum()
{
NodeType *type = NodeType::add("pass", create);
static NodeEnum pass_type_enum;
pass_type_enum.insert("combined", PASS_COMBINED);
pass_type_enum.insert("depth", PASS_DEPTH);
@ -84,7 +82,15 @@ NODE_DEFINE(Pass)
pass_type_enum.insert("bake_primitive", PASS_BAKE_PRIMITIVE);
pass_type_enum.insert("bake_differential", PASS_BAKE_DIFFERENTIAL);
SOCKET_ENUM(type, "Type", pass_type_enum, PASS_COMBINED);
return &pass_type_enum;
}
NODE_DEFINE(Pass)
{
NodeType *type = NodeType::add("pass", create);
NodeEnum *pass_type_enum = get_pass_type_enum();
SOCKET_ENUM(type, "Type", *pass_type_enum, PASS_COMBINED);
SOCKET_STRING(name, "Name", ustring());
return type;
@ -383,6 +389,21 @@ NODE_DEFINE(Film)
SOCKET_INT(denoising_flags, "Denoising Flags", 0);
SOCKET_BOOLEAN(use_adaptive_sampling, "Use Adaptive Sampling", false);
SOCKET_BOOLEAN(use_light_visibility, "Use Light Visibility", false);
NodeEnum *pass_type_enum = get_pass_type_enum();
SOCKET_ENUM(display_pass, "Display Pass", *pass_type_enum, PASS_COMBINED);
static NodeEnum cryptomatte_passes_enum;
cryptomatte_passes_enum.insert("none", CRYPT_NONE);
cryptomatte_passes_enum.insert("object", CRYPT_OBJECT);
cryptomatte_passes_enum.insert("material", CRYPT_MATERIAL);
cryptomatte_passes_enum.insert("asset", CRYPT_ASSET);
cryptomatte_passes_enum.insert("accurate", CRYPT_ACCURATE);
SOCKET_ENUM(cryptomatte_passes, "Cryptomatte Passes", cryptomatte_passes_enum, CRYPT_NONE);
SOCKET_INT(cryptomatte_depth, "Cryptomatte Depth", 0);
return type;
}
@ -392,8 +413,6 @@ Film::Film() : Node(node_type)
filter_table_offset = TABLE_OFFSET_INVALID;
cryptomatte_passes = CRYPT_NONE;
display_pass = PASS_COMBINED;
need_update = true;
}
Film::~Film()
@ -407,7 +426,7 @@ void Film::add_default(Scene *scene)
void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
{
if (!need_update)
if (!is_modified())
return;
scoped_callback_timer timer([scene](double time) {
@ -658,7 +677,7 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
denoising_data_offset = kfilm->pass_denoising_data;
denoising_clean_offset = kfilm->pass_denoising_clean;
need_update = false;
clear_modified();
}
void Film::device_free(Device * /*device*/, DeviceScene * /*dscene*/, Scene *scene)
@ -666,11 +685,6 @@ void Film::device_free(Device * /*device*/, DeviceScene * /*dscene*/, Scene *sce
scene->lookup_tables->remove_table(&filter_table_offset);
}
bool Film::modified(const Film &film)
{
return !Node::equals(film);
}
void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes)
{
if (Pass::contains(scene->passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) {
@ -691,11 +705,6 @@ void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool upd
}
}
void Film::tag_update(Scene * /*scene*/)
{
need_update = true;
}
int Film::get_aov_offset(Scene *scene, string name, bool &is_color)
{
int num_color = 0, num_value = 0;
@ -719,4 +728,24 @@ int Film::get_aov_offset(Scene *scene, string name, bool &is_color)
return -1;
}
int Film::get_pass_stride() const
{
return pass_stride;
}
int Film::get_denoising_data_offset() const
{
return denoising_data_offset;
}
int Film::get_denoising_clean_offset() const
{
return denoising_clean_offset;
}
size_t Film::get_filter_table_offset() const
{
return filter_table_offset;
}
CCL_NAMESPACE_END

@ -60,34 +60,35 @@ class Film : public Node {
public:
NODE_DECLARE
float exposure;
bool denoising_data_pass;
bool denoising_clean_pass;
bool denoising_prefiltered_pass;
int denoising_flags;
float pass_alpha_threshold;
NODE_SOCKET_API(float, exposure)
NODE_SOCKET_API(bool, denoising_data_pass)
NODE_SOCKET_API(bool, denoising_clean_pass)
NODE_SOCKET_API(bool, denoising_prefiltered_pass)
NODE_SOCKET_API(int, denoising_flags)
NODE_SOCKET_API(float, pass_alpha_threshold)
PassType display_pass;
NODE_SOCKET_API(PassType, display_pass)
NODE_SOCKET_API(FilterType, filter_type)
NODE_SOCKET_API(float, filter_width)
NODE_SOCKET_API(float, mist_start)
NODE_SOCKET_API(float, mist_depth)
NODE_SOCKET_API(float, mist_falloff)
NODE_SOCKET_API(bool, use_light_visibility)
NODE_SOCKET_API(CryptomatteType, cryptomatte_passes)
NODE_SOCKET_API(int, cryptomatte_depth)
NODE_SOCKET_API(bool, use_adaptive_sampling)
private:
int pass_stride;
int denoising_data_offset;
int denoising_clean_offset;
FilterType filter_type;
float filter_width;
size_t filter_table_offset;
float mist_start;
float mist_depth;
float mist_falloff;
bool use_light_visibility;
CryptomatteType cryptomatte_passes;
int cryptomatte_depth;
bool use_adaptive_sampling;
bool need_update;
public:
Film();
~Film();
@ -97,11 +98,14 @@ class Film : public Node {
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
bool modified(const Film &film);
void tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes = true);
void tag_update(Scene *scene);
int get_aov_offset(Scene *scene, string name, bool &is_color);
int get_pass_stride() const;
int get_denoising_data_offset() const;
int get_denoising_clean_offset() const;
size_t get_filter_table_offset() const;
};
CCL_NAMESPACE_END

@ -52,14 +52,14 @@ NODE_ABSTRACT_DEFINE(Geometry)
SOCKET_UINT(motion_steps, "Motion Steps", 3);
SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false);
SOCKET_NODE_ARRAY(used_shaders, "Shaders", &Shader::node_type);
return type;
}
Geometry::Geometry(const NodeType *node_type, const Type type)
: Node(node_type), type(type), attributes(this, ATTR_PRIM_GEOMETRY)
: Node(node_type), geometry_type(type), attributes(this, ATTR_PRIM_GEOMETRY)
{
need_update = true;
need_update_rebuild = false;
transform_applied = false;
@ -99,9 +99,11 @@ bool Geometry::need_attribute(Scene *scene, AttributeStandard std)
if (scene->need_global_attribute(std))
return true;
foreach (Shader *shader, used_shaders)
foreach (Node *node, used_shaders) {
Shader *shader = static_cast<Shader *>(node);
if (shader->attributes.find(std))
return true;
}
return false;
}
@ -111,9 +113,11 @@ bool Geometry::need_attribute(Scene * /*scene*/, ustring name)
if (name == ustring())
return false;
foreach (Shader *shader, used_shaders)
foreach (Node *node, used_shaders) {
Shader *shader = static_cast<Shader *>(node);
if (shader->attributes.find(name))
return true;
}
return false;
}
@ -122,8 +126,10 @@ AttributeRequestSet Geometry::needed_attributes()
{
AttributeRequestSet result;
foreach (Shader *shader, used_shaders)
foreach (Node *node, used_shaders) {
Shader *shader = static_cast<Shader *>(node);
result.add(shader->attributes);
}
return result;
}
@ -171,8 +177,9 @@ bool Geometry::is_instanced() const
bool Geometry::has_true_displacement() const
{
foreach (Shader *shader, used_shaders) {
if (shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) {
foreach (Node *node, used_shaders) {
Shader *shader = static_cast<Shader *>(node);
if (shader->has_displacement && shader->get_displacement_method() != DISPLACE_BUMP) {
return true;
}
}
@ -198,7 +205,7 @@ void Geometry::compute_bvh(
msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total);
Object object;
object.geometry = this;
object.set_geometry(this);
vector<Geometry *> geometry;
geometry.push_back(this);
@ -232,7 +239,7 @@ void Geometry::compute_bvh(
}
}
need_update = false;
clear_modified();
need_update_rebuild = false;
}
@ -254,16 +261,18 @@ bool Geometry::has_voxel_attributes() const
void Geometry::tag_update(Scene *scene, bool rebuild)
{
need_update = true;
tag_modified();
if (rebuild) {
need_update_rebuild = true;
scene->light_manager->need_update = true;
}
else {
foreach (Shader *shader, used_shaders)
foreach (Node *node, used_shaders) {
Shader *shader = static_cast<Shader *>(node);
if (shader->has_surface_emission)
scene->light_manager->need_update = true;
}
}
scene->geometry_manager->need_update = true;
@ -433,9 +442,9 @@ static void emit_attribute_mapping(
emit_attribute_map_entry(attr_map, index, id, req.type, req.desc);
if (geom->type == Geometry::MESH) {
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->subd_faces.size()) {
if (mesh->get_num_subd_faces()) {
emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc);
}
}
@ -547,19 +556,19 @@ static void update_attribute_element_size(Geometry *geom,
}
}
static void update_attribute_element_offset(Geometry *geom,
device_vector<float> &attr_float,
size_t &attr_float_offset,
device_vector<float2> &attr_float2,
size_t &attr_float2_offset,
device_vector<float4> &attr_float3,
size_t &attr_float3_offset,
device_vector<uchar4> &attr_uchar4,
size_t &attr_uchar4_offset,
Attribute *mattr,
AttributePrimitive prim,
TypeDesc &type,
AttributeDescriptor &desc)
void GeometryManager::update_attribute_element_offset(Geometry *geom,
device_vector<float> &attr_float,
size_t &attr_float_offset,
device_vector<float2> &attr_float2,
size_t &attr_float2_offset,
device_vector<float4> &attr_float3,
size_t &attr_float3_offset,
device_vector<uchar4> &attr_uchar4,
size_t &attr_uchar4_offset,
Attribute *mattr,
AttributePrimitive prim,
TypeDesc &type,
AttributeDescriptor &desc)
{
if (mattr) {
/* store element and type */
@ -631,7 +640,7 @@ static void update_attribute_element_offset(Geometry *geom,
/* mesh vertex/curve index is global, not per object, so we sneak
* a correction for that in here */
if (geom->type == Geometry::MESH) {
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK &&
desc.flags & ATTR_SUBDIVIDED) {
@ -655,7 +664,7 @@ static void update_attribute_element_offset(Geometry *geom,
offset -= mesh->corner_offset;
}
}
else if (geom->type == Geometry::HAIR) {
else if (geom->is_hair()) {
Hair *hair = static_cast<Hair *>(geom);
if (element == ATTR_ELEMENT_CURVE)
offset -= hair->prim_offset;
@ -690,7 +699,8 @@ void GeometryManager::device_update_attributes(Device *device,
geom->index = i;
scene->need_global_attributes(geom_attributes[i]);
foreach (Shader *shader, geom->used_shaders) {
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
geom_attributes[i].add(shader->attributes);
}
}
@ -754,7 +764,7 @@ void GeometryManager::device_update_attributes(Device *device,
&attr_float3_size,
&attr_uchar4_size);
if (geom->type == Geometry::MESH) {
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
Attribute *subd_attr = mesh->subd_attributes.find(req);
@ -816,7 +826,7 @@ void GeometryManager::device_update_attributes(Device *device,
req.type,
req.desc);
if (geom->type == Geometry::MESH) {
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
Attribute *subd_attr = mesh->subd_attributes.find(req);
@ -919,7 +929,7 @@ void GeometryManager::mesh_calc_offset(Scene *scene)
size_t optix_prim_size = 0;
foreach (Geometry *geom, scene->geometry) {
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
mesh->vert_offset = vert_size;
@ -932,8 +942,8 @@ void GeometryManager::mesh_calc_offset(Scene *scene)
vert_size += mesh->verts.size();
tri_size += mesh->num_triangles();
if (mesh->subd_faces.size()) {
Mesh::SubdFace &last = mesh->subd_faces[mesh->subd_faces.size() - 1];
if (mesh->get_num_subd_faces()) {
Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1);
patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
/* patch tables are stored in same array so include them in patch_size */
@ -943,19 +953,19 @@ void GeometryManager::mesh_calc_offset(Scene *scene)
}
}
face_size += mesh->subd_faces.size();
face_size += mesh->get_num_subd_faces();
corner_size += mesh->subd_face_corners.size();
mesh->optix_prim_offset = optix_prim_size;
optix_prim_size += mesh->num_triangles();
}
else if (geom->type == Geometry::HAIR) {
else if (geom->is_hair()) {
Hair *hair = static_cast<Hair *>(geom);
hair->curvekey_offset = curve_key_size;
hair->prim_offset = curve_size;
curve_key_size += hair->curve_keys.size();
curve_key_size += hair->get_curve_keys().size();
curve_size += hair->num_curves();
hair->optix_prim_offset = optix_prim_size;
@ -977,14 +987,14 @@ void GeometryManager::device_update_mesh(
size_t patch_size = 0;
foreach (Geometry *geom, scene->geometry) {
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
vert_size += mesh->verts.size();
tri_size += mesh->num_triangles();
if (mesh->subd_faces.size()) {
Mesh::SubdFace &last = mesh->subd_faces[mesh->subd_faces.size() - 1];
if (mesh->get_num_subd_faces()) {
Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1);
patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
/* patch tables are stored in same array so include them in patch_size */
@ -994,10 +1004,10 @@ void GeometryManager::device_update_mesh(
}
}
}
else if (geom->type == Geometry::HAIR) {
else if (geom->is_hair()) {
Hair *hair = static_cast<Hair *>(geom);
curve_key_size += hair->curve_keys.size();
curve_key_size += hair->get_curve_keys().size();
curve_size += hair->num_curves();
}
}
@ -1011,7 +1021,7 @@ void GeometryManager::device_update_mesh(
* really use same semantic of arrays.
*/
foreach (Geometry *geom, scene->geometry) {
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
for (size_t i = 0; i < mesh->num_triangles(); ++i) {
tri_prim_index[i + mesh->prim_offset] = 3 * (i + mesh->prim_offset);
@ -1039,7 +1049,7 @@ void GeometryManager::device_update_mesh(
float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
foreach (Geometry *geom, scene->geometry) {
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
mesh->pack_normals(&vnormal[mesh->vert_offset]);
@ -1071,7 +1081,7 @@ void GeometryManager::device_update_mesh(
float4 *curves = dscene->curves.alloc(curve_size);
foreach (Geometry *geom, scene->geometry) {
if (geom->type == Geometry::HAIR) {
if (geom->is_hair()) {
Hair *hair = static_cast<Hair *>(geom);
hair->pack_curves(scene,
&curve_keys[hair->curvekey_offset],
@ -1092,7 +1102,7 @@ void GeometryManager::device_update_mesh(
uint *patch_data = dscene->patches.alloc(patch_size);
foreach (Geometry *geom, scene->geometry) {
if (geom->type == Geometry::MESH) {
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
mesh->pack_patches(&patch_data[mesh->patch_offset],
mesh->vert_offset,
@ -1115,7 +1125,7 @@ void GeometryManager::device_update_mesh(
if (for_displacement) {
float4 *prim_tri_verts = dscene->prim_tri_verts.alloc(tri_size * 3);
foreach (Geometry *geom, scene->geometry) {
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
for (size_t i = 0; i < mesh->num_triangles(); ++i) {
Mesh::Triangle t = mesh->get_triangle(i);
@ -1242,7 +1252,8 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
foreach (Geometry *geom, scene->geometry) {
geom->has_volume = false;
foreach (const Shader *shader, geom->used_shaders) {
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->has_volume) {
geom->has_volume = true;
}
@ -1254,7 +1265,7 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
/* Re-create volume mesh if we will rebuild or refit the BVH. Note we
* should only do it in that case, otherwise the BVH and mesh can go
* out of sync. */
if (geom->need_update && geom->type == Geometry::VOLUME) {
if (geom->is_modified() && geom->geometry_type == Geometry::VOLUME) {
/* Create volume meshes if there is voxel data. */
if (!volume_images_updated) {
progress.set_status("Updating Meshes Volume Bounds");
@ -1266,7 +1277,7 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
create_volume_mesh(volume, progress);
}
if (geom->type == Geometry::HAIR) {
if (geom->is_hair()) {
/* Set curve shape, still a global scene setting for now. */
Hair *hair = static_cast<Hair *>(geom);
hair->curve_shape = scene->params.hair_shape;
@ -1285,9 +1296,10 @@ void GeometryManager::device_update_displacement_images(Device *device,
ImageManager *image_manager = scene->image_manager;
set<int> bump_images;
foreach (Geometry *geom, scene->geometry) {
if (geom->need_update) {
foreach (Shader *shader, geom->used_shaders) {
if (!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
if (geom->is_modified()) {
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
continue;
}
foreach (ShaderNode *node, shader->graph->nodes) {
@ -1321,7 +1333,7 @@ void GeometryManager::device_update_volume_images(Device *device, Scene *scene,
set<int> volume_images;
foreach (Geometry *geom, scene->geometry) {
if (!geom->need_update) {
if (!geom->is_modified()) {
continue;
}
@ -1370,12 +1382,14 @@ void GeometryManager::device_update(Device *device,
});
foreach (Geometry *geom, scene->geometry) {
foreach (Shader *shader, geom->used_shaders) {
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->need_update_geometry)
geom->need_update = true;
geom->tag_modified();
}
if (geom->need_update && (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME)) {
if (geom->is_modified() &&
(geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME)) {
Mesh *mesh = static_cast<Mesh *>(geom);
/* Update normals. */
@ -1387,8 +1401,7 @@ void GeometryManager::device_update(Device *device,
}
/* Test if we need tessellation. */
if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE && mesh->num_subd_verts == 0 &&
mesh->subd_params) {
if (mesh->need_tesselation()) {
total_tess_needed++;
}
@ -1413,17 +1426,18 @@ void GeometryManager::device_update(Device *device,
});
Camera *dicing_camera = scene->dicing_camera;
dicing_camera->set_screen_size_and_resolution(
dicing_camera->get_full_width(), dicing_camera->get_full_height(), 1);
dicing_camera->update(scene);
size_t i = 0;
foreach (Geometry *geom, scene->geometry) {
if (!(geom->need_update && geom->type == Geometry::MESH)) {
if (!(geom->is_modified() && geom->is_mesh())) {
continue;
}
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE && mesh->num_subd_verts == 0 &&
mesh->subd_params) {
if (mesh->need_tesselation()) {
string msg = "Tessellating ";
if (mesh->name == "")
msg += string_printf("%u/%u", (uint)(i + 1), (uint)total_tess_needed);
@ -1500,8 +1514,8 @@ void GeometryManager::device_update(Device *device,
});
foreach (Geometry *geom, scene->geometry) {
if (geom->need_update) {
if (geom->type == Geometry::MESH) {
if (geom->is_modified()) {
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (displace(device, dscene, scene, mesh, progress)) {
displacement_done = true;
@ -1543,7 +1557,7 @@ void GeometryManager::device_update(Device *device,
size_t i = 0;
foreach (Geometry *geom, scene->geometry) {
if (geom->need_update) {
if (geom->is_modified()) {
pool.push(function_bind(
&Geometry::compute_bvh, geom, device, dscene, &scene->params, &progress, i, num_bvh));
if (geom->need_build_bvh(bvh_layout)) {

@ -56,13 +56,13 @@ class Geometry : public Node {
VOLUME,
};
Type type;
Type geometry_type;
/* Attributes */
AttributeSet attributes;
/* Shaders */
vector<Shader *> used_shaders;
NODE_SOCKET_API_ARRAY(array<Node *>, used_shaders)
/* Transform */
BoundBox bounds;
@ -71,8 +71,8 @@ class Geometry : public Node {
Transform transform_normal;
/* Motion Blur */
uint motion_steps;
bool use_motion_blur;
NODE_SOCKET_API(uint, motion_steps)
NODE_SOCKET_API(bool, use_motion_blur)
/* Maximum number of motion steps supported (due to Embree). */
static const uint MAX_MOTION_STEPS = 129;
@ -88,7 +88,6 @@ class Geometry : public Node {
bool has_surface_bssrdf; /* Set in the device_update_flags(). */
/* Update Flags */
bool need_update;
bool need_update_rebuild;
/* Index into scene->geometry (only valid during update) */
@ -143,6 +142,16 @@ class Geometry : public Node {
bool has_motion_blur() const;
bool has_voxel_attributes() const;
bool is_mesh() const
{
return geometry_type == MESH;
}
bool is_hair() const
{
return geometry_type == HAIR;
}
/* Updates */
void tag_update(Scene *scene, bool rebuild);
};
@ -206,6 +215,21 @@ class GeometryManager {
void device_update_displacement_images(Device *device, Scene *scene, Progress &progress);
void device_update_volume_images(Device *device, Scene *scene, Progress &progress);
private:
static void update_attribute_element_offset(Geometry *geom,
device_vector<float> &attr_float,
size_t &attr_float_offset,
device_vector<float2> &attr_float2,
size_t &attr_float2_offset,
device_vector<float4> &attr_float3,
size_t &attr_float3_offset,
device_vector<uchar4> &attr_uchar4,
size_t &attr_uchar4_offset,
Attribute *mattr,
AttributePrimitive prim,
TypeDesc &type,
AttributeDescriptor &desc);
};
CCL_NAMESPACE_END

@ -273,8 +273,8 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
if (to->type() == SocketType::CLOSURE) {
EmissionNode *emission = create_node<EmissionNode>();
emission->color = make_float3(1.0f, 1.0f, 1.0f);
emission->strength = 1.0f;
emission->set_color(make_float3(1.0f, 1.0f, 1.0f));
emission->set_strength(1.0f);
convert = add(emission);
/* Connect float inputs to Strength to save an additional Falue->Color conversion. */
if (from->type() == SocketType::FLOAT) {
@ -586,7 +586,7 @@ void ShaderGraph::constant_fold(Scene *scene)
*/
if (has_displacement && !output()->input("Displacement")->link) {
ColorNode *value = (ColorNode *)add(create_node<ColorNode>());
value->value = output()->displacement;
value->set_value(output()->get_displacement());
connect(value->output("Color"), output()->input("Displacement"));
}
@ -1003,8 +1003,8 @@ void ShaderGraph::bump_from_displacement(bool use_object_space)
/* add bump node and connect copied graphs to it */
BumpNode *bump = (BumpNode *)add(create_node<BumpNode>());
bump->use_object_space = use_object_space;
bump->distance = 1.0f;
bump->set_use_object_space(use_object_space);
bump->set_distance(1.0f);
ShaderOutput *out = displacement_in->link;
ShaderOutput *out_center = nodes_center[out->parent]->output(out->name());
@ -1016,9 +1016,9 @@ void ShaderGraph::bump_from_displacement(bool use_object_space)
VectorMathNode *dot_dx = (VectorMathNode *)add(create_node<VectorMathNode>());
VectorMathNode *dot_dy = (VectorMathNode *)add(create_node<VectorMathNode>());
dot_center->type = NODE_VECTOR_MATH_DOT_PRODUCT;
dot_dx->type = NODE_VECTOR_MATH_DOT_PRODUCT;
dot_dy->type = NODE_VECTOR_MATH_DOT_PRODUCT;
dot_center->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
dot_dx->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
dot_dy->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
GeometryNode *geom = (GeometryNode *)add(create_node<GeometryNode>());
connect(geom->output("Normal"), dot_center->input("Vector2"));
@ -1072,7 +1072,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
if (fin->link)
connect(fin->link, fac_in);
else
mix_node->fac = node->get_float(fin->socket_type);
mix_node->set_fac(node->get_float(fin->socket_type));
if (weight_out)
connect(weight_out, weight_in);
@ -1107,12 +1107,12 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
if (weight_in->link)
connect(weight_in->link, math_node->input("Value1"));
else
math_node->value1 = weight_value;
math_node->set_value1(weight_value);
if (weight_out)
connect(weight_out, math_node->input("Value2"));
else
math_node->value2 = 1.0f;
math_node->set_value2(1.0f);
weight_out = math_node->output("Value");
if (weight_in->link)

@ -337,12 +337,18 @@ void Hair::add_curve_key(float3 co, float radius)
{
curve_keys.push_back_reserved(co);
curve_radius.push_back_reserved(radius);
tag_curve_keys_modified();
tag_curve_radius_modified();
}
void Hair::add_curve(int first_key, int shader)
{
curve_first_key.push_back_reserved(first_key);
curve_shader.push_back_reserved(shader);
tag_curve_first_key_modified();
tag_curve_shader_modified();
}
void Hair::copy_center_to_motion_step(const int motion_step)
@ -474,8 +480,9 @@ void Hair::pack_curves(Scene *scene,
for (size_t i = 0; i < curve_num; i++) {
Curve curve = get_curve(i);
int shader_id = curve_shader[i];
Shader *shader = (shader_id < used_shaders.size()) ? used_shaders[shader_id] :
scene->default_surface;
Shader *shader = (shader_id < used_shaders.size()) ?
static_cast<Shader *>(used_shaders[shader_id]) :
scene->default_surface;
shader_id = scene->shader_manager->get_shader_id(shader, false);
curve_data[i] = make_float4(__int_as_float(curve.first_key + curvekey_offset),

@ -89,10 +89,10 @@ class Hair : public Geometry {
float4 r_keys[4]) const;
};
array<float3> curve_keys;
array<float> curve_radius;
array<int> curve_first_key;
array<int> curve_shader;
NODE_SOCKET_API(array<float3>, curve_keys)
NODE_SOCKET_API(array<float>, curve_radius)
NODE_SOCKET_API(array<int>, curve_first_key)
NODE_SOCKET_API(array<int>, curve_shader)
/* BVH */
size_t curvekey_offset;

@ -381,7 +381,7 @@ ImageHandle ImageManager::add_image(const string &filename, const ImageParams &p
ImageHandle ImageManager::add_image(const string &filename,
const ImageParams &params,
const vector<int> &tiles)
const array<int> &tiles)
{
ImageHandle handle;
handle.manager = this;

@ -174,7 +174,7 @@ class ImageManager {
ImageHandle add_image(const string &filename, const ImageParams &params);
ImageHandle add_image(const string &filename,
const ImageParams &params,
const vector<int> &tiles);
const array<int> &tiles);
ImageHandle add_image(ImageLoader *loader, const ImageParams &params, const bool builtin = true);
void device_update(Device *device, Scene *scene, Progress &progress);

@ -96,7 +96,6 @@ NODE_DEFINE(Integrator)
Integrator::Integrator() : Node(node_type)
{
need_update = true;
}
Integrator::~Integrator()
@ -105,7 +104,7 @@ Integrator::~Integrator()
void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene)
{
if (!need_update)
if (!is_modified())
return;
scoped_callback_timer timer([scene](double time) {
@ -144,7 +143,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->transparent_shadows = false;
foreach (Shader *shader, scene->shaders) {
/* keep this in sync with SD_HAS_TRANSPARENT_SHADOW in shader.cpp */
if ((shader->has_surface_transparent && shader->use_transparent_shadow) ||
if ((shader->has_surface_transparent && shader->get_use_transparent_shadow()) ||
shader->has_volume) {
kintegrator->transparent_shadows = true;
break;
@ -227,7 +226,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
if (method == BRANCHED_PATH) {
foreach (Light *light, scene->lights)
max_samples = max(max_samples, light->samples);
max_samples = max(max_samples, light->get_samples());
max_samples = max(max_samples,
max(diffuse_samples, max(glossy_samples, transmission_samples)));
@ -265,7 +264,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
dscene->sample_pattern_lut.copy_to_device();
}
need_update = false;
clear_modified();
}
void Integrator::device_free(Device *, DeviceScene *dscene)
@ -273,11 +272,6 @@ void Integrator::device_free(Device *, DeviceScene *dscene)
dscene->sample_pattern_lut.free();
}
bool Integrator::modified(const Integrator &integrator)
{
return !Node::equals(integrator);
}
void Integrator::tag_update(Scene *scene)
{
foreach (Shader *shader, scene->shaders) {
@ -286,7 +280,7 @@ void Integrator::tag_update(Scene *scene)
break;
}
}
need_update = true;
tag_modified();
}
CCL_NAMESPACE_END

@ -31,52 +31,52 @@ class Integrator : public Node {
public:
NODE_DECLARE
int min_bounce;
int max_bounce;
NODE_SOCKET_API(int, min_bounce)
NODE_SOCKET_API(int, max_bounce)
int max_diffuse_bounce;
int max_glossy_bounce;
int max_transmission_bounce;
int max_volume_bounce;
NODE_SOCKET_API(int, max_diffuse_bounce)
NODE_SOCKET_API(int, max_glossy_bounce)
NODE_SOCKET_API(int, max_transmission_bounce)
NODE_SOCKET_API(int, max_volume_bounce)
int transparent_min_bounce;
int transparent_max_bounce;
NODE_SOCKET_API(int, transparent_min_bounce)
NODE_SOCKET_API(int, transparent_max_bounce)
int ao_bounces;
NODE_SOCKET_API(int, ao_bounces)
int volume_max_steps;
float volume_step_rate;
NODE_SOCKET_API(int, volume_max_steps)
NODE_SOCKET_API(float, volume_step_rate)
bool caustics_reflective;
bool caustics_refractive;
float filter_glossy;
NODE_SOCKET_API(bool, caustics_reflective)
NODE_SOCKET_API(bool, caustics_refractive)
NODE_SOCKET_API(float, filter_glossy)
int seed;
NODE_SOCKET_API(int, seed)
float sample_clamp_direct;
float sample_clamp_indirect;
bool motion_blur;
NODE_SOCKET_API(float, sample_clamp_direct)
NODE_SOCKET_API(float, sample_clamp_indirect)
NODE_SOCKET_API(bool, motion_blur)
/* Maximum number of samples, beyond which we are likely to run into
* precision issues for sampling patterns. */
static const int MAX_SAMPLES = (1 << 24);
int aa_samples;
int diffuse_samples;
int glossy_samples;
int transmission_samples;
int ao_samples;
int mesh_light_samples;
int subsurface_samples;
int volume_samples;
int start_sample;
NODE_SOCKET_API(int, aa_samples)
NODE_SOCKET_API(int, diffuse_samples)
NODE_SOCKET_API(int, glossy_samples)
NODE_SOCKET_API(int, transmission_samples)
NODE_SOCKET_API(int, ao_samples)
NODE_SOCKET_API(int, mesh_light_samples)
NODE_SOCKET_API(int, subsurface_samples)
NODE_SOCKET_API(int, volume_samples)
NODE_SOCKET_API(int, start_sample)
bool sample_all_lights_direct;
bool sample_all_lights_indirect;
float light_sampling_threshold;
NODE_SOCKET_API(bool, sample_all_lights_direct)
NODE_SOCKET_API(bool, sample_all_lights_indirect)
NODE_SOCKET_API(float, light_sampling_threshold)
int adaptive_min_samples;
float adaptive_threshold;
NODE_SOCKET_API(int, adaptive_min_samples)
NODE_SOCKET_API(float, adaptive_threshold)
enum Method {
BRANCHED_PATH = 0,
@ -85,11 +85,9 @@ class Integrator : public Node {
NUM_METHODS,
};
Method method;
NODE_SOCKET_API(Method, method)
SamplingPattern sampling_pattern;
bool need_update;
NODE_SOCKET_API(SamplingPattern, sampling_pattern)
Integrator();
~Integrator();
@ -97,7 +95,6 @@ class Integrator : public Node {
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene);
bool modified(const Integrator &integrator);
void tag_update(Scene *scene);
};

@ -114,7 +114,7 @@ NODE_DEFINE(Light)
type_enum.insert("background", LIGHT_BACKGROUND);
type_enum.insert("area", LIGHT_AREA);
type_enum.insert("spot", LIGHT_SPOT);
SOCKET_ENUM(type, "Type", type_enum, LIGHT_POINT);
SOCKET_ENUM(light_type, "Type", type_enum, LIGHT_POINT);
SOCKET_COLOR(strength, "Strength", make_float3(1.0f, 1.0f, 1.0f));
@ -162,7 +162,7 @@ Light::Light() : Node(node_type)
void Light::tag_update(Scene *scene)
{
scene->light_manager->need_update = true;
scene->light_manager->need_update = is_modified();
}
bool Light::has_contribution(Scene *scene)
@ -173,7 +173,7 @@ bool Light::has_contribution(Scene *scene)
if (is_portal) {
return false;
}
if (type == LIGHT_BACKGROUND) {
if (light_type == LIGHT_BACKGROUND) {
return true;
}
return (shader) ? shader->has_surface_emission : scene->default_light->has_surface_emission;
@ -200,7 +200,7 @@ LightManager::~LightManager()
bool LightManager::has_background_light(Scene *scene)
{
foreach (Light *light, scene->lights) {
if (light->type == LIGHT_BACKGROUND && light->is_enabled) {
if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) {
return true;
}
}
@ -217,7 +217,7 @@ void LightManager::test_enabled_lights(Scene *scene)
foreach (Light *light, scene->lights) {
light->is_enabled = light->has_contribution(scene);
has_portal |= light->is_portal;
has_background |= light->type == LIGHT_BACKGROUND;
has_background |= light->light_type == LIGHT_BACKGROUND;
}
bool background_enabled = false;
@ -232,7 +232,7 @@ void LightManager::test_enabled_lights(Scene *scene)
const bool disable_mis = !(has_portal || shader->has_surface_spatial_varying);
VLOG_IF(1, disable_mis) << "Background MIS has been disabled.\n";
foreach (Light *light, scene->lights) {
if (light->type == LIGHT_BACKGROUND) {
if (light->light_type == LIGHT_BACKGROUND) {
light->is_enabled = !disable_mis;
background_enabled = !disable_mis;
background_resolution = light->map_resolution;
@ -250,8 +250,8 @@ void LightManager::test_enabled_lights(Scene *scene)
bool LightManager::object_usable_as_light(Object *object)
{
Geometry *geom = object->geometry;
if (geom->type != Geometry::MESH && geom->type != Geometry::VOLUME) {
Geometry *geom = object->get_geometry();
if (geom->geometry_type != Geometry::MESH && geom->geometry_type != Geometry::VOLUME) {
return false;
}
/* Skip objects with NaNs */
@ -259,7 +259,7 @@ bool LightManager::object_usable_as_light(Object *object)
return false;
}
/* Skip if we are not visible for BSDFs. */
if (!(object->visibility & (PATH_RAY_DIFFUSE | PATH_RAY_GLOSSY | PATH_RAY_TRANSMIT))) {
if (!(object->get_visibility() & (PATH_RAY_DIFFUSE | PATH_RAY_GLOSSY | PATH_RAY_TRANSMIT))) {
return false;
}
/* Skip if we have no emission shaders. */
@ -267,8 +267,9 @@ bool LightManager::object_usable_as_light(Object *object)
* iterate all geometry shaders twice (when counting and when calculating
* triangle area.
*/
foreach (const Shader *shader, geom->used_shaders) {
if (shader->use_mis && shader->has_surface_emission) {
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->get_use_mis() && shader->has_surface_emission) {
return true;
}
}
@ -308,15 +309,15 @@ void LightManager::device_update_distribution(Device *,
}
/* Count triangles. */
Mesh *mesh = static_cast<Mesh *>(object->geometry);
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
size_t mesh_num_triangles = mesh->num_triangles();
for (size_t i = 0; i < mesh_num_triangles; i++) {
int shader_index = mesh->shader[i];
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] :
int shader_index = mesh->get_shader()[i];
Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
scene->default_surface;
if (shader->use_mis && shader->has_surface_emission) {
if (shader->get_use_mis() && shader->has_surface_emission) {
num_triangles++;
}
}
@ -342,37 +343,37 @@ void LightManager::device_update_distribution(Device *,
continue;
}
/* Sum area. */
Mesh *mesh = static_cast<Mesh *>(object->geometry);
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
bool transform_applied = mesh->transform_applied;
Transform tfm = object->tfm;
Transform tfm = object->get_tfm();
int object_id = j;
int shader_flag = 0;
if (!(object->visibility & PATH_RAY_DIFFUSE)) {
if (!(object->get_visibility() & PATH_RAY_DIFFUSE)) {
shader_flag |= SHADER_EXCLUDE_DIFFUSE;
use_light_visibility = true;
}
if (!(object->visibility & PATH_RAY_GLOSSY)) {
if (!(object->get_visibility() & PATH_RAY_GLOSSY)) {
shader_flag |= SHADER_EXCLUDE_GLOSSY;
use_light_visibility = true;
}
if (!(object->visibility & PATH_RAY_TRANSMIT)) {
if (!(object->get_visibility() & PATH_RAY_TRANSMIT)) {
shader_flag |= SHADER_EXCLUDE_TRANSMIT;
use_light_visibility = true;
}
if (!(object->visibility & PATH_RAY_VOLUME_SCATTER)) {
if (!(object->get_visibility() & PATH_RAY_VOLUME_SCATTER)) {
shader_flag |= SHADER_EXCLUDE_SCATTER;
use_light_visibility = true;
}
size_t mesh_num_triangles = mesh->num_triangles();
for (size_t i = 0; i < mesh_num_triangles; i++) {
int shader_index = mesh->shader[i];
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] :
int shader_index = mesh->get_shader()[i];
Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
scene->default_surface;
if (shader->use_mis && shader->has_surface_emission) {
if (shader->get_use_mis() && shader->has_surface_emission) {
distribution[offset].totarea = totarea;
distribution[offset].prim = i + mesh->prim_offset;
distribution[offset].mesh_light.shader_flag = shader_flag;
@ -380,12 +381,12 @@ void LightManager::device_update_distribution(Device *,
offset++;
Mesh::Triangle t = mesh->get_triangle(i);
if (!t.valid(&mesh->verts[0])) {
if (!t.valid(&mesh->get_verts()[0])) {
continue;
}
float3 p1 = mesh->verts[t.v[0]];
float3 p2 = mesh->verts[t.v[1]];
float3 p3 = mesh->verts[t.v[2]];
float3 p1 = mesh->get_verts()[t.v[0]];
float3 p2 = mesh->get_verts()[t.v[1]];
float3 p3 = mesh->get_verts()[t.v[2]];
if (!transform_applied) {
p1 = transform_point(&tfm, p1);
@ -417,16 +418,16 @@ void LightManager::device_update_distribution(Device *,
distribution[offset].lamp.size = light->size;
totarea += lightarea;
if (light->type == LIGHT_DISTANT) {
if (light->light_type == LIGHT_DISTANT) {
use_lamp_mis |= (light->angle > 0.0f && light->use_mis);
}
else if (light->type == LIGHT_POINT || light->type == LIGHT_SPOT) {
else if (light->light_type == LIGHT_POINT || light->light_type == LIGHT_SPOT) {
use_lamp_mis |= (light->size > 0.0f && light->use_mis);
}
else if (light->type == LIGHT_AREA) {
else if (light->light_type == LIGHT_AREA) {
use_lamp_mis |= light->use_mis;
}
else if (light->type == LIGHT_BACKGROUND) {
else if (light->light_type == LIGHT_BACKGROUND) {
num_background_lights++;
background_mis |= light->use_mis;
}
@ -576,7 +577,7 @@ void LightManager::device_update_background(Device *device,
/* find background light */
foreach (Light *light, scene->lights) {
if (light->type == LIGHT_BACKGROUND) {
if (light->light_type == LIGHT_BACKGROUND) {
background_light = light;
break;
}
@ -611,7 +612,7 @@ void LightManager::device_update_background(Device *device,
}
if (node->type == SkyTextureNode::node_type) {
SkyTextureNode *sky = (SkyTextureNode *)node;
if (sky->type == NODE_SKY_NISHITA && sky->sun_disc) {
if (sky->get_sky_type() == NODE_SKY_NISHITA && sky->get_sun_disc()) {
/* Ensure that the input coordinates aren't transformed before they reach the node.
* If that is the case, the logic used for sampling the sun's location does not work
* and we have to fall back to map-based sampling. */
@ -627,8 +628,8 @@ void LightManager::device_update_background(Device *device,
}
/* Determine sun direction from lat/long and texture mapping. */
float latitude = sky->sun_elevation;
float longitude = M_2PI_F - sky->sun_rotation + M_PI_2_F;
float latitude = sky->get_sun_elevation();
float longitude = M_2PI_F - sky->get_sun_rotation() + M_PI_2_F;
float3 sun_direction = make_float3(
cosf(latitude) * cosf(longitude), cosf(latitude) * sinf(longitude), sinf(latitude));
Transform sky_transform = transform_inverse(sky->tex_mapping.compute_transform());
@ -771,13 +772,13 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
use_light_visibility = true;
}
klights[light_index].type = light->type;
klights[light_index].type = light->light_type;
klights[light_index].samples = light->samples;
klights[light_index].strength[0] = light->strength.x;
klights[light_index].strength[1] = light->strength.y;
klights[light_index].strength[2] = light->strength.z;
if (light->type == LIGHT_POINT) {
if (light->light_type == LIGHT_POINT) {
shader_id &= ~SHADER_AREA_LIGHT;
float radius = light->size;
@ -793,7 +794,7 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
klights[light_index].spot.radius = radius;
klights[light_index].spot.invarea = invarea;
}
else if (light->type == LIGHT_DISTANT) {
else if (light->light_type == LIGHT_DISTANT) {
shader_id &= ~SHADER_AREA_LIGHT;
float angle = light->angle / 2.0f;
@ -816,8 +817,8 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
klights[light_index].distant.radius = radius;
klights[light_index].distant.cosangle = cosangle;
}
else if (light->type == LIGHT_BACKGROUND) {
uint visibility = scene->background->visibility;
else if (light->light_type == LIGHT_BACKGROUND) {
uint visibility = scene->background->get_visibility();
shader_id &= ~SHADER_AREA_LIGHT;
shader_id |= SHADER_USE_MIS;
@ -839,7 +840,7 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
use_light_visibility = true;
}
}
else if (light->type == LIGHT_AREA) {
else if (light->light_type == LIGHT_AREA) {
float3 axisu = light->axisu * (light->sizeu * light->size);
float3 axisv = light->axisv * (light->sizev * light->size);
float area = len(axisu) * len(axisv);
@ -869,7 +870,7 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
klights[light_index].area.dir[1] = dir.y;
klights[light_index].area.dir[2] = dir.z;
}
else if (light->type == LIGHT_SPOT) {
else if (light->light_type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
float radius = light->size;
@ -913,7 +914,7 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
foreach (Light *light, scene->lights) {
if (!light->is_portal)
continue;
assert(light->type == LIGHT_AREA);
assert(light->light_type == LIGHT_AREA);
float3 co = light->co;
float3 axisu = light->axisu * (light->sizeu * light->size);
@ -995,10 +996,7 @@ void LightManager::device_update(Device *device,
if (progress.get_cancel())
return;
if (use_light_visibility != scene->film->use_light_visibility) {
scene->film->use_light_visibility = use_light_visibility;
scene->film->tag_update(scene);
}
scene->film->set_use_light_visibility(use_light_visibility);
need_update = false;
need_update_background = false;

@ -21,6 +21,10 @@
#include "graph/node.h"
/* included as Light::set_shader defined through NODE_SOCKET_API does not select
* the right Node::set overload as it does not know that Shader is a Node */
#include "render/shader.h"
#include "util/util_ies.h"
#include "util/util_thread.h"
#include "util/util_types.h"
@ -41,46 +45,48 @@ class Light : public Node {
Light();
LightType type;
float3 strength;
float3 co;
NODE_SOCKET_API(LightType, light_type)
NODE_SOCKET_API(float3, strength)
NODE_SOCKET_API(float3, co)
float3 dir;
float size;
float angle;
NODE_SOCKET_API(float3, dir)
NODE_SOCKET_API(float, size)
NODE_SOCKET_API(float, angle)
float3 axisu;
float sizeu;
float3 axisv;
float sizev;
bool round;
NODE_SOCKET_API(float3, axisu)
NODE_SOCKET_API(float, sizeu)
NODE_SOCKET_API(float3, axisv)
NODE_SOCKET_API(float, sizev)
NODE_SOCKET_API(bool, round)
Transform tfm;
NODE_SOCKET_API(Transform, tfm)
int map_resolution;
NODE_SOCKET_API(int, map_resolution)
float spot_angle;
float spot_smooth;
NODE_SOCKET_API(float, spot_angle)
NODE_SOCKET_API(float, spot_smooth)
bool cast_shadow;
bool use_mis;
bool use_diffuse;
bool use_glossy;
bool use_transmission;
bool use_scatter;
NODE_SOCKET_API(bool, cast_shadow)
NODE_SOCKET_API(bool, use_mis)
NODE_SOCKET_API(bool, use_diffuse)
NODE_SOCKET_API(bool, use_glossy)
NODE_SOCKET_API(bool, use_transmission)
NODE_SOCKET_API(bool, use_scatter)
bool is_portal;
bool is_enabled;
NODE_SOCKET_API(bool, is_portal)
NODE_SOCKET_API(bool, is_enabled)
Shader *shader;
int samples;
int max_bounces;
uint random_id;
NODE_SOCKET_API(Shader *, shader)
NODE_SOCKET_API(int, samples)
NODE_SOCKET_API(int, max_bounces)
NODE_SOCKET_API(uint, random_id)
void tag_update(Scene *scene);
/* Check whether the light has contribution the scene. */
bool has_contribution(Scene *scene);
friend class LightManager;
};
class LightManager {

@ -132,11 +132,58 @@ NODE_DEFINE(Mesh)
SOCKET_INT_ARRAY(shader, "Shader", array<int>());
SOCKET_BOOLEAN_ARRAY(smooth, "Smooth", array<bool>());
SOCKET_INT_ARRAY(triangle_patch, "Triangle Patch", array<int>());
SOCKET_POINT2_ARRAY(vert_patch_uv, "Patch UVs", array<float2>());
static NodeEnum subdivision_type_enum;
subdivision_type_enum.insert("none", SUBDIVISION_NONE);
subdivision_type_enum.insert("linear", SUBDIVISION_LINEAR);
subdivision_type_enum.insert("catmull_clark", SUBDIVISION_CATMULL_CLARK);
SOCKET_ENUM(subdivision_type, "Subdivision Type", subdivision_type_enum, SUBDIVISION_NONE);
SOCKET_INT_ARRAY(subd_creases_edge, "Subdivision Crease Edges", array<int>());
SOCKET_FLOAT_ARRAY(subd_creases_weight, "Subdivision Crease Weights", array<float>());
SOCKET_INT_ARRAY(subd_face_corners, "Subdivision Face Corners", array<int>());
SOCKET_INT_ARRAY(subd_start_corner, "Subdivision Face Start Corner", array<int>());
SOCKET_INT_ARRAY(subd_num_corners, "Subdivision Face Corner Count", array<int>());
SOCKET_INT_ARRAY(subd_shader, "Subdivision Face Shader", array<int>());
SOCKET_BOOLEAN_ARRAY(subd_smooth, "Subdivision Face Smooth", array<bool>());
SOCKET_INT_ARRAY(subd_ptex_offset, "Subdivision Face PTex Offset", array<int>());
SOCKET_INT(num_ngons, "NGons Number", 0);
/* Subdivisions parameters */
SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 0.0f)
SOCKET_INT(subd_max_level, "Subdivision Dicing Rate", 0);
SOCKET_TRANSFORM(subd_objecttoworld, "Subdivision Object Transform", transform_identity());
return type;
}
Mesh::Mesh(const NodeType *node_type_, Type geom_type_)
: Geometry(node_type_, geom_type_), subd_attributes(this, ATTR_PRIM_SUBD)
SubdParams *Mesh::get_subd_params()
{
if (subdivision_type == SubdivisionType::SUBDIVISION_NONE) {
return nullptr;
}
if (!subd_params) {
subd_params = new SubdParams(this);
}
subd_params->dicing_rate = subd_dicing_rate;
subd_params->max_level = subd_max_level;
subd_params->objecttoworld = subd_objecttoworld;
return subd_params;
}
bool Mesh::need_tesselation()
{
return get_subd_params() && (verts_is_modified() || subd_dicing_rate_is_modified() ||
subd_objecttoworld_is_modified() || subd_max_level_is_modified());
}
Mesh::Mesh(const NodeType *node_type, Type geom_type_)
: Geometry(node_type, geom_type_), subd_attributes(this, ATTR_PRIM_SUBD)
{
vert_offset = 0;
@ -145,6 +192,7 @@ Mesh::Mesh(const NodeType *node_type_, Type geom_type_)
corner_offset = 0;
num_subd_verts = 0;
num_subd_faces = 0;
num_ngons = 0;
@ -171,7 +219,7 @@ void Mesh::resize_mesh(int numverts, int numtris)
shader.resize(numtris);
smooth.resize(numtris);
if (subd_faces.size()) {
if (get_num_subd_faces()) {
triangle_patch.resize(numtris);
vert_patch_uv.resize(numverts);
}
@ -187,7 +235,7 @@ void Mesh::reserve_mesh(int numverts, int numtris)
shader.reserve(numtris);
smooth.reserve(numtris);
if (subd_faces.size()) {
if (get_num_subd_faces()) {
triangle_patch.reserve(numtris);
vert_patch_uv.reserve(numverts);
}
@ -197,22 +245,38 @@ void Mesh::reserve_mesh(int numverts, int numtris)
void Mesh::resize_subd_faces(int numfaces, int num_ngons_, int numcorners)
{
subd_faces.resize(numfaces);
subd_start_corner.resize(numfaces);
subd_num_corners.resize(numfaces);
subd_shader.resize(numfaces);
subd_smooth.resize(numfaces);
subd_ptex_offset.resize(numfaces);
subd_face_corners.resize(numcorners);
num_ngons = num_ngons_;
num_subd_faces = numfaces;
subd_attributes.resize();
}
void Mesh::reserve_subd_faces(int numfaces, int num_ngons_, int numcorners)
{
subd_faces.reserve(numfaces);
subd_start_corner.reserve(numfaces);
subd_num_corners.reserve(numfaces);
subd_shader.reserve(numfaces);
subd_smooth.reserve(numfaces);
subd_ptex_offset.reserve(numfaces);
subd_face_corners.reserve(numcorners);
num_ngons = num_ngons_;
num_subd_faces = numfaces;
subd_attributes.resize(true);
}
void Mesh::reserve_subd_creases(size_t num_creases)
{
subd_creases_edge.reserve(num_creases * 2);
subd_creases_weight.reserve(num_creases);
}
void Mesh::clear(bool preserve_shaders, bool preserve_voxel_data)
{
Geometry::clear(preserve_shaders);
@ -226,12 +290,18 @@ void Mesh::clear(bool preserve_shaders, bool preserve_voxel_data)
triangle_patch.clear();
vert_patch_uv.clear();
subd_faces.clear();
subd_start_corner.clear();
subd_num_corners.clear();
subd_shader.clear();
subd_smooth.clear();
subd_ptex_offset.clear();
subd_face_corners.clear();
num_subd_verts = 0;
num_subd_faces = 0;
subd_creases.clear();
subd_creases_edge.clear();
subd_creases_weight.clear();
subd_attributes.clear();
attributes.clear(preserve_voxel_data);
@ -239,6 +309,8 @@ void Mesh::clear(bool preserve_shaders, bool preserve_voxel_data)
vert_to_stitching_key_map.clear();
vert_stitching_map.clear();
subdivision_type = SubdivisionType::SUBDIVISION_NONE;
delete patch_table;
patch_table = NULL;
}
@ -251,18 +323,22 @@ void Mesh::clear(bool preserve_shaders)
void Mesh::add_vertex(float3 P)
{
verts.push_back_reserved(P);
tag_verts_modified();
if (subd_faces.size()) {
if (get_num_subd_faces()) {
vert_patch_uv.push_back_reserved(make_float2(0.0f, 0.0f));
tag_vert_patch_uv_modified();
}
}
void Mesh::add_vertex_slow(float3 P)
{
verts.push_back_slow(P);
tag_verts_modified();
if (subd_faces.size()) {
if (get_num_subd_faces()) {
vert_patch_uv.push_back_slow(make_float2(0.0f, 0.0f));
tag_vert_patch_uv_modified();
}
}
@ -274,8 +350,13 @@ void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
shader.push_back_reserved(shader_);
smooth.push_back_reserved(smooth_);
if (subd_faces.size()) {
tag_triangles_modified();
tag_shader_modified();
tag_smooth_modified();
if (get_num_subd_faces()) {
triangle_patch.push_back_reserved(-1);
tag_triangle_patch_modified();
}
}
@ -288,14 +369,47 @@ void Mesh::add_subd_face(int *corners, int num_corners, int shader_, bool smooth
}
int ptex_offset = 0;
if (subd_faces.size()) {
SubdFace &s = subd_faces[subd_faces.size() - 1];
// cannot use get_num_subd_faces here as it holds the total number of subd_faces, but we do not
// have the total amount of data yet
if (subd_shader.size()) {
SubdFace s = get_subd_face(subd_shader.size() - 1);
ptex_offset = s.ptex_offset + s.num_ptex_faces();
}
SubdFace face = {start_corner, num_corners, shader_, smooth_, ptex_offset};
subd_faces.push_back_reserved(face);
subd_start_corner.push_back_reserved(start_corner);
subd_num_corners.push_back_reserved(num_corners);
subd_shader.push_back_reserved(shader_);
subd_smooth.push_back_reserved(smooth_);
subd_ptex_offset.push_back_reserved(ptex_offset);
tag_subd_face_corners_modified();
tag_subd_start_corner_modified();
tag_subd_num_corners_modified();
tag_subd_shader_modified();
tag_subd_smooth_modified();
tag_subd_ptex_offset_modified();
}
Mesh::SubdFace Mesh::get_subd_face(size_t index) const
{
Mesh::SubdFace s;
s.shader = subd_shader[index];
s.num_corners = subd_num_corners[index];
s.smooth = subd_smooth[index];
s.ptex_offset = subd_ptex_offset[index];
s.start_corner = subd_start_corner[index];
return s;
}
void Mesh::add_crease(int v0, int v1, float weight)
{
subd_creases_edge.push_back_slow(v0);
subd_creases_edge.push_back_slow(v1);
subd_creases_weight.push_back_slow(weight);
tag_subd_creases_edge_modified();
tag_subd_creases_edge_modified();
tag_subd_creases_weight_modified();
}
void Mesh::copy_center_to_motion_step(const int motion_step)
@ -505,7 +619,7 @@ void Mesh::add_vertex_normals()
}
/* subd vertex normals */
if (!subd_attributes.find(ATTR_STD_VERTEX_NORMAL) && subd_faces.size()) {
if (!subd_attributes.find(ATTR_STD_VERTEX_NORMAL) && get_num_subd_faces()) {
/* get attributes */
Attribute *attr_vN = subd_attributes.add(ATTR_STD_VERTEX_NORMAL);
float3 *vN = attr_vN->data_float3();
@ -513,8 +627,8 @@ void Mesh::add_vertex_normals()
/* compute vertex normals */
memset(vN, 0, verts.size() * sizeof(float3));
for (size_t i = 0; i < subd_faces.size(); i++) {
SubdFace &face = subd_faces[i];
for (size_t i = 0; i < get_num_subd_faces(); i++) {
SubdFace face = get_subd_face(i);
float3 fN = face.normal(this);
for (size_t j = 0; j < face.num_corners; j++) {
@ -574,8 +688,9 @@ void Mesh::pack_shaders(Scene *scene, uint *tri_shader)
if (shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
last_shader = shader_ptr[i];
last_smooth = smooth[i];
Shader *shader = (last_shader < used_shaders.size()) ? used_shaders[last_shader] :
scene->default_surface;
Shader *shader = (last_shader < used_shaders.size()) ?
static_cast<Shader *>(used_shaders[last_shader]) :
scene->default_surface;
shader_id = scene->shader_manager->get_shader_id(shader, last_smooth);
}
@ -616,7 +731,7 @@ void Mesh::pack_verts(const vector<uint> &tri_prim_index,
{
size_t verts_size = verts.size();
if (verts_size && subd_faces.size()) {
if (verts_size && get_num_subd_faces()) {
float2 *vert_patch_uv_ptr = vert_patch_uv.data();
for (size_t i = 0; i < verts_size; i++) {
@ -633,17 +748,17 @@ void Mesh::pack_verts(const vector<uint> &tri_prim_index,
t.v[2] + vert_offset,
tri_prim_index[i + tri_offset]);
tri_patch[i] = (!subd_faces.size()) ? -1 : (triangle_patch[i] * 8 + patch_offset);
tri_patch[i] = (!get_num_subd_faces()) ? -1 : (triangle_patch[i] * 8 + patch_offset);
}
}
void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset)
{
size_t num_faces = subd_faces.size();
size_t num_faces = get_num_subd_faces();
int ngons = 0;
for (size_t f = 0; f < num_faces; f++) {
SubdFace face = subd_faces[f];
SubdFace face = get_subd_face(f);
if (face.is_quad()) {
int c[4];

@ -118,36 +118,57 @@ class Mesh : public Geometry {
float crease;
};
SubdEdgeCrease get_subd_crease(size_t i) const
{
SubdEdgeCrease s;
s.v[0] = subd_creases_edge[i * 2];
s.v[1] = subd_creases_edge[i * 2 + 1];
s.crease = subd_creases_weight[i];
return s;
}
bool need_tesselation();
enum SubdivisionType {
SUBDIVISION_NONE,
SUBDIVISION_LINEAR,
SUBDIVISION_CATMULL_CLARK,
};
SubdivisionType subdivision_type;
NODE_SOCKET_API(SubdivisionType, subdivision_type)
/* Mesh Data */
array<int> triangles;
array<float3> verts;
array<int> shader;
array<bool> smooth;
NODE_SOCKET_API_ARRAY(array<int>, triangles)
NODE_SOCKET_API_ARRAY(array<float3>, verts)
NODE_SOCKET_API_ARRAY(array<int>, shader)
NODE_SOCKET_API_ARRAY(array<bool>, smooth)
/* used for storing patch info for subd triangles, only allocated if there are patches */
array<int> triangle_patch; /* must be < 0 for non subd triangles */
array<float2> vert_patch_uv;
NODE_SOCKET_API_ARRAY(array<int>, triangle_patch) /* must be < 0 for non subd triangles */
NODE_SOCKET_API_ARRAY(array<float2>, vert_patch_uv)
array<SubdFace> subd_faces;
array<int> subd_face_corners;
int num_ngons;
/* SubdFaces */
NODE_SOCKET_API_ARRAY(array<int>, subd_start_corner)
NODE_SOCKET_API_ARRAY(array<int>, subd_num_corners)
NODE_SOCKET_API_ARRAY(array<int>, subd_shader)
NODE_SOCKET_API_ARRAY(array<bool>, subd_smooth)
NODE_SOCKET_API_ARRAY(array<int>, subd_ptex_offset)
array<SubdEdgeCrease> subd_creases;
NODE_SOCKET_API_ARRAY(array<int>, subd_face_corners)
NODE_SOCKET_API(int, num_ngons)
SubdParams *subd_params;
NODE_SOCKET_API_ARRAY(array<int>, subd_creases_edge)
NODE_SOCKET_API_ARRAY(array<float>, subd_creases_weight)
/* Subdivisions parameters */
NODE_SOCKET_API(float, subd_dicing_rate)
NODE_SOCKET_API(int, subd_max_level)
NODE_SOCKET_API(Transform, subd_objecttoworld)
AttributeSet subd_attributes;
private:
PackedPatchTable *patch_table;
/* BVH */
size_t vert_offset;
@ -157,13 +178,22 @@ class Mesh : public Geometry {
size_t corner_offset;
size_t num_subd_verts;
size_t num_subd_faces;
private:
unordered_map<int, int> vert_to_stitching_key_map; /* real vert index -> stitching index */
unordered_multimap<int, int>
vert_stitching_map; /* stitching index -> multiple real vert indices */
friend class BVH;
friend class BVHBuild;
friend class BVHEmbree;
friend class BVHSpatialSplit;
friend class DiagSplit;
friend class EdgeDice;
friend class GeometryManager;
friend class ObjectManager;
SubdParams *subd_params = nullptr;
public:
/* Functions */
@ -174,11 +204,13 @@ class Mesh : public Geometry {
void reserve_mesh(int numverts, int numfaces);
void resize_subd_faces(int numfaces, int num_ngons, int numcorners);
void reserve_subd_faces(int numfaces, int num_ngons, int numcorners);
void reserve_subd_creases(size_t num_creases);
void clear(bool preserve_shaders = false) override;
void add_vertex(float3 P);
void add_vertex_slow(float3 P);
void add_triangle(int v0, int v1, int v2, int shader, bool smooth);
void add_subd_face(int *corners, int num_corners, int shader_, bool smooth_);
void add_crease(int v0, int v1, float weight);
void copy_center_to_motion_step(const int motion_step);
@ -202,6 +234,25 @@ class Mesh : public Geometry {
void tessellate(DiagSplit *split);
SubdFace get_subd_face(size_t index) const;
SubdParams *get_subd_params();
size_t get_num_subd_faces() const
{
return num_subd_faces;
}
void set_num_subd_faces(size_t num_subd_faces_)
{
num_subd_faces = num_subd_faces_;
}
size_t get_num_subd_verts()
{
return num_subd_verts;
}
protected:
void clear(bool preserve_shaders, bool preserve_voxel_data);
};

@ -58,7 +58,7 @@ bool GeometryManager::displace(
size_t object_index = OBJECT_NONE;
for (size_t i = 0; i < scene->objects.size(); i++) {
if (scene->objects[i]->geometry == mesh) {
if (scene->objects[i]->get_geometry() == mesh) {
object_index = i;
break;
}
@ -76,10 +76,10 @@ bool GeometryManager::displace(
Mesh::Triangle t = mesh->get_triangle(i);
int shader_index = mesh->shader[i];
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] :
static_cast<Shader *>(mesh->used_shaders[shader_index]) :
scene->default_surface;
if (!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
continue;
}
@ -160,10 +160,10 @@ bool GeometryManager::displace(
Mesh::Triangle t = mesh->get_triangle(i);
int shader_index = mesh->shader[i];
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] :
static_cast<Shader *>(mesh->used_shaders[shader_index]) :
scene->default_surface;
if (!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
continue;
}
@ -227,8 +227,9 @@ bool GeometryManager::displace(
bool need_recompute_vertex_normals = false;
foreach (Shader *shader, mesh->used_shaders) {
if (shader->has_displacement && shader->displacement_method == DISPLACE_TRUE) {
foreach (Node *node, mesh->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->has_displacement && shader->get_displacement_method() == DISPLACE_TRUE) {
need_recompute_vertex_normals = true;
break;
}
@ -241,11 +242,11 @@ bool GeometryManager::displace(
for (size_t i = 0; i < num_triangles; i++) {
int shader_index = mesh->shader[i];
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] :
static_cast<Shader *>(mesh->used_shaders[shader_index]) :
scene->default_surface;
tri_has_true_disp[i] = shader->has_displacement &&
shader->displacement_method == DISPLACE_TRUE;
shader->get_displacement_method() == DISPLACE_TRUE;
}
/* static vertex normals */

@ -46,13 +46,11 @@ template<>
bool TopologyRefinerFactory<ccl::Mesh>::resizeComponentTopology(TopologyRefiner &refiner,
ccl::Mesh const &mesh)
{
setNumBaseVertices(refiner, mesh.verts.size());
setNumBaseFaces(refiner, mesh.subd_faces.size());
setNumBaseVertices(refiner, mesh.get_verts().size());
setNumBaseFaces(refiner, mesh.get_num_subd_faces());
const ccl::Mesh::SubdFace *face = mesh.subd_faces.data();
for (int i = 0; i < mesh.subd_faces.size(); i++, face++) {
setNumBaseFaceVertices(refiner, i, face->num_corners);
for (int i = 0; i < mesh.get_num_subd_faces(); i++) {
setNumBaseFaceVertices(refiner, i, mesh.get_subd_num_corners()[i]);
}
return true;
@ -62,14 +60,17 @@ template<>
bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTopology(TopologyRefiner &refiner,
ccl::Mesh const &mesh)
{
const ccl::Mesh::SubdFace *face = mesh.subd_faces.data();
const ccl::array<int> &subd_face_corners = mesh.get_subd_face_corners();
const ccl::array<int> &subd_start_corner = mesh.get_subd_start_corner();
const ccl::array<int> &subd_num_corners = mesh.get_subd_num_corners();
for (int i = 0; i < mesh.subd_faces.size(); i++, face++) {
for (int i = 0; i < mesh.get_num_subd_faces(); i++) {
IndexArray face_verts = getBaseFaceVertices(refiner, i);
int *corner = &mesh.subd_face_corners[face->start_corner];
int start_corner = subd_start_corner[i];
int *corner = &subd_face_corners[start_corner];
for (int j = 0; j < face->num_corners; j++, corner++) {
for (int j = 0; j < subd_num_corners[i]; j++, corner++) {
face_verts[j] = *corner;
}
}
@ -81,17 +82,18 @@ template<>
bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner &refiner,
ccl::Mesh const &mesh)
{
const ccl::Mesh::SubdEdgeCrease *crease = mesh.subd_creases.data();
size_t num_creases = mesh.get_subd_creases_weight().size();
for (int i = 0; i < mesh.subd_creases.size(); i++, crease++) {
Index edge = findBaseEdge(refiner, crease->v[0], crease->v[1]);
for (int i = 0; i < num_creases; i++) {
ccl::Mesh::SubdEdgeCrease crease = mesh.get_subd_crease(i);
Index edge = findBaseEdge(refiner, crease.v[0], crease.v[1]);
if (edge != INDEX_INVALID) {
setBaseEdgeSharpness(refiner, edge, crease->crease * 10.0f);
setBaseEdgeSharpness(refiner, edge, crease.crease * 10.0f);
}
}
for (int i = 0; i < mesh.verts.size(); i++) {
for (int i = 0; i < mesh.get_verts().size(); i++) {
ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i);
if (vert_edges.size() == 2) {
@ -203,8 +205,8 @@ class OsdData {
int num_local_points = patch_table->GetNumLocalPoints();
verts.resize(num_refiner_verts + num_local_points);
for (int i = 0; i < mesh->verts.size(); i++) {
verts[i].value = mesh->verts[i];
for (int i = 0; i < mesh->get_verts().size(); i++) {
verts[i].value = mesh->get_verts()[i];
}
OsdValue<float3> *src = verts.data();
@ -278,16 +280,17 @@ class OsdData {
{
/* loop over all edges to find longest in screen space */
const Far::TopologyLevel &level = refiner->GetLevel(0);
Transform objecttoworld = mesh->subd_params->objecttoworld;
Camera *cam = mesh->subd_params->camera;
const SubdParams *subd_params = mesh->get_subd_params();
Transform objecttoworld = subd_params->objecttoworld;
Camera *cam = subd_params->camera;
float longest_edge = 0.0f;
for (size_t i = 0; i < level.GetNumEdges(); i++) {
Far::ConstIndexArray verts = level.GetEdgeVertices(i);
float3 a = mesh->verts[verts[0]];
float3 b = mesh->verts[verts[1]];
float3 a = mesh->get_verts()[verts[0]];
float3 b = mesh->get_verts()[verts[1]];
float edge_len;
@ -305,7 +308,7 @@ class OsdData {
}
/* calculate isolation level */
int isolation = (int)(log2f(max(longest_edge / mesh->subd_params->dicing_rate, 1.0f)) + 1.0f);
int isolation = (int)(log2f(max(longest_edge / subd_params->dicing_rate, 1.0f)) + 1.0f);
return min(isolation, 10);
}
@ -368,12 +371,16 @@ struct OsdPatch : Patch {
void Mesh::tessellate(DiagSplit *split)
{
/* reset the number of subdivision vertices, in case the Mesh was not cleared
* between calls or data updates */
num_subd_verts = 0;
#ifdef WITH_OPENSUBDIV
OsdData osd_data;
bool need_packed_patch_table = false;
if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
if (subd_faces.size()) {
if (get_num_subd_faces()) {
osd_data.build_from_mesh(this);
}
}
@ -391,7 +398,7 @@ void Mesh::tessellate(DiagSplit *split)
}
}
int num_faces = subd_faces.size();
int num_faces = get_num_subd_faces();
Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL);
float3 *vN = (attr_vN) ? attr_vN->data_float3() : NULL;
@ -399,7 +406,7 @@ void Mesh::tessellate(DiagSplit *split)
/* count patches */
int num_patches = 0;
for (int f = 0; f < num_faces; f++) {
SubdFace &face = subd_faces[f];
SubdFace face = get_subd_face(f);
if (face.is_quad()) {
num_patches++;
@ -416,7 +423,7 @@ void Mesh::tessellate(DiagSplit *split)
OsdPatch *patch = osd_patches.data();
for (int f = 0; f < num_faces; f++) {
SubdFace &face = subd_faces[f];
SubdFace face = get_subd_face(f);
if (face.is_quad()) {
patch->patch_index = face.ptex_offset;
@ -444,7 +451,7 @@ void Mesh::tessellate(DiagSplit *split)
LinearQuadPatch *patch = linear_patches.data();
for (int f = 0; f < num_faces; f++) {
SubdFace &face = subd_faces[f];
SubdFace face = get_subd_face(f);
if (face.is_quad()) {
float3 *hull = patch->hull;
@ -542,7 +549,7 @@ void Mesh::tessellate(DiagSplit *split)
/* keep subdivision for corner attributes disabled for now */
attr.flags &= ~ATTR_SUBDIVIDED;
}
else if (subd_faces.size()) {
else if (get_num_subd_faces()) {
osd_data.subdivide_attribute(attr);
need_packed_patch_table = true;
@ -558,7 +565,7 @@ void Mesh::tessellate(DiagSplit *split)
switch (attr.element) {
case ATTR_ELEMENT_VERTEX: {
for (int f = 0; f < num_faces; f++) {
SubdFace &face = subd_faces[f];
SubdFace face = get_subd_face(f);
if (!face.is_quad()) {
char *center = data + (verts.size() - num_subd_verts + ngons) * stride;
@ -581,7 +588,7 @@ void Mesh::tessellate(DiagSplit *split)
} break;
case ATTR_ELEMENT_CORNER: {
for (int f = 0; f < num_faces; f++) {
SubdFace &face = subd_faces[f];
SubdFace face = get_subd_face(f);
if (!face.is_quad()) {
char *center = data + (subd_face_corners.size() + ngons) * stride;
@ -600,7 +607,7 @@ void Mesh::tessellate(DiagSplit *split)
} break;
case ATTR_ELEMENT_CORNER_BYTE: {
for (int f = 0; f < num_faces; f++) {
SubdFace &face = subd_faces[f];
SubdFace face = get_subd_face(f);
if (!face.is_quad()) {
uchar *center = (uchar *)data + (subd_face_corners.size() + ngons) * stride;

@ -247,6 +247,9 @@ NODE_DEFINE(ImageTextureNode)
SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f);
SOCKET_INT_ARRAY(tiles, "Tiles", array<int>());
SOCKET_BOOLEAN(animated, "Animated", false);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV);
SOCKET_OUT_COLOR(color, "Color");
@ -259,7 +262,7 @@ ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(node_type)
{
colorspace = u_colorspace_raw;
animated = false;
tiles.push_back(1001);
tiles.push_back_slow(1001);
}
ShaderNode *ImageTextureNode::clone(ShaderGraph *graph) const
@ -286,7 +289,7 @@ void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph)
* 1001 tile, so there's no point in loading any others. */
if (projection == NODE_IMAGE_PROJ_BOX) {
tiles.clear();
tiles.push_back(1001);
tiles.push_back_slow(1001);
return;
}
@ -308,7 +311,7 @@ void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph)
ShaderNode *node = vector_in->link->parent;
if (node->type == UVMapNode::node_type) {
UVMapNode *uvmap = (UVMapNode *)node;
attribute = uvmap->attribute;
attribute = uvmap->get_attribute();
}
else if (node->type == TextureCoordinateNode::node_type) {
if (vector_in->link != node->output("UV")) {
@ -325,20 +328,21 @@ void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph)
* be to have a cache in each mesh that is indexed by attribute.
* Additionally, building a graph-to-meshes list once could help. */
foreach (Geometry *geom, scene->geometry) {
foreach (Shader *shader, geom->used_shaders) {
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->graph == graph) {
geom->get_uv_tiles(attribute, used_tiles);
}
}
}
ccl::vector<int> new_tiles;
array<int> new_tiles;
foreach (int tile, tiles) {
if (used_tiles.count(tile)) {
new_tiles.push_back(tile);
new_tiles.push_back_slow(tile);
}
}
tiles.swap(new_tiles);
tiles.steal_data(new_tiles);
}
void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@ -511,6 +515,8 @@ NODE_DEFINE(EnvironmentTextureNode)
projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL);
SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR);
SOCKET_BOOLEAN(animated, "Animated", false);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
SOCKET_OUT_COLOR(color, "Color");
@ -790,7 +796,7 @@ NODE_DEFINE(SkyTextureNode)
type_enum.insert("preetham", NODE_SKY_PREETHAM);
type_enum.insert("hosek_wilkie", NODE_SKY_HOSEK);
type_enum.insert("nishita_improved", NODE_SKY_NISHITA);
SOCKET_ENUM(type, "Type", type_enum, NODE_SKY_NISHITA);
SOCKET_ENUM(sky_type, "Type", type_enum, NODE_SKY_NISHITA);
SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f));
SOCKET_FLOAT(turbidity, "Turbidity", 2.2f);
@ -823,11 +829,11 @@ void SkyTextureNode::compile(SVMCompiler &compiler)
ShaderOutput *color_out = output("Color");
SunSky sunsky;
if (type == NODE_SKY_PREETHAM)
if (sky_type == NODE_SKY_PREETHAM)
sky_texture_precompute_preetham(&sunsky, sun_direction, turbidity);
else if (type == NODE_SKY_HOSEK)
else if (sky_type == NODE_SKY_HOSEK)
sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
else if (type == NODE_SKY_NISHITA) {
else if (sky_type == NODE_SKY_NISHITA) {
/* Clamp altitude to reasonable values.
* Below 1m causes numerical issues and above 60km is space. */
float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
@ -860,9 +866,9 @@ void SkyTextureNode::compile(SVMCompiler &compiler)
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.stack_assign(color_out);
compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), type);
compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_type);
/* nishita doesn't need this data */
if (type != NODE_SKY_NISHITA) {
if (sky_type != NODE_SKY_NISHITA) {
compiler.add_node(__float_as_uint(sunsky.phi),
__float_as_uint(sunsky.theta),
__float_as_uint(sunsky.radiance_x),
@ -919,11 +925,11 @@ void SkyTextureNode::compile(OSLCompiler &compiler)
tex_mapping.compile(compiler);
SunSky sunsky;
if (type == NODE_SKY_PREETHAM)
if (sky_type == NODE_SKY_PREETHAM)
sky_texture_precompute_preetham(&sunsky, sun_direction, turbidity);
else if (type == NODE_SKY_HOSEK)
else if (sky_type == NODE_SKY_HOSEK)
sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
else if (type == NODE_SKY_NISHITA) {
else if (sky_type == NODE_SKY_NISHITA) {
/* Clamp altitude to reasonable values.
* Below 1m causes numerical issues and above 60km is space. */
float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
@ -963,7 +969,7 @@ void SkyTextureNode::compile(OSLCompiler &compiler)
compiler.parameter_array("config_z", sunsky.config_z, 9);
compiler.parameter_array("nishita_data", sunsky.nishita_data, 10);
/* nishita texture */
if (type == NODE_SKY_NISHITA) {
if (sky_type == NODE_SKY_NISHITA) {
compiler.parameter_texture("filename", handle.svm_slot());
}
compiler.add(this, "node_sky_texture");
@ -985,7 +991,7 @@ NODE_DEFINE(GradientTextureNode)
type_enum.insert("radial", NODE_BLEND_RADIAL);
type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE);
type_enum.insert("spherical", NODE_BLEND_SPHERICAL);
SOCKET_ENUM(type, "Type", type_enum, NODE_BLEND_LINEAR);
SOCKET_ENUM(gradient_type, "Type", type_enum, NODE_BLEND_LINEAR);
SOCKET_IN_POINT(
vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
@ -1009,7 +1015,7 @@ void GradientTextureNode::compile(SVMCompiler &compiler)
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_GRADIENT,
compiler.encode_uchar4(type,
compiler.encode_uchar4(gradient_type,
vector_offset,
compiler.stack_assign_if_linked(fac_out),
compiler.stack_assign_if_linked(color_out)));
@ -1369,7 +1375,7 @@ NODE_DEFINE(MusgraveTextureNode)
type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL);
type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL);
type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM);
SOCKET_ENUM(musgrave_type, "Type", type_enum, NODE_MUSGRAVE_FBM);
SOCKET_IN_POINT(
vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
@ -1414,7 +1420,7 @@ void MusgraveTextureNode::compile(SVMCompiler &compiler)
compiler.add_node(
NODE_TEX_MUSGRAVE,
compiler.encode_uchar4(type, dimensions, vector_stack_offset, w_stack_offset),
compiler.encode_uchar4(musgrave_type, dimensions, vector_stack_offset, w_stack_offset),
compiler.encode_uchar4(scale_stack_offset,
detail_stack_offset,
dimension_stack_offset,
@ -1447,7 +1453,7 @@ NODE_DEFINE(WaveTextureNode)
static NodeEnum type_enum;
type_enum.insert("bands", NODE_WAVE_BANDS);
type_enum.insert("rings", NODE_WAVE_RINGS);
SOCKET_ENUM(type, "Type", type_enum, NODE_WAVE_BANDS);
SOCKET_ENUM(wave_type, "Type", type_enum, NODE_WAVE_BANDS);
static NodeEnum bands_direction_enum;
bands_direction_enum.insert("x", NODE_WAVE_BANDS_DIRECTION_X);
@ -1504,7 +1510,7 @@ void WaveTextureNode::compile(SVMCompiler &compiler)
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_WAVE,
compiler.encode_uchar4(type, bands_direction, rings_direction, profile),
compiler.encode_uchar4(wave_type, bands_direction, rings_direction, profile),
compiler.encode_uchar4(vector_offset,
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(distortion_in)),
@ -1926,7 +1932,7 @@ NODE_DEFINE(MappingNode)
type_enum.insert("texture", NODE_MAPPING_TYPE_TEXTURE);
type_enum.insert("vector", NODE_MAPPING_TYPE_VECTOR);
type_enum.insert("normal", NODE_MAPPING_TYPE_NORMAL);
SOCKET_ENUM(type, "Type", type_enum, NODE_MAPPING_TYPE_POINT);
SOCKET_ENUM(mapping_type, "Type", type_enum, NODE_MAPPING_TYPE_POINT);
SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_POINT(location, "Location", make_float3(0.0f, 0.0f, 0.0f));
@ -1945,11 +1951,11 @@ MappingNode::MappingNode() : ShaderNode(node_type)
void MappingNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
float3 result = svm_mapping((NodeMappingType)mapping_type, vector, location, rotation, scale);
folder.make_constant(result);
}
else {
folder.fold_mapping((NodeMappingType)type);
folder.fold_mapping((NodeMappingType)mapping_type);
}
}
@ -1969,7 +1975,7 @@ void MappingNode::compile(SVMCompiler &compiler)
compiler.add_node(
NODE_MAPPING,
type,
mapping_type,
compiler.encode_uchar4(
vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset),
result_stack_offset);
@ -2385,7 +2391,7 @@ void GlossyBsdfNode::simplify_settings(Scene *scene)
}
Integrator *integrator = scene->integrator;
ShaderInput *roughness_input = input("Roughness");
if (integrator->filter_glossy == 0.0f) {
if (integrator->get_filter_glossy() == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
* Note: Keep the epsilon in sync with kernel!
*/
@ -2478,7 +2484,7 @@ void GlassBsdfNode::simplify_settings(Scene *scene)
}
Integrator *integrator = scene->integrator;
ShaderInput *roughness_input = input("Roughness");
if (integrator->filter_glossy == 0.0f) {
if (integrator->get_filter_glossy() == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
* Note: Keep the epsilon in sync with kernel!
*/
@ -2571,7 +2577,7 @@ void RefractionBsdfNode::simplify_settings(Scene *scene)
}
Integrator *integrator = scene->integrator;
ShaderInput *roughness_input = input("Roughness");
if (integrator->filter_glossy == 0.0f) {
if (integrator->get_filter_glossy() == 0.0f) {
/* Fallback to Sharp closure for Roughness close to 0.
* Note: Keep the epsilon in sync with kernel!
*/
@ -4481,7 +4487,7 @@ void VolumeInfoNode::expand(ShaderGraph *graph)
ShaderOutput *color_out = output("Color");
if (!color_out->links.empty()) {
AttributeNode *attr = graph->create_node<AttributeNode>();
attr->attribute = "color";
attr->set_attribute(ustring("color"));
graph->add(attr);
graph->relink(color_out, attr->output("Color"));
}
@ -4489,7 +4495,7 @@ void VolumeInfoNode::expand(ShaderGraph *graph)
ShaderOutput *density_out = output("Density");
if (!density_out->links.empty()) {
AttributeNode *attr = graph->create_node<AttributeNode>();
attr->attribute = "density";
attr->set_attribute(ustring("density"));
graph->add(attr);
graph->relink(density_out, attr->output("Fac"));
}
@ -4497,7 +4503,7 @@ void VolumeInfoNode::expand(ShaderGraph *graph)
ShaderOutput *flame_out = output("Flame");
if (!flame_out->links.empty()) {
AttributeNode *attr = graph->create_node<AttributeNode>();
attr->attribute = "flame";
attr->set_attribute(ustring("flame"));
graph->add(attr);
graph->relink(flame_out, attr->output("Fac"));
}
@ -4505,7 +4511,7 @@ void VolumeInfoNode::expand(ShaderGraph *graph)
ShaderOutput *temperature_out = output("Temperature");
if (!temperature_out->links.empty()) {
AttributeNode *attr = graph->create_node<AttributeNode>();
attr->attribute = "temperature";
attr->set_attribute(ustring("temperature"));
graph->add(attr);
graph->relink(temperature_out, attr->output("Fac"));
}
@ -4882,7 +4888,7 @@ NODE_DEFINE(MixNode)
type_enum.insert("color", NODE_MIX_COLOR);
type_enum.insert("soft_light", NODE_MIX_SOFT);
type_enum.insert("linear_light", NODE_MIX_LINEAR);
SOCKET_ENUM(type, "Type", type_enum, NODE_MIX_BLEND);
SOCKET_ENUM(mix_type, "Type", type_enum, NODE_MIX_BLEND);
SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
@ -4910,7 +4916,7 @@ void MixNode::compile(SVMCompiler &compiler)
compiler.stack_assign(fac_in),
compiler.stack_assign(color1_in),
compiler.stack_assign(color2_in));
compiler.add_node(NODE_MIX, type, compiler.stack_assign(color_out));
compiler.add_node(NODE_MIX, mix_type, compiler.stack_assign(color_out));
if (use_clamp) {
compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out));
@ -4928,10 +4934,10 @@ void MixNode::compile(OSLCompiler &compiler)
void MixNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp);
folder.make_constant_clamp(svm_mix(mix_type, fac, color1, color2), use_clamp);
}
else {
folder.fold_mix(type, use_clamp);
folder.fold_mix(mix_type, use_clamp);
}
}
@ -5761,7 +5767,7 @@ NODE_DEFINE(MapRangeNode)
type_enum.insert("stepped", NODE_MAP_RANGE_STEPPED);
type_enum.insert("smoothstep", NODE_MAP_RANGE_SMOOTHSTEP);
type_enum.insert("smootherstep", NODE_MAP_RANGE_SMOOTHERSTEP);
SOCKET_ENUM(type, "Type", type_enum, NODE_MAP_RANGE_LINEAR);
SOCKET_ENUM(range_type, "Type", type_enum, NODE_MAP_RANGE_LINEAR);
SOCKET_IN_FLOAT(value, "Value", 1.0f);
SOCKET_IN_FLOAT(from_min, "From Min", 0.0f);
@ -5786,7 +5792,7 @@ void MapRangeNode::expand(ShaderGraph *graph)
ShaderOutput *result_out = output("Result");
if (!result_out->links.empty()) {
ClampNode *clamp_node = graph->create_node<ClampNode>();
clamp_node->type = NODE_CLAMP_RANGE;
clamp_node->set_clamp_type(NODE_CLAMP_RANGE);
graph->add(clamp_node);
graph->relink(result_out, clamp_node->output("Result"));
graph->connect(result_out, clamp_node->input("Value"));
@ -5794,13 +5800,13 @@ void MapRangeNode::expand(ShaderGraph *graph)
graph->connect(input("To Min")->link, clamp_node->input("Min"));
}
else {
clamp_node->min = to_min;
clamp_node->set_min(to_min);
}
if (input("To Max")->link) {
graph->connect(input("To Max")->link, clamp_node->input("Max"));
}
else {
clamp_node->max = to_max;
clamp_node->set_max(to_max);
}
}
}
@ -5829,7 +5835,7 @@ void MapRangeNode::compile(SVMCompiler &compiler)
value_stack_offset,
compiler.encode_uchar4(
from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset),
compiler.encode_uchar4(type, steps_stack_offset, result_stack_offset));
compiler.encode_uchar4(range_type, steps_stack_offset, result_stack_offset));
compiler.add_node(__float_as_int(from_min),
__float_as_int(from_max),
@ -5853,7 +5859,7 @@ NODE_DEFINE(ClampNode)
static NodeEnum type_enum;
type_enum.insert("minmax", NODE_CLAMP_MINMAX);
type_enum.insert("range", NODE_CLAMP_RANGE);
SOCKET_ENUM(type, "Type", type_enum, NODE_CLAMP_MINMAX);
SOCKET_ENUM(clamp_type, "Type", type_enum, NODE_CLAMP_MINMAX);
SOCKET_IN_FLOAT(value, "Value", 1.0f);
SOCKET_IN_FLOAT(min, "Min", 0.0f);
@ -5871,7 +5877,7 @@ ClampNode::ClampNode() : ShaderNode(node_type)
void ClampNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
if (type == NODE_CLAMP_RANGE && (min > max)) {
if (clamp_type == NODE_CLAMP_RANGE && (min > max)) {
folder.make_constant(clamp(value, max, min));
}
else {
@ -5894,7 +5900,7 @@ void ClampNode::compile(SVMCompiler &compiler)
compiler.add_node(NODE_CLAMP,
value_stack_offset,
compiler.encode_uchar4(min_stack_offset, max_stack_offset, type),
compiler.encode_uchar4(min_stack_offset, max_stack_offset, clamp_type),
result_stack_offset);
compiler.add_node(__float_as_int(min), __float_as_int(max));
}
@ -6004,7 +6010,7 @@ NODE_DEFINE(MathNode)
type_enum.insert("smoothmin", NODE_MATH_SMOOTH_MIN);
type_enum.insert("smoothmax", NODE_MATH_SMOOTH_MAX);
type_enum.insert("compare", NODE_MATH_COMPARE);
SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD);
SOCKET_ENUM(math_type, "Type", type_enum, NODE_MATH_ADD);
SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
@ -6027,9 +6033,9 @@ void MathNode::expand(ShaderGraph *graph)
ShaderOutput *result_out = output("Value");
if (!result_out->links.empty()) {
ClampNode *clamp_node = graph->create_node<ClampNode>();
clamp_node->type = NODE_CLAMP_MINMAX;
clamp_node->min = 0.0f;
clamp_node->max = 1.0f;
clamp_node->set_clamp_type(NODE_CLAMP_MINMAX);
clamp_node->set_min(0.0f);
clamp_node->set_max(1.0f);
graph->add(clamp_node);
graph->relink(result_out, clamp_node->output("Result"));
graph->connect(result_out, clamp_node->input("Value"));
@ -6040,10 +6046,10 @@ void MathNode::expand(ShaderGraph *graph)
void MathNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
folder.make_constant(svm_math(type, value1, value2, value3));
folder.make_constant(svm_math(math_type, value1, value2, value3));
}
else {
folder.fold_math(type);
folder.fold_math(math_type);
}
}
@ -6061,7 +6067,7 @@ void MathNode::compile(SVMCompiler &compiler)
compiler.add_node(
NODE_MATH,
type,
math_type,
compiler.encode_uchar4(value1_stack_offset, value2_stack_offset, value3_stack_offset),
value_stack_offset);
}
@ -6107,7 +6113,7 @@ NODE_DEFINE(VectorMathNode)
type_enum.insert("sine", NODE_VECTOR_MATH_SINE);
type_enum.insert("cosine", NODE_VECTOR_MATH_COSINE);
type_enum.insert("tangent", NODE_VECTOR_MATH_TANGENT);
SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
SOCKET_ENUM(math_type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f));
@ -6130,7 +6136,7 @@ void VectorMathNode::constant_fold(const ConstantFolder &folder)
float3 vector = make_float3(0.0f, 0.0f, 0.0f);
if (folder.all_inputs_constant()) {
svm_vector_math(&value, &vector, type, vector1, vector2, vector3, scale);
svm_vector_math(&value, &vector, math_type, vector1, vector2, vector3, scale);
if (folder.output == output("Value")) {
folder.make_constant(value);
}
@ -6139,7 +6145,7 @@ void VectorMathNode::constant_fold(const ConstantFolder &folder)
}
}
else {
folder.fold_vector_math(type);
folder.fold_vector_math(math_type);
}
}
@ -6158,12 +6164,12 @@ void VectorMathNode::compile(SVMCompiler &compiler)
int vector_stack_offset = compiler.stack_assign_if_linked(vector_out);
/* 3 Vector Operators */
if (type == NODE_VECTOR_MATH_WRAP) {
if (math_type == NODE_VECTOR_MATH_WRAP) {
ShaderInput *vector3_in = input("Vector3");
int vector3_stack_offset = compiler.stack_assign(vector3_in);
compiler.add_node(
NODE_VECTOR_MATH,
type,
math_type,
compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, scale_stack_offset),
compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
compiler.add_node(vector3_stack_offset);
@ -6171,7 +6177,7 @@ void VectorMathNode::compile(SVMCompiler &compiler)
else {
compiler.add_node(
NODE_VECTOR_MATH,
type,
math_type,
compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, scale_stack_offset),
compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
}
@ -6195,7 +6201,7 @@ NODE_DEFINE(VectorRotateNode)
type_enum.insert("y_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_Y);
type_enum.insert("z_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_Z);
type_enum.insert("euler_xyz", NODE_VECTOR_ROTATE_TYPE_EULER_XYZ);
SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_ROTATE_TYPE_AXIS);
SOCKET_ENUM(rotate_type, "Type", type_enum, NODE_VECTOR_ROTATE_TYPE_AXIS);
SOCKET_BOOLEAN(invert, "Invert", false);
@ -6222,14 +6228,15 @@ void VectorRotateNode::compile(SVMCompiler &compiler)
ShaderInput *angle_in = input("Angle");
ShaderOutput *vector_out = output("Vector");
compiler.add_node(
NODE_VECTOR_ROTATE,
compiler.encode_uchar4(
type, compiler.stack_assign(vector_in), compiler.stack_assign(rotation_in), invert),
compiler.encode_uchar4(compiler.stack_assign(center_in),
compiler.stack_assign(axis_in),
compiler.stack_assign(angle_in)),
compiler.stack_assign(vector_out));
compiler.add_node(NODE_VECTOR_ROTATE,
compiler.encode_uchar4(rotate_type,
compiler.stack_assign(vector_in),
compiler.stack_assign(rotation_in),
invert),
compiler.encode_uchar4(compiler.stack_assign(center_in),
compiler.stack_assign(axis_in),
compiler.stack_assign(angle_in)),
compiler.stack_assign(vector_out));
}
void VectorRotateNode::compile(OSLCompiler &compiler)
@ -6249,7 +6256,7 @@ NODE_DEFINE(VectorTransformNode)
type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
SOCKET_ENUM(transform_type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
static NodeEnum space_enum;
space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
@ -6275,7 +6282,7 @@ void VectorTransformNode::compile(SVMCompiler &compiler)
compiler.add_node(
NODE_VECTOR_TRANSFORM,
compiler.encode_uchar4(type, convert_from, convert_to),
compiler.encode_uchar4(transform_type, convert_from, convert_to),
compiler.encode_uchar4(compiler.stack_assign(vector_in), compiler.stack_assign(vector_out)));
}

File diff suppressed because it is too large Load Diff

@ -104,9 +104,13 @@ NODE_DEFINE(Object)
SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f));
SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
SOCKET_FLOAT(shadow_terminator_offset, "Terminator Offset", 0.0f);
SOCKET_STRING(asset_name, "Asset Name", ustring());
SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false);
SOCKET_NODE(particle_system, "Particle System", &ParticleSystem::node_type);
SOCKET_INT(particle_index, "Particle Index", 0);
return type;
}
@ -213,10 +217,11 @@ void Object::tag_update(Scene *scene)
{
if (geometry) {
if (geometry->transform_applied)
geometry->need_update = true;
geometry->tag_modified();
foreach (Shader *shader, geometry->used_shaders) {
if (shader->use_mis && shader->has_surface_emission)
foreach (Node *node, geometry->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->get_use_mis() && shader->has_surface_emission)
scene->light_manager->need_update = true;
}
}
@ -273,7 +278,7 @@ uint Object::visibility_for_tracing() const
float Object::compute_volume_step_size() const
{
if (geometry->type != Geometry::MESH && geometry->type != Geometry::VOLUME) {
if (geometry->geometry_type != Geometry::MESH && geometry->geometry_type != Geometry::VOLUME) {
return FLT_MAX;
}
@ -286,11 +291,12 @@ float Object::compute_volume_step_size() const
/* Compute step rate from shaders. */
float step_rate = FLT_MAX;
foreach (Shader *shader, mesh->used_shaders) {
foreach (Node *node, mesh->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (shader->has_volume) {
if ((shader->heterogeneous_volume && shader->has_volume_spatial_varying) ||
if ((shader->get_heterogeneous_volume() && shader->has_volume_spatial_varying) ||
(shader->has_volume_attribute_dependency)) {
step_rate = fminf(shader->volume_step_rate, step_rate);
step_rate = fminf(shader->get_volume_step_rate(), step_rate);
}
}
}
@ -302,7 +308,7 @@ float Object::compute_volume_step_size() const
/* Compute step size from voxel grids. */
float step_size = FLT_MAX;
if (geometry->type == Geometry::VOLUME) {
if (geometry->geometry_type == Geometry::VOLUME) {
Volume *volume = static_cast<Volume *>(geometry);
foreach (Attribute &attr, volume->attributes.attributes) {
@ -314,7 +320,7 @@ float Object::compute_volume_step_size() const
}
/* User specified step size. */
float voxel_step_size = volume->step_size;
float voxel_step_size = volume->get_step_size();
if (voxel_step_size == 0.0f) {
/* Auto detect step size. */
@ -328,7 +334,7 @@ float Object::compute_volume_step_size() const
}
voxel_step_size = min3(fabs(transform_direction(&voxel_tfm, size)));
}
else if (volume->object_space) {
else if (volume->get_object_space()) {
/* User specified step size in object space. */
float3 size = make_float3(voxel_step_size, voxel_step_size, voxel_step_size);
voxel_step_size = min3(fabs(transform_direction(&tfm, size)));
@ -372,14 +378,15 @@ static float object_surface_area(UpdateObjectTransformState *state,
const Transform &tfm,
Geometry *geom)
{
if (geom->type != Geometry::MESH && geom->type != Geometry::VOLUME) {
if (geom->geometry_type != Geometry::MESH && geom->geometry_type != Geometry::VOLUME) {
return 0.0f;
}
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->has_volume || geom->type == Geometry::VOLUME) {
if (mesh->has_volume || geom->geometry_type == Geometry::VOLUME) {
/* Volume density automatically adjust to object scale. */
if (geom->type == Geometry::VOLUME && static_cast<Volume *>(geom)->object_space) {
if (geom->geometry_type == Geometry::VOLUME &&
static_cast<Volume *>(geom)->get_object_space()) {
const float3 unit = normalize(make_float3(1.0f, 1.0f, 1.0f));
return 1.0f / len(transform_direction(&tfm, unit));
}
@ -411,9 +418,9 @@ static float object_surface_area(UpdateObjectTransformState *state,
size_t num_triangles = mesh->num_triangles();
for (size_t j = 0; j < num_triangles; j++) {
Mesh::Triangle t = mesh->get_triangle(j);
float3 p1 = mesh->verts[t.v[0]];
float3 p2 = mesh->verts[t.v[1]];
float3 p3 = mesh->verts[t.v[2]];
float3 p1 = mesh->get_verts()[t.v[0]];
float3 p2 = mesh->get_verts()[t.v[1]];
float3 p3 = mesh->get_verts()[t.v[2]];
surface_area += triangle_area(p1, p2, p3);
}
@ -432,9 +439,9 @@ static float object_surface_area(UpdateObjectTransformState *state,
size_t num_triangles = mesh->num_triangles();
for (size_t j = 0; j < num_triangles; j++) {
Mesh::Triangle t = mesh->get_triangle(j);
float3 p1 = transform_point(&tfm, mesh->verts[t.v[0]]);
float3 p2 = transform_point(&tfm, mesh->verts[t.v[1]]);
float3 p3 = transform_point(&tfm, mesh->verts[t.v[2]]);
float3 p1 = transform_point(&tfm, mesh->get_verts()[t.v[0]]);
float3 p2 = transform_point(&tfm, mesh->get_verts()[t.v[1]]);
float3 p3 = transform_point(&tfm, mesh->get_verts()[t.v[2]]);
surface_area += triangle_area(p1, p2, p3);
}
@ -473,11 +480,11 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
kobject.particle_index = particle_index;
kobject.motion_offset = 0;
if (geom->use_motion_blur) {
if (geom->get_use_motion_blur()) {
state->have_motion = true;
}
if (geom->type == Geometry::MESH) {
if (geom->geometry_type == Geometry::MESH) {
/* TODO: why only mesh? */
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
@ -528,14 +535,16 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
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 = (geom->type == Geometry::HAIR) ? static_cast<Hair *>(geom)->curve_keys.size() :
0;
kobject.numkeys = (geom->geometry_type == Geometry::HAIR) ?
static_cast<Hair *>(geom)->get_curve_keys().size() :
0;
kobject.dupli_uv[0] = ob->dupli_uv[0];
kobject.dupli_uv[1] = ob->dupli_uv[1];
int totalsteps = geom->motion_steps;
int totalsteps = geom->get_motion_steps();
kobject.numsteps = (totalsteps - 1) / 2;
kobject.numverts = (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) ?
static_cast<Mesh *>(geom)->verts.size() :
kobject.numverts = (geom->geometry_type == Geometry::MESH ||
geom->geometry_type == Geometry::VOLUME) ?
static_cast<Mesh *>(geom)->get_verts().size() :
0;
kobject.patch_map_offset = 0;
kobject.attribute_map_offset = 0;
@ -553,7 +562,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
state->object_volume_step[ob->index] = FLT_MAX;
/* Have curves. */
if (geom->type == Geometry::HAIR) {
if (geom->geometry_type == Geometry::HAIR) {
state->have_curves = true;
}
}
@ -688,6 +697,10 @@ void ObjectManager::device_update(Device *device,
progress.set_status("Updating Objects", "Applying Static Transformations");
apply_static_transforms(dscene, scene, progress);
}
foreach (Object *object, scene->objects) {
object->clear_modified();
}
}
void ObjectManager::device_update_flags(
@ -787,7 +800,7 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc
foreach (Object *object, scene->objects) {
Geometry *geom = object->geometry;
if (geom->type == Geometry::MESH) {
if (geom->geometry_type == Geometry::MESH) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->patch_table) {
uint patch_map_offset = 2 * (mesh->patch_table_offset + mesh->patch_table->total_size() -
@ -865,11 +878,11 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P
bool apply = (geometry_users[geom] == 1) && !geom->has_surface_bssrdf &&
!geom->has_true_displacement();
if (geom->type == Geometry::MESH || geom->type == Geometry::VOLUME) {
if (geom->geometry_type == Geometry::MESH) {
Mesh *mesh = static_cast<Mesh *>(geom);
apply = apply && mesh->subdivision_type == Mesh::SUBDIVISION_NONE;
apply = apply && mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE;
}
else if (geom->type == Geometry::HAIR) {
else if (geom->geometry_type == Geometry::HAIR) {
/* Can't apply non-uniform scale to curves, this can't be represented by
* control points and radius alone. */
float scale;

@ -18,6 +18,11 @@
#define __OBJECT_H__
#include "graph/node.h"
/* included as Object::set_particle_system defined through NODE_SOCKET_API does
* not select the right Node::set overload as it does not know that ParticleSystem
* is a Node */
#include "render/particles.h"
#include "render/scene.h"
#include "util/util_array.h"
@ -46,26 +51,26 @@ class Object : public Node {
public:
NODE_DECLARE
Geometry *geometry;
Transform tfm;
NODE_SOCKET_API(Geometry *, geometry)
NODE_SOCKET_API(Transform, tfm)
BoundBox bounds;
uint random_id;
int pass_id;
float3 color;
ustring asset_name;
NODE_SOCKET_API(uint, random_id)
NODE_SOCKET_API(int, pass_id)
NODE_SOCKET_API(float3, color)
NODE_SOCKET_API(ustring, asset_name)
vector<ParamValue> attributes;
uint visibility;
array<Transform> motion;
bool hide_on_missing_motion;
bool use_holdout;
bool is_shadow_catcher;
float shadow_terminator_offset;
NODE_SOCKET_API(uint, visibility)
NODE_SOCKET_API_ARRAY(array<Transform>, motion)
NODE_SOCKET_API(bool, hide_on_missing_motion)
NODE_SOCKET_API(bool, use_holdout)
NODE_SOCKET_API(bool, is_shadow_catcher)
NODE_SOCKET_API(float, shadow_terminator_offset)
float3 dupli_generated;
float2 dupli_uv;
NODE_SOCKET_API(float3, dupli_generated)
NODE_SOCKET_API(float2, dupli_uv)
ParticleSystem *particle_system;
int particle_index;
NODE_SOCKET_API(ParticleSystem *, particle_system);
NODE_SOCKET_API(int, particle_index);
Object();
~Object();

@ -131,7 +131,7 @@ void OSLShaderManager::device_update(Device *device,
compiler.background = (shader == background_shader);
compiler.compile(og, shader);
if (shader->use_mis && shader->has_surface_emission)
if (shader->get_use_mis() && shader->has_surface_emission)
scene->light_manager->need_update = true;
}
@ -145,7 +145,7 @@ void OSLShaderManager::device_update(Device *device,
og->use = true;
foreach (Shader *shader, scene->shaders)
shader->need_update = false;
shader->clear_modified();
need_update = false;
@ -1120,18 +1120,18 @@ OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph
void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
{
if (shader->need_update) {
if (shader->is_modified()) {
ShaderGraph *graph = shader->graph;
ShaderNode *output = (graph) ? graph->output() : NULL;
bool has_bump = (shader->displacement_method != DISPLACE_TRUE) &&
bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) &&
output->input("Surface")->link && output->input("Displacement")->link;
/* finalize */
shader->graph->finalize(scene,
has_bump,
shader->has_integrator_dependency,
shader->displacement_method == DISPLACE_BOTH);
shader->get_displacement_method() == DISPLACE_BOTH);
current_shader = shader;

@ -339,7 +339,7 @@ void Scene::device_update(Device *device_, Progress &progress)
Scene::MotionType Scene::need_motion()
{
if (integrator->motion_blur)
if (integrator->get_motion_blur())
return MOTION_BLUR;
else if (Pass::contains(passes, PASS_MOTION))
return MOTION_PASS;
@ -352,7 +352,7 @@ float Scene::motion_shutter_time()
if (need_motion() == Scene::MOTION_PASS)
return 2.0f;
else
return camera->shuttertime;
return camera->get_shuttertime();
}
bool Scene::need_global_attribute(AttributeStandard std)
@ -376,20 +376,21 @@ void Scene::need_global_attributes(AttributeRequestSet &attributes)
bool Scene::need_update()
{
return (need_reset() || film->need_update);
return (need_reset() || film->is_modified());
}
bool Scene::need_data_update()
{
return (background->need_update || image_manager->need_update || object_manager->need_update ||
return (background->is_modified() || image_manager->need_update || object_manager->need_update ||
geometry_manager->need_update || light_manager->need_update ||
lookup_tables->need_update || integrator->need_update || shader_manager->need_update ||
particle_system_manager->need_update || bake_manager->need_update || film->need_update);
lookup_tables->need_update || integrator->is_modified() || shader_manager->need_update ||
particle_system_manager->need_update || bake_manager->need_update ||
film->is_modified());
}
bool Scene::need_reset()
{
return need_data_update() || camera->need_update;
return need_data_update() || camera->is_modified();
}
void Scene::reset()
@ -398,9 +399,9 @@ void Scene::reset()
shader_manager->add_default(this);
/* ensure all objects are updated */
camera->tag_update();
dicing_camera->tag_update();
film->tag_update(this);
camera->tag_modified();
dicing_camera->tag_modified();
film->tag_modified();
background->tag_update(this);
integrator->tag_update(this);
object_manager->tag_update(this);
@ -442,24 +443,24 @@ DeviceRequestedFeatures Scene::get_requested_device_features()
requested_features.use_object_motion = false;
requested_features.use_camera_motion = use_motion && camera->use_motion();
foreach (Object *object, objects) {
Geometry *geom = object->geometry;
Geometry *geom = object->get_geometry();
if (use_motion) {
requested_features.use_object_motion |= object->use_motion() | geom->use_motion_blur;
requested_features.use_camera_motion |= geom->use_motion_blur;
requested_features.use_object_motion |= object->use_motion() | geom->get_use_motion_blur();
requested_features.use_camera_motion |= geom->get_use_motion_blur();
}
if (object->is_shadow_catcher) {
if (object->get_is_shadow_catcher()) {
requested_features.use_shadow_tricks = true;
}
if (geom->type == Geometry::MESH) {
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
#ifdef WITH_OPENSUBDIV
if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) {
if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
requested_features.use_patch_evaluation = true;
}
#endif
requested_features.use_true_displacement |= mesh->has_true_displacement();
}
else if (geom->type == Geometry::HAIR) {
else if (geom->is_hair()) {
requested_features.use_hair = true;
}
}
@ -467,8 +468,9 @@ DeviceRequestedFeatures Scene::get_requested_device_features()
requested_features.use_background_light = light_manager->has_background_light(this);
requested_features.use_baking = bake_manager->get_baking();
requested_features.use_integrator_branched = (integrator->method == Integrator::BRANCHED_PATH);
if (film->denoising_data_pass) {
requested_features.use_integrator_branched = (integrator->get_method() ==
Integrator::BRANCHED_PATH);
if (film->get_denoising_data_pass()) {
requested_features.use_denoising = true;
requested_features.use_shadow_tricks = true;
}

@ -1008,23 +1008,19 @@ bool Session::update_scene()
int height = tile_manager.state.buffer.full_height;
int resolution = tile_manager.state.resolution_divider;
if (width != cam->width || height != cam->height || resolution != cam->resolution) {
cam->width = width;
cam->height = height;
cam->resolution = resolution;
cam->tag_update();
}
cam->set_screen_size_and_resolution(width, height, resolution);
/* number of samples is needed by multi jittered
* sampling pattern and by baking */
Integrator *integrator = scene->integrator;
BakeManager *bake_manager = scene->bake_manager;
if (integrator->sampling_pattern != SAMPLING_PATTERN_SOBOL || bake_manager->get_baking()) {
if (integrator->get_sampling_pattern() != SAMPLING_PATTERN_SOBOL || bake_manager->get_baking()) {
int aa_samples = tile_manager.num_samples;
if (aa_samples != integrator->aa_samples) {
integrator->aa_samples = aa_samples;
integrator->set_aa_samples(aa_samples);
if (integrator->is_modified()) {
integrator->tag_update(scene);
}
}
@ -1118,7 +1114,7 @@ bool Session::render_need_denoise(bool &delayed)
/* Viewport render. */
/* It can happen that denoising was already enabled, but the scene still needs an update. */
if (scene->film->need_update || !scene->film->denoising_data_offset) {
if (scene->film->is_modified() || !scene->film->get_denoising_data_offset()) {
return false;
}
@ -1163,9 +1159,10 @@ void Session::render(bool need_denoise)
task.update_progress_sample = function_bind(&Progress::add_samples, &this->progress, _1, _2);
task.get_tile_stolen = function_bind(&Session::get_tile_stolen, this);
task.need_finish_queue = params.progressive_refine;
task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH;
task.integrator_branched = scene->integrator->get_method() == Integrator::BRANCHED_PATH;
task.adaptive_sampling.use = (scene->integrator->sampling_pattern == SAMPLING_PATTERN_PMJ) &&
task.adaptive_sampling.use = (scene->integrator->get_sampling_pattern() ==
SAMPLING_PATTERN_PMJ) &&
scene->dscene.data.film.pass_adaptive_aux_buffer;
task.adaptive_sampling.min_samples = scene->dscene.data.integrator.adaptive_min_samples;
task.adaptive_sampling.adaptive_step = scene->dscene.data.integrator.adaptive_step;
@ -1176,10 +1173,10 @@ void Session::render(bool need_denoise)
if (need_denoise) {
task.denoising = params.denoising;
task.pass_stride = scene->film->pass_stride;
task.pass_stride = scene->film->get_pass_stride();
task.target_pass_stride = task.pass_stride;
task.pass_denoising_data = scene->film->denoising_data_offset;
task.pass_denoising_clean = scene->film->denoising_clean_offset;
task.pass_denoising_data = scene->film->get_denoising_data_offset();
task.pass_denoising_clean = scene->film->get_denoising_clean_offset();
task.denoising_from_render = true;

@ -187,6 +187,8 @@ NODE_DEFINE(Shader)
displacement_method_enum.insert("both", DISPLACE_BOTH);
SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
SOCKET_INT(pass_id, "Pass ID", 0);
return type;
}
@ -216,7 +218,6 @@ Shader::Shader() : Node(node_type)
id = -1;
used = false;
need_update = true;
need_update_geometry = true;
}
@ -250,7 +251,7 @@ bool Shader::is_constant_emission(float3 *emission)
return false;
}
*emission = node->color * node->strength;
*emission = node->get_color() * node->get_strength();
}
else if (surf->link->parent->type == BackgroundNode::node_type) {
BackgroundNode *node = (BackgroundNode *)surf->link->parent;
@ -262,7 +263,7 @@ bool Shader::is_constant_emission(float3 *emission)
return false;
}
*emission = node->color * node->strength;
*emission = node->get_color() * node->get_strength();
}
else {
return false;
@ -306,7 +307,7 @@ void Shader::set_graph(ShaderGraph *graph_)
void Shader::tag_update(Scene *scene)
{
/* update tag */
need_update = true;
tag_modified();
scene->shader_manager->need_update = true;
/* if the shader previously was emissive, update light distribution,
@ -369,7 +370,7 @@ void Shader::tag_used(Scene *scene)
/* if an unused shader suddenly gets used somewhere, it needs to be
* recompiled because it was skipped for compilation before */
if (!used) {
need_update = true;
tag_modified();
scene->shader_manager->need_update = true;
}
}
@ -493,16 +494,18 @@ void ShaderManager::update_shaders_used(Scene *scene)
scene->default_background->used = true;
scene->default_empty->used = true;
if (scene->background->shader)
scene->background->shader->used = true;
if (scene->background->get_shader())
scene->background->get_shader()->used = true;
foreach (Geometry *geom, scene->geometry)
foreach (Shader *shader, geom->used_shaders)
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
shader->used = true;
}
foreach (Light *light, scene->lights)
if (light->shader)
light->shader->used = true;
if (light->get_shader())
const_cast<Shader *>(light->get_shader())->used = true;
}
void ShaderManager::device_update_common(Device *device,
@ -522,9 +525,9 @@ void ShaderManager::device_update_common(Device *device,
foreach (Shader *shader, scene->shaders) {
uint flag = 0;
if (shader->use_mis)
if (shader->get_use_mis())
flag |= SD_USE_MIS;
if (shader->has_surface_transparent && shader->use_transparent_shadow)
if (shader->has_surface_transparent && shader->get_use_transparent_shadow())
flag |= SD_HAS_TRANSPARENT_SHADOW;
if (shader->has_volume) {
flag |= SD_HAS_VOLUME;
@ -539,7 +542,7 @@ void ShaderManager::device_update_common(Device *device,
if (shader->has_volume_connected && !shader->has_surface)
flag |= SD_HAS_ONLY_VOLUME;
if (shader->has_volume) {
if (shader->heterogeneous_volume && shader->has_volume_spatial_varying)
if (shader->get_heterogeneous_volume() && shader->has_volume_spatial_varying)
flag |= SD_HETEROGENEOUS_VOLUME;
}
if (shader->has_volume_attribute_dependency)
@ -547,16 +550,16 @@ void ShaderManager::device_update_common(Device *device,
if (shader->has_bssrdf_bump)
flag |= SD_HAS_BSSRDF_BUMP;
if (device->info.has_volume_decoupled) {
if (shader->volume_sampling_method == VOLUME_SAMPLING_EQUIANGULAR)
if (shader->get_volume_sampling_method() == VOLUME_SAMPLING_EQUIANGULAR)
flag |= SD_VOLUME_EQUIANGULAR;
if (shader->volume_sampling_method == VOLUME_SAMPLING_MULTIPLE_IMPORTANCE)
if (shader->get_volume_sampling_method() == VOLUME_SAMPLING_MULTIPLE_IMPORTANCE)
flag |= SD_VOLUME_MIS;
}
if (shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC)
if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC)
flag |= SD_VOLUME_CUBIC;
if (shader->has_bump)
flag |= SD_HAS_BUMP;
if (shader->displacement_method != DISPLACE_BUMP)
if (shader->get_displacement_method() != DISPLACE_BUMP)
flag |= SD_HAS_DISPLACEMENT;
/* constant emission check */
@ -568,7 +571,7 @@ void ShaderManager::device_update_common(Device *device,
/* regular shader */
kshader->flags = flag;
kshader->pass_id = shader->pass_id;
kshader->pass_id = shader->get_pass_id();
kshader->constant_emission[0] = constant_emission.x;
kshader->constant_emission[1] = constant_emission.y;
kshader->constant_emission[2] = constant_emission.z;
@ -625,7 +628,7 @@ void ShaderManager::add_default(Scene *scene)
ShaderGraph *graph = new ShaderGraph();
DiffuseBsdfNode *diffuse = graph->create_node<DiffuseBsdfNode>();
diffuse->color = make_float3(0.8f, 0.8f, 0.8f);
diffuse->set_color(make_float3(0.8f, 0.8f, 0.8f));
graph->add(diffuse);
graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface"));
@ -658,8 +661,8 @@ void ShaderManager::add_default(Scene *scene)
ShaderGraph *graph = new ShaderGraph();
EmissionNode *emission = graph->create_node<EmissionNode>();
emission->color = make_float3(0.8f, 0.8f, 0.8f);
emission->strength = 0.0f;
emission->set_color(make_float3(0.8f, 0.8f, 0.8f));
emission->set_strength(0.0f);
graph->add(emission);
graph->connect(emission->output("Emission"), graph->output()->input("Surface"));
@ -703,10 +706,10 @@ void ShaderManager::get_requested_graph_features(ShaderGraph *graph,
requested_features->nodes_features |= node->get_feature();
if (node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) {
BsdfBaseNode *bsdf_node = static_cast<BsdfBaseNode *>(node);
if (CLOSURE_IS_VOLUME(bsdf_node->closure)) {
if (CLOSURE_IS_VOLUME(bsdf_node->get_closure_type())) {
requested_features->nodes_features |= NODE_FEATURE_VOLUME;
}
else if (CLOSURE_IS_PRINCIPLED(bsdf_node->closure)) {
else if (CLOSURE_IS_PRINCIPLED(bsdf_node->get_closure_type())) {
requested_features->use_principled = true;
}
}
@ -738,7 +741,7 @@ void ShaderManager::get_requested_features(Scene *scene,
ShaderNode *output_node = shader->graph->output();
if (output_node->input("Displacement")->link != NULL) {
requested_features->nodes_features |= NODE_FEATURE_BUMP;
if (shader->displacement_method == DISPLACE_BOTH) {
if (shader->get_displacement_method() == DISPLACE_BOTH) {
requested_features->nodes_features |= NODE_FEATURE_BUMP_STATE;
requested_features->max_nodes_group = max(requested_features->max_nodes_group,
NODE_GROUP_LEVEL_1);

@ -81,22 +81,25 @@ class Shader : public Node {
public:
NODE_DECLARE
int pass_id;
/* shader graph */
ShaderGraph *graph;
NODE_SOCKET_API(int, pass_id)
/* sampling */
bool use_mis;
bool use_transparent_shadow;
bool heterogeneous_volume;
VolumeSampling volume_sampling_method;
int volume_interpolation_method;
float volume_step_rate;
NODE_SOCKET_API(bool, use_mis)
NODE_SOCKET_API(bool, use_transparent_shadow)
NODE_SOCKET_API(bool, heterogeneous_volume)
NODE_SOCKET_API(VolumeSampling, volume_sampling_method)
NODE_SOCKET_API(int, volume_interpolation_method)
NODE_SOCKET_API(float, volume_step_rate)
/* displacement */
NODE_SOCKET_API(DisplacementMethod, displacement_method)
float prev_volume_step_rate;
/* synchronization */
bool need_update;
bool need_update_geometry;
/* If the shader has only volume components, the surface is assumed to
@ -122,9 +125,6 @@ class Shader : public Node {
bool has_volume_attribute_dependency;
bool has_integrator_dependency;
/* displacement */
DisplacementMethod displacement_method;
/* requested mesh attributes */
AttributeRequestSet attributes;

@ -123,8 +123,8 @@ void SVMShaderManager::device_update(Device *device,
for (int i = 0; i < num_shaders; i++) {
Shader *shader = scene->shaders[i];
shader->need_update = false;
if (shader->use_mis && shader->has_surface_emission) {
shader->clear_modified();
if (shader->get_use_mis() && shader->has_surface_emission) {
scene->light_manager->need_update = true;
}
@ -749,7 +749,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
/* for the bump shader we need add a node to store the shader state */
bool need_bump_state = (type == SHADER_TYPE_BUMP) &&
(shader->displacement_method == DISPLACE_BOTH);
(shader->get_displacement_method() == DISPLACE_BOTH);
int bump_state_offset = SVM_STACK_INVALID;
if (need_bump_state) {
bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE);
@ -840,7 +840,7 @@ void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Sum
const double time_start = time_dt();
bool has_bump = (shader->displacement_method != DISPLACE_TRUE) &&
bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) &&
output->input("Surface")->link && output->input("Displacement")->link;
/* finalize */
@ -849,7 +849,7 @@ void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Sum
shader->graph->finalize(scene,
has_bump,
shader->has_integrator_dependency,
shader->displacement_method == DISPLACE_BOTH);
shader->get_displacement_method() == DISPLACE_BOTH);
}
current_shader = shader;

@ -518,20 +518,20 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
if (image_memory->data_elements == 1) {
grid = openvdb_grid_from_device_texture<openvdb::FloatGrid>(
image_memory, volume->clipping, handle.metadata().transform_3d);
image_memory, volume->get_clipping(), handle.metadata().transform_3d);
}
else if (image_memory->data_elements == 3) {
grid = openvdb_grid_from_device_texture<openvdb::Vec3fGrid>(
image_memory, volume->clipping, handle.metadata().transform_3d);
image_memory, volume->get_clipping(), handle.metadata().transform_3d);
}
else if (image_memory->data_elements == 4) {
grid = openvdb_grid_from_device_texture<openvdb::Vec4fGrid>(
image_memory, volume->clipping, handle.metadata().transform_3d);
image_memory, volume->get_clipping(), handle.metadata().transform_3d);
}
}
if (grid) {
builder.add_grid(grid, do_clipping, volume->clipping);
builder.add_grid(grid, do_clipping, volume->get_clipping());
}
}
#endif
@ -544,17 +544,19 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
Shader *volume_shader = NULL;
int pad_size = 0;
foreach (Shader *shader, volume->used_shaders) {
foreach (Node *node, volume->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
if (!shader->has_volume) {
continue;
}
volume_shader = shader;
if (shader->volume_interpolation_method == VOLUME_INTERPOLATION_LINEAR) {
if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_LINEAR) {
pad_size = max(1, pad_size);
}
else if (shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC) {
else if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC) {
pad_size = max(2, pad_size);
}
@ -582,8 +584,8 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress)
volume->clear();
volume->reserve_mesh(vertices.size(), indices.size() / 3);
volume->used_shaders.push_back(volume_shader);
volume->need_update = true;
volume->used_shaders.push_back_slow(volume_shader);
volume->tag_modified();
volume->need_update_rebuild = true;
for (size_t i = 0; i < vertices.size(); ++i) {

@ -28,9 +28,9 @@ class Volume : public Mesh {
Volume();
float clipping;
float step_size;
bool object_space;
NODE_SOCKET_API(float, clipping)
NODE_SOCKET_API(float, step_size)
NODE_SOCKET_API(bool, object_space)
virtual void clear(bool preserve_shaders = false) override;
};

@ -42,11 +42,11 @@ void EdgeDice::reserve(int num_verts, int num_triangles)
{
Mesh *mesh = params.mesh;
vert_offset = mesh->verts.size();
vert_offset = mesh->get_verts().size();
tri_offset = mesh->num_triangles();
mesh->resize_mesh(mesh->verts.size() + num_verts, mesh->num_triangles());
mesh->reserve_mesh(mesh->verts.size() + num_verts, mesh->num_triangles() + num_triangles);
mesh->resize_mesh(mesh->get_verts().size() + num_verts, mesh->num_triangles());
mesh->reserve_mesh(mesh->get_verts().size() + num_verts, mesh->num_triangles() + num_triangles);
Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);

@ -341,8 +341,8 @@ void DiagSplit::split_patches(Patch *patches, size_t patches_byte_stride)
{
int patch_index = 0;
for (int f = 0; f < params.mesh->subd_faces.size(); f++) {
Mesh::SubdFace &face = params.mesh->subd_faces[f];
for (int f = 0; f < params.mesh->get_num_subd_faces(); f++) {
Mesh::SubdFace face = params.mesh->get_subd_face(f);
Patch *patch = (Patch *)(((char *)patches) + patch_index * patches_byte_stride);
@ -372,8 +372,8 @@ static Edge *create_edge_from_corner(DiagSplit *split,
int v0,
int v1)
{
int a = mesh->subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)];
int b = mesh->subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)];
int a = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 0, face.num_corners)];
int b = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 1, face.num_corners)];
reversed = !(b < a);
@ -443,8 +443,8 @@ static Edge *create_split_edge_from_corner(DiagSplit *split,
{
Edge *edge = split->alloc_edge();
int a = mesh->subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)];
int b = mesh->subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)];
int a = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 0, face.num_corners)];
int b = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 1, face.num_corners)];
if (b < a) {
edge->stitch_edge_key = {b, a};

@ -64,9 +64,11 @@ template<typename T> class ShaderNodeBuilder {
return *this;
}
template<typename T2, typename V> ShaderNodeBuilder &set(V T2::*pfield, V value)
template<typename V> ShaderNodeBuilder &set_param(const string &input_name, V value)
{
static_cast<T *>(node_)->*pfield = value;
const SocketType *input_socket = node_->type->find_input(ustring(input_name.c_str()));
EXPECT_NE((void *)NULL, input_socket);
node_->set(*input_socket, value);
return *this;
}
@ -121,8 +123,8 @@ class ShaderGraphBuilder {
/* Common input/output boilerplate. */
ShaderGraphBuilder &add_attribute(const string &name)
{
return (*this).add_node(ShaderNodeBuilder<AttributeNode>(*graph_, name)
.set(&AttributeNode::attribute, ustring(name)));
return (*this).add_node(
ShaderNodeBuilder<AttributeNode>(*graph_, name).set_param("attribute", ustring(name)));
}
ShaderGraphBuilder &output_closure(const string &from)
@ -210,12 +212,12 @@ TEST_F(RenderGraph, deduplicate_deep)
builder.add_node(ShaderNodeBuilder<GeometryNode>(graph, "Geometry1"))
.add_node(ShaderNodeBuilder<GeometryNode>(graph, "Geometry2"))
.add_node(ShaderNodeBuilder<ValueNode>(graph, "Value1").set(&ValueNode::value, 0.8f))
.add_node(ShaderNodeBuilder<ValueNode>(graph, "Value2").set(&ValueNode::value, 0.8f))
.add_node(ShaderNodeBuilder<ValueNode>(graph, "Value1").set_param("value", 0.8f))
.add_node(ShaderNodeBuilder<ValueNode>(graph, "Value2").set_param("value", 0.8f))
.add_node(ShaderNodeBuilder<NoiseTextureNode>(graph, "Noise1"))
.add_node(ShaderNodeBuilder<NoiseTextureNode>(graph, "Noise2"))
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix")
.set(&MixNode::type, NODE_MIX_BLEND)
.set_param("mix_type", NODE_MIX_BLEND)
.set("Fac", 0.5f))
.add_connection("Geometry1::Parametric", "Noise1::Vector")
.add_connection("Value1::Value", "Noise1::Scale")
@ -422,8 +424,8 @@ TEST_F(RenderGraph, constant_fold_mix_add)
builder
.add_node(ShaderNodeBuilder<MixNode>(graph, "MixAdd")
.set(&MixNode::type, NODE_MIX_ADD)
.set(&MixNode::use_clamp, false)
.set_param("mix_type", NODE_MIX_ADD)
.set_param("use_clamp", false)
.set("Fac", 0.8f)
.set("Color1", make_float3(0.3f, 0.5f, 0.7f))
.set("Color2", make_float3(0.4f, 0.8f, 0.9f)))
@ -443,8 +445,8 @@ TEST_F(RenderGraph, constant_fold_mix_add_clamp)
builder
.add_node(ShaderNodeBuilder<MixNode>(graph, "MixAdd")
.set(&MixNode::type, NODE_MIX_ADD)
.set(&MixNode::use_clamp, true)
.set_param("mix_type", NODE_MIX_ADD)
.set_param("use_clamp", true)
.set("Fac", 0.8f)
.set("Color1", make_float3(0.3f, 0.5f, 0.7f))
.set("Color2", make_float3(0.4f, 0.8f, 0.9f)))
@ -465,8 +467,8 @@ TEST_F(RenderGraph, constant_fold_part_mix_dodge_no_fac_0)
builder.add_attribute("Attribute1")
.add_attribute("Attribute2")
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix")
.set(&MixNode::type, NODE_MIX_DODGE)
.set(&MixNode::use_clamp, false)
.set_param("mix_type", NODE_MIX_DODGE)
.set_param("use_clamp", false)
.set("Fac", 0.0f))
.add_connection("Attribute1::Color", "Mix::Color1")
.add_connection("Attribute2::Color", "Mix::Color2")
@ -487,8 +489,8 @@ TEST_F(RenderGraph, constant_fold_part_mix_light_no_fac_0)
builder.add_attribute("Attribute1")
.add_attribute("Attribute2")
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix")
.set(&MixNode::type, NODE_MIX_LIGHT)
.set(&MixNode::use_clamp, false)
.set_param("mix_type", NODE_MIX_LIGHT)
.set_param("use_clamp", false)
.set("Fac", 0.0f))
.add_connection("Attribute1::Color", "Mix::Color1")
.add_connection("Attribute2::Color", "Mix::Color2")
@ -509,8 +511,8 @@ TEST_F(RenderGraph, constant_fold_part_mix_burn_no_fac_0)
builder.add_attribute("Attribute1")
.add_attribute("Attribute2")
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix")
.set(&MixNode::type, NODE_MIX_BURN)
.set(&MixNode::use_clamp, false)
.set_param("mix_type", NODE_MIX_BURN)
.set_param("use_clamp", false)
.set("Fac", 0.0f))
.add_connection("Attribute1::Color", "Mix::Color1")
.add_connection("Attribute2::Color", "Mix::Color2")
@ -531,8 +533,8 @@ TEST_F(RenderGraph, constant_fold_part_mix_blend_clamped_no_fac_0)
builder.add_attribute("Attribute1")
.add_attribute("Attribute2")
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix")
.set(&MixNode::type, NODE_MIX_BLEND)
.set(&MixNode::use_clamp, true)
.set_param("mix_type", NODE_MIX_BLEND)
.set_param("use_clamp", true)
.set("Fac", 0.0f))
.add_connection("Attribute1::Color", "Mix::Color1")
.add_connection("Attribute2::Color", "Mix::Color2")
@ -557,22 +559,22 @@ TEST_F(RenderGraph, constant_fold_part_mix_blend)
.add_attribute("Attribute2")
/* choose left */
.add_node(ShaderNodeBuilder<MixNode>(graph, "MixBlend1")
.set(&MixNode::type, NODE_MIX_BLEND)
.set(&MixNode::use_clamp, false)
.set_param("mix_type", NODE_MIX_BLEND)
.set_param("use_clamp", false)
.set("Fac", 0.0f))
.add_connection("Attribute1::Color", "MixBlend1::Color1")
.add_connection("Attribute2::Color", "MixBlend1::Color2")
/* choose right */
.add_node(ShaderNodeBuilder<MixNode>(graph, "MixBlend2")
.set(&MixNode::type, NODE_MIX_BLEND)
.set(&MixNode::use_clamp, false)
.set_param("mix_type", NODE_MIX_BLEND)
.set_param("use_clamp", false)
.set("Fac", 1.0f))
.add_connection("Attribute1::Color", "MixBlend2::Color2")
.add_connection("Attribute2::Color", "MixBlend2::Color1")
/* both inputs folded to Attribute1 */
.add_node(ShaderNodeBuilder<MixNode>(graph, "MixBlend3")
.set(&MixNode::type, NODE_MIX_BLEND)
.set(&MixNode::use_clamp, false))
.set_param("mix_type", NODE_MIX_BLEND)
.set_param("use_clamp", false))
.add_connection("Attribute1::Fac", "MixBlend3::Fac")
.add_connection("MixBlend1::Color", "MixBlend3::Color1")
.add_connection("MixBlend2::Color", "MixBlend3::Color2")
@ -592,8 +594,8 @@ TEST_F(RenderGraph, constant_fold_part_mix_sub_same_fac_bad)
builder.add_attribute("Attribute")
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix")
.set(&MixNode::type, NODE_MIX_SUB)
.set(&MixNode::use_clamp, true)
.set_param("mix_type", NODE_MIX_SUB)
.set_param("use_clamp", true)
.set("Fac", 0.5f))
.add_connection("Attribute::Color", "Mix::Color1")
.add_connection("Attribute::Color", "Mix::Color2")
@ -613,8 +615,8 @@ TEST_F(RenderGraph, constant_fold_part_mix_sub_same_fac_1)
builder.add_attribute("Attribute")
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix")
.set(&MixNode::type, NODE_MIX_SUB)
.set(&MixNode::use_clamp, true)
.set_param("mix_type", NODE_MIX_SUB)
.set_param("use_clamp", true)
.set("Fac", 1.0f))
.add_connection("Attribute::Color", "Mix::Color1")
.add_connection("Attribute::Color", "Mix::Color2")
@ -635,12 +637,12 @@ static void build_mix_partial_test_graph(ShaderGraphBuilder &builder,
.add_attribute("Attribute")
/* constant on the left */
.add_node(ShaderNodeBuilder<MixNode>(builder.graph(), "Mix_Cx_Fx")
.set(&MixNode::type, type)
.set(&MixNode::use_clamp, false)
.set_param("mix_type", type)
.set_param("use_clamp", false)
.set("Color1", constval))
.add_node(ShaderNodeBuilder<MixNode>(builder.graph(), "Mix_Cx_F1")
.set(&MixNode::type, type)
.set(&MixNode::use_clamp, false)
.set_param("mix_type", type)
.set_param("use_clamp", false)
.set("Color1", constval)
.set("Fac", 1.0f))
.add_connection("Attribute::Fac", "Mix_Cx_Fx::Fac")
@ -648,12 +650,12 @@ static void build_mix_partial_test_graph(ShaderGraphBuilder &builder,
.add_connection("Attribute::Color", "Mix_Cx_F1::Color2")
/* constant on the right */
.add_node(ShaderNodeBuilder<MixNode>(builder.graph(), "Mix_xC_Fx")
.set(&MixNode::type, type)
.set(&MixNode::use_clamp, false)
.set_param("mix_type", type)
.set_param("use_clamp", false)
.set("Color2", constval))
.add_node(ShaderNodeBuilder<MixNode>(builder.graph(), "Mix_xC_F1")
.set(&MixNode::type, type)
.set(&MixNode::use_clamp, false)
.set_param("mix_type", type)
.set_param("use_clamp", false)
.set("Color2", constval)
.set("Fac", 1.0f))
.add_connection("Attribute::Fac", "Mix_xC_Fx::Fac")
@ -661,16 +663,16 @@ static void build_mix_partial_test_graph(ShaderGraphBuilder &builder,
.add_connection("Attribute::Color", "Mix_xC_F1::Color1")
/* results of actual tests simply added up to connect to output */
.add_node(ShaderNodeBuilder<MixNode>(builder.graph(), "Out12")
.set(&MixNode::type, NODE_MIX_ADD)
.set(&MixNode::use_clamp, true)
.set_param("mix_type", NODE_MIX_ADD)
.set_param("use_clamp", true)
.set("Fac", 1.0f))
.add_node(ShaderNodeBuilder<MixNode>(builder.graph(), "Out34")
.set(&MixNode::type, NODE_MIX_ADD)
.set(&MixNode::use_clamp, true)
.set_param("mix_type", NODE_MIX_ADD)
.set_param("use_clamp", true)
.set("Fac", 1.0f))
.add_node(ShaderNodeBuilder<MixNode>(builder.graph(), "Out1234")
.set(&MixNode::type, NODE_MIX_ADD)
.set(&MixNode::use_clamp, true)
.set_param("mix_type", NODE_MIX_ADD)
.set_param("use_clamp", true)
.set("Fac", 1.0f))
.add_connection("Mix_Cx_Fx::Color", "Out12::Color1")
.add_connection("Mix_Cx_F1::Color", "Out12::Color2")
@ -898,8 +900,8 @@ TEST_F(RenderGraph, constant_fold_gamma_part_0)
.add_connection("Attribute::Color", "Gamma_xC::Color")
/* output sum */
.add_node(ShaderNodeBuilder<MixNode>(graph, "Out")
.set(&MixNode::type, NODE_MIX_ADD)
.set(&MixNode::use_clamp, true)
.set_param("mix_type", NODE_MIX_ADD)
.set_param("use_clamp", true)
.set("Fac", 1.0f))
.add_connection("Gamma_Cx::Color", "Out::Color1")
.add_connection("Gamma_xC::Color", "Out::Color2")
@ -928,8 +930,8 @@ TEST_F(RenderGraph, constant_fold_gamma_part_1)
.add_connection("Attribute::Color", "Gamma_xC::Color")
/* output sum */
.add_node(ShaderNodeBuilder<MixNode>(graph, "Out")
.set(&MixNode::type, NODE_MIX_ADD)
.set(&MixNode::use_clamp, true)
.set_param("mix_type", NODE_MIX_ADD)
.set_param("use_clamp", true)
.set("Fac", 1.0f))
.add_connection("Gamma_Cx::Color", "Out::Color1")
.add_connection("Gamma_xC::Color", "Out::Color2")
@ -988,8 +990,8 @@ TEST_F(RenderGraph, constant_fold_math)
builder
.add_node(ShaderNodeBuilder<MathNode>(graph, "Math")
.set(&MathNode::type, NODE_MATH_ADD)
.set(&MathNode::use_clamp, false)
.set_param("math_type", NODE_MATH_ADD)
.set_param("use_clamp", false)
.set("Value1", 0.7f)
.set("Value2", 0.9f))
.output_value("Math::Value");
@ -1007,8 +1009,8 @@ TEST_F(RenderGraph, constant_fold_math_clamp)
builder
.add_node(ShaderNodeBuilder<MathNode>(graph, "Math")
.set(&MathNode::type, NODE_MATH_ADD)
.set(&MathNode::use_clamp, true)
.set_param("math_type", NODE_MATH_ADD)
.set_param("use_clamp", true)
.set("Value1", 0.7f)
.set("Value2", 0.9f))
.output_value("Math::Value");
@ -1028,20 +1030,20 @@ static void build_math_partial_test_graph(ShaderGraphBuilder &builder,
.add_attribute("Attribute")
/* constant on the left */
.add_node(ShaderNodeBuilder<MathNode>(builder.graph(), "Math_Cx")
.set(&MathNode::type, type)
.set(&MathNode::use_clamp, false)
.set_param("math_type", type)
.set_param("use_clamp", false)
.set("Value1", constval))
.add_connection("Attribute::Fac", "Math_Cx::Value2")
/* constant on the right */
.add_node(ShaderNodeBuilder<MathNode>(builder.graph(), "Math_xC")
.set(&MathNode::type, type)
.set(&MathNode::use_clamp, false)
.set_param("math_type", type)
.set_param("use_clamp", false)
.set("Value2", constval))
.add_connection("Attribute::Fac", "Math_xC::Value1")
/* output sum */
.add_node(ShaderNodeBuilder<MathNode>(builder.graph(), "Out")
.set(&MathNode::type, NODE_MATH_ADD)
.set(&MathNode::use_clamp, true))
.set_param("math_type", NODE_MATH_ADD)
.set_param("use_clamp", true))
.add_connection("Math_Cx::Value", "Out::Value1")
.add_connection("Math_xC::Value", "Out::Value2")
.output_value("Out::Value");
@ -1178,7 +1180,7 @@ TEST_F(RenderGraph, constant_fold_vector_math)
builder
.add_node(ShaderNodeBuilder<VectorMathNode>(graph, "VectorMath")
.set(&VectorMathNode::type, NODE_VECTOR_MATH_SUBTRACT)
.set_param("math_type", NODE_VECTOR_MATH_SUBTRACT)
.set("Vector1", make_float3(1.3f, 0.5f, 0.7f))
.set("Vector2", make_float3(-1.7f, 0.5f, 0.7f)))
.output_color("VectorMath::Vector");
@ -1198,17 +1200,17 @@ static void build_vecmath_partial_test_graph(ShaderGraphBuilder &builder,
.add_attribute("Attribute")
/* constant on the left */
.add_node(ShaderNodeBuilder<VectorMathNode>(builder.graph(), "Math_Cx")
.set(&VectorMathNode::type, type)
.set_param("math_type", type)
.set("Vector1", constval))
.add_connection("Attribute::Vector", "Math_Cx::Vector2")
/* constant on the right */
.add_node(ShaderNodeBuilder<VectorMathNode>(builder.graph(), "Math_xC")
.set(&VectorMathNode::type, type)
.set_param("math_type", type)
.set("Vector2", constval))
.add_connection("Attribute::Vector", "Math_xC::Vector1")
/* output sum */
.add_node(ShaderNodeBuilder<VectorMathNode>(builder.graph(), "Out")
.set(&VectorMathNode::type, NODE_VECTOR_MATH_ADD))
.set_param("math_type", NODE_VECTOR_MATH_ADD))
.add_connection("Math_Cx::Vector", "Out::Vector1")
.add_connection("Math_xC::Vector", "Out::Vector2")
.output_color("Out::Vector");
@ -1312,9 +1314,9 @@ TEST_F(RenderGraph, constant_fold_rgb_curves)
builder
.add_node(ShaderNodeBuilder<RGBCurvesNode>(graph, "Curves")
.set(&CurvesNode::curves, curve)
.set(&CurvesNode::min_x, 0.1f)
.set(&CurvesNode::max_x, 0.9f)
.set_param("curves", curve)
.set_param("min_x", 0.1f)
.set_param("max_x", 0.9f)
.set("Fac", 0.5f)
.set("Color", make_float3(0.3f, 0.5f, 0.7f)))
.output_color("Curves::Color");
@ -1336,9 +1338,9 @@ TEST_F(RenderGraph, constant_fold_rgb_curves_fac_0)
builder.add_attribute("Attribute")
.add_node(ShaderNodeBuilder<RGBCurvesNode>(graph, "Curves")
.set(&CurvesNode::curves, curve)
.set(&CurvesNode::min_x, 0.1f)
.set(&CurvesNode::max_x, 0.9f)
.set_param("curves", curve)
.set_param("min_x", 0.1f)
.set_param("max_x", 0.9f)
.set("Fac", 0.0f))
.add_connection("Attribute::Color", "Curves::Color")
.output_color("Curves::Color");
@ -1360,9 +1362,9 @@ TEST_F(RenderGraph, constant_fold_rgb_curves_fac_0_const)
builder
.add_node(ShaderNodeBuilder<RGBCurvesNode>(graph, "Curves")
.set(&CurvesNode::curves, curve)
.set(&CurvesNode::min_x, 0.1f)
.set(&CurvesNode::max_x, 0.9f)
.set_param("curves", curve)
.set_param("min_x", 0.1f)
.set_param("max_x", 0.9f)
.set("Fac", 0.0f)
.set("Color", make_float3(0.3f, 0.5f, 0.7f)))
.output_color("Curves::Color");
@ -1384,9 +1386,9 @@ TEST_F(RenderGraph, constant_fold_vector_curves)
builder
.add_node(ShaderNodeBuilder<VectorCurvesNode>(graph, "Curves")
.set(&CurvesNode::curves, curve)
.set(&CurvesNode::min_x, 0.1f)
.set(&CurvesNode::max_x, 0.9f)
.set_param("curves", curve)
.set_param("min_x", 0.1f)
.set_param("max_x", 0.9f)
.set("Fac", 0.5f)
.set("Vector", make_float3(0.3f, 0.5f, 0.7f)))
.output_color("Curves::Vector");
@ -1408,9 +1410,9 @@ TEST_F(RenderGraph, constant_fold_vector_curves_fac_0)
builder.add_attribute("Attribute")
.add_node(ShaderNodeBuilder<VectorCurvesNode>(graph, "Curves")
.set(&CurvesNode::curves, curve)
.set(&CurvesNode::min_x, 0.1f)
.set(&CurvesNode::max_x, 0.9f)
.set_param("curves", curve)
.set_param("min_x", 0.1f)
.set_param("max_x", 0.9f)
.set("Fac", 0.0f))
.add_connection("Attribute::Vector", "Curves::Vector")
.output_color("Curves::Vector");
@ -1435,11 +1437,11 @@ TEST_F(RenderGraph, constant_fold_rgb_ramp)
builder
.add_node(ShaderNodeBuilder<RGBRampNode>(graph, "Ramp")
.set(&RGBRampNode::ramp, curve)
.set(&RGBRampNode::ramp_alpha, alpha)
.set(&RGBRampNode::interpolate, true)
.set_param("ramp", curve)
.set_param("ramp_alpha", alpha)
.set_param("interpolate", true)
.set("Fac", 0.56f))
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix").set(&MixNode::type, NODE_MIX_ADD))
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix").set_param("mix_type", NODE_MIX_ADD))
.add_connection("Ramp::Color", "Mix::Color1")
.add_connection("Ramp::Alpha", "Mix::Color2")
.output_color("Mix::Color");
@ -1464,11 +1466,11 @@ TEST_F(RenderGraph, constant_fold_rgb_ramp_flat)
builder
.add_node(ShaderNodeBuilder<RGBRampNode>(graph, "Ramp")
.set(&RGBRampNode::ramp, curve)
.set(&RGBRampNode::ramp_alpha, alpha)
.set(&RGBRampNode::interpolate, false)
.set_param("ramp", curve)
.set_param("ramp_alpha", alpha)
.set_param("interpolate", false)
.set("Fac", 0.56f))
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix").set(&MixNode::type, NODE_MIX_ADD))
.add_node(ShaderNodeBuilder<MixNode>(graph, "Mix").set_param("mix_type", NODE_MIX_ADD))
.add_connection("Ramp::Color", "Mix::Color1")
.add_connection("Ramp::Alpha", "Mix::Color2")
.output_color("Mix::Color");
@ -1510,7 +1512,7 @@ TEST_F(RenderGraph, constant_fold_convert_color_vector_color)
builder.add_attribute("Attribute")
.add_node(ShaderNodeBuilder<VectorMathNode>(graph, "VecAdd")
.set(&VectorMathNode::type, NODE_VECTOR_MATH_ADD)
.set_param("math_type", NODE_VECTOR_MATH_ADD)
.set("Vector2", make_float3(0, 0, 0)))
.add_connection("Attribute::Color", "VecAdd::Vector1")
.output_color("VecAdd::Vector");
@ -1531,7 +1533,7 @@ TEST_F(RenderGraph, constant_fold_convert_color_float_color)
builder.add_attribute("Attribute")
.add_node(ShaderNodeBuilder<MathNode>(graph, "MathAdd")
.set(&MathNode::type, NODE_MATH_ADD)
.set_param("math_type", NODE_MATH_ADD)
.set("Value2", 0.0f))
.add_connection("Attribute::Color", "MathAdd::Value1")
.output_color("MathAdd::Value");

@ -213,6 +213,26 @@ template<typename T, size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES> class arra
return data_[i];
}
T *begin()
{
return data_;
}
const T *begin() const
{
return data_;
}
T *end()
{
return data_ + datasize_;
}
const T *end() const
{
return data_ + datasize_;
}
void reserve(size_t newcapacity)
{
if (newcapacity > capacity_) {