Cycles: Perform attribute subdivision on the host side
* Add SubdAttributeInterpolation class for linear attribute interpolation. * Dicing computes ptex UV and face ID for interpolation. * Simplify mesh storage of subd primitive counts * Remove kernel code for subd attribute interpolation * Remove patch table packing and upload The old optimization adds a fair amount of complexity to the kernel, affecting performance even when not using the feature. It's also not that useful as it does not work for UVs that needs special interpolation. With this simpler code it should be easier to make it feature complete. Pull Request: https://projects.blender.org/blender/blender/pulls/135681
This commit is contained in:
@@ -580,13 +580,11 @@ static void xml_read_mesh(const XMLReadState &state, const xml_node node)
|
||||
/* create vertices */
|
||||
mesh->set_verts(P_array);
|
||||
|
||||
size_t num_ngons = 0;
|
||||
size_t num_corners = 0;
|
||||
for (size_t i = 0; i < nverts.size(); i++) {
|
||||
num_ngons += (nverts[i] == 4) ? 0 : 1;
|
||||
num_corners += nverts[i];
|
||||
}
|
||||
mesh->reserve_subd_faces(nverts.size(), num_ngons, num_corners);
|
||||
mesh->reserve_subd_faces(nverts.size(), num_corners);
|
||||
|
||||
/* create subd_faces */
|
||||
int index_offset = 0;
|
||||
@@ -603,14 +601,6 @@ static void xml_read_mesh(const XMLReadState &state, const xml_node node)
|
||||
Attribute *attr = mesh->subd_attributes.add(ATTR_STD_UV);
|
||||
float3 *fdata = attr->data_float3();
|
||||
|
||||
/* TODO: Implement various face-varying interpolation modes and make it
|
||||
* a property of Mesh. */
|
||||
#if 0
|
||||
if (subdivide_uvs) {
|
||||
attr->flags |= ATTR_SUBDIVIDED;
|
||||
}
|
||||
#endif
|
||||
|
||||
index_offset = 0;
|
||||
for (size_t i = 0; i < nverts.size(); i++) {
|
||||
for (int j = 0; j < nverts[i]; j++) {
|
||||
|
||||
@@ -504,7 +504,6 @@ static void attr_create_uv_map(Scene *scene,
|
||||
static void attr_create_subd_uv_map(Scene *scene,
|
||||
Mesh *mesh,
|
||||
const ::Mesh &b_mesh,
|
||||
bool subdivide_uvs,
|
||||
const set<ustring> &blender_uv_names)
|
||||
{
|
||||
const blender::OffsetIndices faces = b_mesh.faces();
|
||||
@@ -540,10 +539,6 @@ static void attr_create_subd_uv_map(Scene *scene,
|
||||
uv_attr = mesh->subd_attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
|
||||
}
|
||||
|
||||
if (subdivide_uvs) {
|
||||
uv_attr->flags |= ATTR_SUBDIVIDED;
|
||||
}
|
||||
|
||||
const blender::VArraySpan b_uv_map = *b_attributes.lookup<blender::float2>(
|
||||
uv_name.c_str(), blender::bke::AttrDomain::Corner);
|
||||
float2 *fdata = uv_attr->data_float2();
|
||||
@@ -841,21 +836,13 @@ static void create_mesh(Scene *scene,
|
||||
corner_normals = b_mesh.corner_normals();
|
||||
}
|
||||
|
||||
int numngons = 0;
|
||||
int numtris = 0;
|
||||
if (!subdivision) {
|
||||
numtris = numfaces;
|
||||
}
|
||||
else {
|
||||
const blender::OffsetIndices faces = b_mesh.faces();
|
||||
for (const int i : faces.index_range()) {
|
||||
numngons += (faces[i].size() == 4) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate memory */
|
||||
if (subdivision) {
|
||||
mesh->resize_subd_faces(numfaces, numngons, corner_verts.size());
|
||||
mesh->resize_subd_faces(numfaces, corner_verts.size());
|
||||
}
|
||||
mesh->resize_mesh(positions.size(), numtris);
|
||||
|
||||
@@ -884,7 +871,6 @@ static void create_mesh(Scene *scene,
|
||||
const float(*orco)[3] = static_cast<const float(*)[3]>(
|
||||
CustomData_get_layer(&b_mesh.vert_data, CD_ORCO));
|
||||
Attribute *attr = attributes.add(ATTR_STD_GENERATED);
|
||||
attr->flags |= ATTR_SUBDIVIDED;
|
||||
|
||||
float3 loc;
|
||||
float3 size;
|
||||
@@ -1023,7 +1009,7 @@ static void create_mesh(Scene *scene,
|
||||
attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale);
|
||||
|
||||
if (subdivision) {
|
||||
attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs, blender_uv_names);
|
||||
attr_create_subd_uv_map(scene, mesh, b_mesh, blender_uv_names);
|
||||
}
|
||||
else {
|
||||
attr_create_uv_map(scene, mesh, b_mesh, blender_uv_names);
|
||||
|
||||
@@ -443,14 +443,12 @@ void HdCyclesMesh::PopulateTopology(HdSceneDelegate *sceneDelegate)
|
||||
const PxOsdSubdivTags subdivTags = GetSubdivTags(sceneDelegate);
|
||||
_topology.SetSubdivTags(subdivTags);
|
||||
|
||||
size_t numNgons = 0;
|
||||
size_t numCorners = 0;
|
||||
for (const int vertCount : vertCounts) {
|
||||
numNgons += (vertCount == 4) ? 0 : 1;
|
||||
numCorners += vertCount;
|
||||
}
|
||||
|
||||
_geom->reserve_subd_faces(_topology.GetNumFaces(), numNgons, numCorners);
|
||||
_geom->reserve_subd_faces(_topology.GetNumFaces(), numCorners);
|
||||
|
||||
// TODO: Handle hole indices
|
||||
size_t faceIndex = 0;
|
||||
|
||||
@@ -248,12 +248,10 @@ set(SRC_KERNEL_GEOM_HEADERS
|
||||
geom/motion_triangle_intersect.h
|
||||
geom/motion_triangle_shader.h
|
||||
geom/object.h
|
||||
geom/patch.h
|
||||
geom/point.h
|
||||
geom/point_intersect.h
|
||||
geom/primitive.h
|
||||
geom/shader_data.h
|
||||
geom/subd_triangle.h
|
||||
geom/triangle.h
|
||||
geom/triangle_intersect.h
|
||||
geom/volume.h
|
||||
|
||||
@@ -33,8 +33,6 @@ KERNEL_DATA_ARRAY(DecomposedTransform, camera_motion)
|
||||
KERNEL_DATA_ARRAY(uint, tri_shader)
|
||||
KERNEL_DATA_ARRAY(packed_float3, tri_vnormal)
|
||||
KERNEL_DATA_ARRAY(packed_uint3, tri_vindex)
|
||||
KERNEL_DATA_ARRAY(uint, tri_patch)
|
||||
KERNEL_DATA_ARRAY(float2, tri_patch_uv)
|
||||
KERNEL_DATA_ARRAY(packed_float3, tri_verts)
|
||||
|
||||
/* curves */
|
||||
@@ -42,9 +40,6 @@ KERNEL_DATA_ARRAY(KernelCurve, curves)
|
||||
KERNEL_DATA_ARRAY(float4, curve_keys)
|
||||
KERNEL_DATA_ARRAY(KernelCurveSegment, curve_segments)
|
||||
|
||||
/* patches */
|
||||
KERNEL_DATA_ARRAY(uint, patches)
|
||||
|
||||
/* pointclouds */
|
||||
KERNEL_DATA_ARRAY(float4, points)
|
||||
KERNEL_DATA_ARRAY(uint, points_shader)
|
||||
|
||||
@@ -20,25 +20,9 @@ CCL_NAMESPACE_BEGIN
|
||||
* Lookup of attributes is different between OSL and SVM, as OSL is ustring
|
||||
* based while for SVM we use integer ids. */
|
||||
|
||||
/* Patch index for triangle, -1 if not subdivision triangle */
|
||||
|
||||
ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, const int prim)
|
||||
{
|
||||
return (prim != PRIM_NONE) ? kernel_data_fetch(tri_patch, prim) : ~0;
|
||||
}
|
||||
|
||||
ccl_device_inline uint attribute_primitive_type(KernelGlobals kg, const int prim, const int type)
|
||||
{
|
||||
if ((type & PRIMITIVE_TRIANGLE) && subd_triangle_patch(kg, prim) != ~0) {
|
||||
return ATTR_PRIM_SUBD;
|
||||
}
|
||||
return ATTR_PRIM_GEOMETRY;
|
||||
}
|
||||
|
||||
ccl_device_inline AttributeDescriptor attribute_not_found()
|
||||
{
|
||||
const AttributeDescriptor desc = {
|
||||
ATTR_ELEMENT_NONE, (NodeAttributeType)0, 0, ATTR_STD_NOT_FOUND};
|
||||
const AttributeDescriptor desc = {ATTR_ELEMENT_NONE, (NodeAttributeType)0, ATTR_STD_NOT_FOUND};
|
||||
return desc;
|
||||
}
|
||||
|
||||
@@ -49,8 +33,10 @@ ccl_device_inline uint object_attribute_map_offset(KernelGlobals kg, const int o
|
||||
return kernel_data_fetch(objects, object).attribute_map_offset;
|
||||
}
|
||||
|
||||
ccl_device_inline AttributeDescriptor find_attribute(
|
||||
KernelGlobals kg, const int object, const int prim, const int type, const uint64_t id)
|
||||
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
|
||||
const int object,
|
||||
const int prim,
|
||||
const uint64_t id)
|
||||
{
|
||||
if (object == OBJECT_NONE) {
|
||||
return attribute_not_found();
|
||||
@@ -58,7 +44,6 @@ ccl_device_inline AttributeDescriptor find_attribute(
|
||||
|
||||
/* for SVM, find attribute by unique id */
|
||||
uint attr_offset = object_attribute_map_offset(kg, object);
|
||||
attr_offset += attribute_primitive_type(kg, prim, type);
|
||||
AttributeMap attr_map = kernel_data_fetch(attributes_map, attr_offset);
|
||||
|
||||
while (attr_map.id != id) {
|
||||
@@ -88,7 +73,6 @@ ccl_device_inline AttributeDescriptor find_attribute(
|
||||
desc.offset = (attr_map.element == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND :
|
||||
attr_map.offset;
|
||||
desc.type = (NodeAttributeType)attr_map.type;
|
||||
desc.flags = (AttributeFlag)attr_map.flags;
|
||||
|
||||
return desc;
|
||||
}
|
||||
@@ -97,7 +81,7 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
|
||||
const ccl_private ShaderData *sd,
|
||||
const uint64_t id)
|
||||
{
|
||||
return find_attribute(kg, sd->object, sd->prim, sd->type, id);
|
||||
return find_attribute(kg, sd->object, sd->prim, id);
|
||||
}
|
||||
|
||||
/* Templated functions to read from the attribute data */
|
||||
|
||||
@@ -351,17 +351,6 @@ ccl_device_inline float3 object_dupli_uv(KernelGlobals kg, const int object)
|
||||
return make_float3(kobject->dupli_uv[0], kobject->dupli_uv[1], 0.0f);
|
||||
}
|
||||
|
||||
/* Offset to an objects patch map */
|
||||
|
||||
ccl_device_inline uint object_patch_map_offset(KernelGlobals kg, const int object)
|
||||
{
|
||||
if (object == OBJECT_NONE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return kernel_data_fetch(objects, object).patch_map_offset;
|
||||
}
|
||||
|
||||
/* Volume step size */
|
||||
|
||||
ccl_device_inline float object_volume_density(KernelGlobals kg, const int object)
|
||||
|
||||
@@ -1,319 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2013 Pixar
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/** \file
|
||||
* Based on code from OpenSubdiv.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
|
||||
#include "kernel/geom/object.h"
|
||||
|
||||
#include "util/color.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct PatchHandle {
|
||||
int array_index, patch_index, vert_index;
|
||||
};
|
||||
|
||||
ccl_device_inline int patch_map_resolve_quadrant(const float median,
|
||||
ccl_private float *u,
|
||||
ccl_private float *v)
|
||||
{
|
||||
int quadrant = -1;
|
||||
|
||||
if (*u < median) {
|
||||
if (*v < median) {
|
||||
quadrant = 0;
|
||||
}
|
||||
else {
|
||||
quadrant = 1;
|
||||
*v -= median;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (*v < median) {
|
||||
quadrant = 3;
|
||||
}
|
||||
else {
|
||||
quadrant = 2;
|
||||
*v -= median;
|
||||
}
|
||||
*u -= median;
|
||||
}
|
||||
|
||||
return quadrant;
|
||||
}
|
||||
|
||||
/* retrieve PatchHandle from patch coords */
|
||||
|
||||
ccl_device_inline PatchHandle
|
||||
patch_map_find_patch(KernelGlobals kg, const int object, const int patch, float u, float v)
|
||||
{
|
||||
PatchHandle handle;
|
||||
|
||||
// TODO: temporarily disabled due to slight inaccuracies on ARM.
|
||||
// kernel_assert((u >= 0.0f) && (u <= 1.0f) && (v >= 0.0f) && (v <= 1.0f));
|
||||
|
||||
int node = (object_patch_map_offset(kg, object) + patch) / 2;
|
||||
float median = 0.5f;
|
||||
|
||||
for (int depth = 0; depth < 0xff; depth++) {
|
||||
const float delta = median * 0.5f;
|
||||
|
||||
const int quadrant = patch_map_resolve_quadrant(median, &u, &v);
|
||||
kernel_assert(quadrant >= 0);
|
||||
|
||||
const uint child = kernel_data_fetch(patches, node + quadrant);
|
||||
|
||||
/* is the quadrant a hole? */
|
||||
if (!(child & PATCH_MAP_NODE_IS_SET)) {
|
||||
handle.array_index = -1;
|
||||
return handle;
|
||||
}
|
||||
|
||||
const uint index = child & PATCH_MAP_NODE_INDEX_MASK;
|
||||
|
||||
if (child & PATCH_MAP_NODE_IS_LEAF) {
|
||||
handle.array_index = kernel_data_fetch(patches, index + 0);
|
||||
handle.patch_index = kernel_data_fetch(patches, index + 1);
|
||||
handle.vert_index = kernel_data_fetch(patches, index + 2);
|
||||
|
||||
return handle;
|
||||
}
|
||||
node = index;
|
||||
|
||||
median = delta;
|
||||
}
|
||||
|
||||
/* no leaf found */
|
||||
kernel_assert(0);
|
||||
|
||||
handle.array_index = -1;
|
||||
return handle;
|
||||
}
|
||||
|
||||
ccl_device_inline void patch_eval_bspline_weights(const float t,
|
||||
ccl_private float *point,
|
||||
ccl_private float *deriv)
|
||||
{
|
||||
/* The four uniform cubic B-Spline basis functions evaluated at t */
|
||||
const float inv_6 = 1.0f / 6.0f;
|
||||
|
||||
const float t2 = t * t;
|
||||
const float t3 = t * t2;
|
||||
|
||||
point[0] = inv_6 * (1.0f - 3.0f * (t - t2) - t3);
|
||||
point[1] = inv_6 * (4.0f - 6.0f * t2 + 3.0f * t3);
|
||||
point[2] = inv_6 * (1.0f + 3.0f * (t + t2 - t3));
|
||||
point[3] = inv_6 * t3;
|
||||
|
||||
/* Derivatives of the above four basis functions at t */
|
||||
deriv[0] = -0.5f * t2 + t - 0.5f;
|
||||
deriv[1] = 1.5f * t2 - 2.0f * t;
|
||||
deriv[2] = -1.5f * t2 + t + 0.5f;
|
||||
deriv[3] = 0.5f * t2;
|
||||
}
|
||||
|
||||
ccl_device_inline void patch_eval_adjust_boundary_weights(const uint bits,
|
||||
ccl_private float *s,
|
||||
ccl_private float *t)
|
||||
{
|
||||
const int boundary = ((bits >> 8) & 0xf);
|
||||
|
||||
if (boundary & 1) {
|
||||
t[2] -= t[0];
|
||||
t[1] += 2 * t[0];
|
||||
t[0] = 0;
|
||||
}
|
||||
|
||||
if (boundary & 2) {
|
||||
s[1] -= s[3];
|
||||
s[2] += 2 * s[3];
|
||||
s[3] = 0;
|
||||
}
|
||||
|
||||
if (boundary & 4) {
|
||||
t[1] -= t[3];
|
||||
t[2] += 2 * t[3];
|
||||
t[3] = 0;
|
||||
}
|
||||
|
||||
if (boundary & 8) {
|
||||
s[2] -= s[0];
|
||||
s[1] += 2 * s[0];
|
||||
s[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_inline int patch_eval_depth(const uint patch_bits)
|
||||
{
|
||||
return (patch_bits & 0xf);
|
||||
}
|
||||
|
||||
ccl_device_inline float patch_eval_param_fraction(const uint patch_bits)
|
||||
{
|
||||
const bool non_quad_root = (patch_bits >> 4) & 0x1;
|
||||
const int depth = patch_eval_depth(patch_bits);
|
||||
|
||||
if (non_quad_root) {
|
||||
return 1.0f / (float)(1 << (depth - 1));
|
||||
}
|
||||
return 1.0f / (float)(1 << depth);
|
||||
}
|
||||
|
||||
ccl_device_inline void patch_eval_normalize_coords(const uint patch_bits,
|
||||
ccl_private float *u,
|
||||
ccl_private float *v)
|
||||
{
|
||||
const float frac = patch_eval_param_fraction(patch_bits);
|
||||
|
||||
const int iu = (patch_bits >> 22) & 0x3ff;
|
||||
const int iv = (patch_bits >> 12) & 0x3ff;
|
||||
|
||||
/* top left corner */
|
||||
const float pu = (float)iu * frac;
|
||||
const float pv = (float)iv * frac;
|
||||
|
||||
/* normalize uv coordinates */
|
||||
*u = (*u - pu) / frac;
|
||||
*v = (*v - pv) / frac;
|
||||
}
|
||||
|
||||
/* retrieve patch control indices */
|
||||
|
||||
ccl_device_inline int patch_eval_indices(KernelGlobals kg,
|
||||
const ccl_private PatchHandle *handle,
|
||||
int /*channel*/,
|
||||
int indices[PATCH_MAX_CONTROL_VERTS])
|
||||
{
|
||||
const int index_base = kernel_data_fetch(patches, handle->array_index + 2) + handle->vert_index;
|
||||
|
||||
/* XXX: regular patches only */
|
||||
for (int i = 0; i < 16; i++) {
|
||||
indices[i] = kernel_data_fetch(patches, index_base + i);
|
||||
}
|
||||
|
||||
return 16;
|
||||
}
|
||||
|
||||
/* evaluate patch basis functions */
|
||||
|
||||
ccl_device_inline void patch_eval_basis(KernelGlobals kg,
|
||||
const ccl_private PatchHandle *handle,
|
||||
float u,
|
||||
float v,
|
||||
float weights[PATCH_MAX_CONTROL_VERTS],
|
||||
float weights_du[PATCH_MAX_CONTROL_VERTS],
|
||||
float weights_dv[PATCH_MAX_CONTROL_VERTS])
|
||||
{
|
||||
const uint patch_bits = kernel_data_fetch(patches,
|
||||
handle->patch_index + 1); /* read patch param */
|
||||
float d_scale = 1 << patch_eval_depth(patch_bits);
|
||||
|
||||
const bool non_quad_root = (patch_bits >> 4) & 0x1;
|
||||
if (non_quad_root) {
|
||||
d_scale *= 0.5f;
|
||||
}
|
||||
|
||||
patch_eval_normalize_coords(patch_bits, &u, &v);
|
||||
|
||||
/* XXX: regular patches only for now. */
|
||||
|
||||
float s[4];
|
||||
float t[4];
|
||||
float ds[4];
|
||||
float dt[4];
|
||||
|
||||
patch_eval_bspline_weights(u, s, ds);
|
||||
patch_eval_bspline_weights(v, t, dt);
|
||||
|
||||
patch_eval_adjust_boundary_weights(patch_bits, s, t);
|
||||
patch_eval_adjust_boundary_weights(patch_bits, ds, dt);
|
||||
|
||||
for (int k = 0; k < 4; k++) {
|
||||
for (int l = 0; l < 4; l++) {
|
||||
weights[4 * k + l] = s[l] * t[k];
|
||||
weights_du[4 * k + l] = ds[l] * t[k] * d_scale;
|
||||
weights_dv[4 * k + l] = s[l] * dt[k] * d_scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* generic function for evaluating indices and weights from patch coords */
|
||||
|
||||
ccl_device_inline int patch_eval_control_verts(KernelGlobals kg,
|
||||
const int object,
|
||||
const int patch,
|
||||
const float u,
|
||||
const float v,
|
||||
const int channel,
|
||||
int indices[PATCH_MAX_CONTROL_VERTS],
|
||||
float weights[PATCH_MAX_CONTROL_VERTS],
|
||||
float weights_du[PATCH_MAX_CONTROL_VERTS],
|
||||
float weights_dv[PATCH_MAX_CONTROL_VERTS])
|
||||
{
|
||||
const PatchHandle handle = patch_map_find_patch(kg, object, patch, u, v);
|
||||
kernel_assert(handle.array_index >= 0);
|
||||
|
||||
const int num_control = patch_eval_indices(kg, &handle, channel, indices);
|
||||
patch_eval_basis(kg, &handle, u, v, weights, weights_du, weights_dv);
|
||||
|
||||
return num_control;
|
||||
}
|
||||
|
||||
/* functions for evaluating attributes on patches */
|
||||
|
||||
template<typename T, bool is_uchar>
|
||||
ccl_device T patch_eval(KernelGlobals kg,
|
||||
const ccl_private ShaderData *sd,
|
||||
const int offset,
|
||||
const int patch,
|
||||
const float u,
|
||||
const float v,
|
||||
const int channel,
|
||||
ccl_private T *du,
|
||||
ccl_private T *dv)
|
||||
{
|
||||
int indices[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights_du[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights_dv[PATCH_MAX_CONTROL_VERTS];
|
||||
|
||||
const int num_control = patch_eval_control_verts(
|
||||
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
|
||||
|
||||
T val = make_zero<T>();
|
||||
if (du) {
|
||||
*du = make_zero<T>();
|
||||
}
|
||||
if (dv) {
|
||||
*dv = make_zero<T>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_control; i++) {
|
||||
T v;
|
||||
if (is_uchar) {
|
||||
v = attribute_data_fetch_bytecolor<T>(kg, offset + indices[i]);
|
||||
}
|
||||
else {
|
||||
v = attribute_data_fetch<T>(kg, offset + indices[i]);
|
||||
}
|
||||
|
||||
val += v * weights[i];
|
||||
if (du) {
|
||||
*du += v * weights_du[i];
|
||||
}
|
||||
if (dv) {
|
||||
*dv += v * weights_dv[i];
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "kernel/geom/curve.h"
|
||||
#include "kernel/geom/object.h"
|
||||
#include "kernel/geom/point.h"
|
||||
#include "kernel/geom/subd_triangle.h"
|
||||
#include "kernel/geom/triangle.h"
|
||||
#include "kernel/geom/volume.h"
|
||||
|
||||
@@ -48,10 +47,7 @@ ccl_device_forceinline T primitive_surface_attribute(KernelGlobals kg,
|
||||
}
|
||||
|
||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||
if (subd_triangle_patch(kg, sd->prim) == ~0) {
|
||||
return triangle_attribute<T>(kg, sd, desc, dfdx, dfdy);
|
||||
}
|
||||
return subd_triangle_attribute<T>(kg, sd, desc, dfdx, dfdy);
|
||||
return triangle_attribute<T>(kg, sd, desc, dfdx, dfdy);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
if (sd->type & PRIMITIVE_CURVE) {
|
||||
@@ -232,16 +228,9 @@ ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg,
|
||||
if (sd->type & PRIMITIVE_TRIANGLE)
|
||||
{
|
||||
/* Triangle */
|
||||
if (subd_triangle_patch(kg, sd->prim) == ~0) {
|
||||
motion_pre = triangle_attribute<float3>(kg, sd, desc, nullptr, nullptr);
|
||||
desc.offset += numverts;
|
||||
motion_post = triangle_attribute<float3>(kg, sd, desc, nullptr, nullptr);
|
||||
}
|
||||
else {
|
||||
motion_pre = subd_triangle_attribute<float3>(kg, sd, desc, nullptr, nullptr);
|
||||
desc.offset += numverts;
|
||||
motion_post = subd_triangle_attribute<float3>(kg, sd, desc, nullptr, nullptr);
|
||||
}
|
||||
motion_pre = triangle_attribute<float3>(kg, sd, desc, nullptr, nullptr);
|
||||
desc.offset += numverts;
|
||||
motion_post = triangle_attribute<float3>(kg, sd, desc, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Functions for retrieving attributes on triangles produced from subdivision meshes */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
#include "kernel/types.h"
|
||||
|
||||
#include "kernel/geom/attribute.h"
|
||||
#include "kernel/geom/patch.h"
|
||||
#include "kernel/geom/triangle.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* UV coords of triangle within patch */
|
||||
|
||||
ccl_device_inline void subd_triangle_patch_uv(KernelGlobals kg,
|
||||
const ccl_private ShaderData *sd,
|
||||
float2 uv[3])
|
||||
{
|
||||
const uint3 tri_vindex = kernel_data_fetch(tri_vindex, sd->prim);
|
||||
|
||||
uv[0] = kernel_data_fetch(tri_patch_uv, tri_vindex.x);
|
||||
uv[1] = kernel_data_fetch(tri_patch_uv, tri_vindex.y);
|
||||
uv[2] = kernel_data_fetch(tri_patch_uv, tri_vindex.z);
|
||||
}
|
||||
|
||||
/* Vertex indices of patch */
|
||||
|
||||
ccl_device_inline uint4 subd_triangle_patch_indices(KernelGlobals kg, const int patch)
|
||||
{
|
||||
uint4 indices;
|
||||
|
||||
indices.x = kernel_data_fetch(patches, patch + 0);
|
||||
indices.y = kernel_data_fetch(patches, patch + 1);
|
||||
indices.z = kernel_data_fetch(patches, patch + 2);
|
||||
indices.w = kernel_data_fetch(patches, patch + 3);
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
/* Originating face for patch */
|
||||
|
||||
ccl_device_inline uint subd_triangle_patch_face(KernelGlobals kg, const int patch)
|
||||
{
|
||||
return kernel_data_fetch(patches, patch + 4);
|
||||
}
|
||||
|
||||
/* Number of corners on originating face */
|
||||
|
||||
ccl_device_inline uint subd_triangle_patch_num_corners(KernelGlobals kg, const int patch)
|
||||
{
|
||||
return kernel_data_fetch(patches, patch + 5) & 0xffff;
|
||||
}
|
||||
|
||||
/* Indices of the four corners that are used by the patch */
|
||||
|
||||
ccl_device_inline void subd_triangle_patch_corners(KernelGlobals kg,
|
||||
const int patch,
|
||||
int corners[4])
|
||||
{
|
||||
uint4 data;
|
||||
|
||||
data.x = kernel_data_fetch(patches, patch + 4);
|
||||
data.y = kernel_data_fetch(patches, patch + 5);
|
||||
data.z = kernel_data_fetch(patches, patch + 6);
|
||||
data.w = kernel_data_fetch(patches, patch + 7);
|
||||
|
||||
const int num_corners = data.y & 0xffff;
|
||||
|
||||
if (num_corners == 4) {
|
||||
/* quad */
|
||||
corners[0] = data.z;
|
||||
corners[1] = data.z + 1;
|
||||
corners[2] = data.z + 2;
|
||||
corners[3] = data.z + 3;
|
||||
}
|
||||
else {
|
||||
/* ngon */
|
||||
const int c = data.y >> 16;
|
||||
|
||||
corners[0] = data.z + c;
|
||||
corners[1] = data.z + mod(c + 1, num_corners);
|
||||
corners[2] = data.w;
|
||||
corners[3] = data.z + mod(c - 1, num_corners);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ccl_device_inline void subd_triangle_attribute_df(const ccl_private differential &du,
|
||||
const ccl_private differential &dv,
|
||||
const ccl_private T &dads,
|
||||
const ccl_private T &dadt,
|
||||
const float2 dpdu,
|
||||
const float2 dpdv,
|
||||
ccl_private T *dfdx,
|
||||
ccl_private T *dfdy)
|
||||
{
|
||||
if (!(dfdx || dfdy)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float dsdu = dpdu.x;
|
||||
const float dtdu = dpdu.y;
|
||||
const float dsdv = dpdv.x;
|
||||
const float dtdv = dpdv.y;
|
||||
|
||||
if (dfdx) {
|
||||
const float dudx = du.dx;
|
||||
const float dvdx = dv.dx;
|
||||
|
||||
const float dsdx = dsdu * dudx + dsdv * dvdx;
|
||||
const float dtdx = dtdu * dudx + dtdv * dvdx;
|
||||
|
||||
*dfdx = dads * dsdx + dadt * dtdx;
|
||||
}
|
||||
if (dfdy) {
|
||||
const float dudy = du.dy;
|
||||
const float dvdy = dv.dy;
|
||||
|
||||
const float dsdy = dsdu * dudy + dsdv * dvdy;
|
||||
const float dtdy = dtdu * dudy + dtdv * dvdy;
|
||||
|
||||
*dfdy = dads * dsdy + dadt * dtdy;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reading attributes on various subdivision triangle elements */
|
||||
|
||||
template<typename T>
|
||||
ccl_device_noinline T subd_triangle_attribute(KernelGlobals kg,
|
||||
const ccl_private ShaderData *sd,
|
||||
const AttributeDescriptor desc,
|
||||
ccl_private T *dfdx,
|
||||
ccl_private T *dfdy)
|
||||
{
|
||||
const int patch = subd_triangle_patch(kg, sd->prim);
|
||||
|
||||
#ifdef __PATCH_EVAL__
|
||||
if (desc.flags & ATTR_SUBDIVIDED) {
|
||||
float2 uv[3];
|
||||
subd_triangle_patch_uv(kg, sd, uv);
|
||||
|
||||
const float2 dpdu = uv[1] - uv[0];
|
||||
const float2 dpdv = uv[2] - uv[0];
|
||||
|
||||
/* p is [s, t] */
|
||||
const float2 p = dpdu * sd->u + dpdv * sd->v + uv[0];
|
||||
|
||||
T a;
|
||||
T dads;
|
||||
T dadt;
|
||||
if (desc.type == NODE_ATTR_RGBA) {
|
||||
a = patch_eval<T, true>(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
|
||||
}
|
||||
else {
|
||||
a = patch_eval<T, false>(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
|
||||
}
|
||||
|
||||
# ifdef __RAY_DIFFERENTIALS__
|
||||
subd_triangle_attribute_df(sd->du, sd->dv, dads, dadt, dpdu, dpdv, dfdx, dfdy);
|
||||
# endif
|
||||
|
||||
return a;
|
||||
}
|
||||
#endif /* __PATCH_EVAL__ */
|
||||
if (desc.element == ATTR_ELEMENT_FACE) {
|
||||
if (dfdx) {
|
||||
*dfdx = make_zero<T>();
|
||||
}
|
||||
if (dfdy) {
|
||||
*dfdy = make_zero<T>();
|
||||
}
|
||||
|
||||
return attribute_data_fetch<T>(kg, desc.offset + subd_triangle_patch_face(kg, patch));
|
||||
}
|
||||
if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
|
||||
float2 uv[3];
|
||||
subd_triangle_patch_uv(kg, sd, uv);
|
||||
|
||||
const uint4 v = subd_triangle_patch_indices(kg, patch);
|
||||
|
||||
const T f0 = attribute_data_fetch<T>(kg, desc.offset + v.x);
|
||||
T f1 = attribute_data_fetch<T>(kg, desc.offset + v.y);
|
||||
const T f2 = attribute_data_fetch<T>(kg, desc.offset + v.z);
|
||||
T f3 = attribute_data_fetch<T>(kg, desc.offset + v.w);
|
||||
|
||||
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
|
||||
f1 = (f1 + f0) * 0.5f;
|
||||
f3 = (f3 + f0) * 0.5f;
|
||||
}
|
||||
|
||||
const T a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
||||
const T b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
||||
const T c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if (dfdx) {
|
||||
*dfdx = triangle_attribute_dfdx(sd->du, sd->dv, a, b, c);
|
||||
}
|
||||
if (dfdy) {
|
||||
*dfdy = triangle_attribute_dfdy(sd->du, sd->dv, a, b, c);
|
||||
}
|
||||
#endif
|
||||
|
||||
return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a;
|
||||
}
|
||||
if (desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
float2 uv[3];
|
||||
subd_triangle_patch_uv(kg, sd, uv);
|
||||
|
||||
int corners[4];
|
||||
subd_triangle_patch_corners(kg, patch, corners);
|
||||
|
||||
T f0;
|
||||
T f1;
|
||||
T f2;
|
||||
T f3;
|
||||
|
||||
if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
f0 = attribute_data_fetch_bytecolor<T>(kg, corners[0] + desc.offset);
|
||||
f1 = attribute_data_fetch_bytecolor<T>(kg, corners[1] + desc.offset);
|
||||
f2 = attribute_data_fetch_bytecolor<T>(kg, corners[2] + desc.offset);
|
||||
f3 = attribute_data_fetch_bytecolor<T>(kg, corners[3] + desc.offset);
|
||||
}
|
||||
else {
|
||||
f0 = attribute_data_fetch<T>(kg, corners[0] + desc.offset);
|
||||
f1 = attribute_data_fetch<T>(kg, corners[1] + desc.offset);
|
||||
f2 = attribute_data_fetch<T>(kg, corners[2] + desc.offset);
|
||||
f3 = attribute_data_fetch<T>(kg, corners[3] + desc.offset);
|
||||
}
|
||||
|
||||
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
|
||||
f1 = (f1 + f0) * 0.5f;
|
||||
f3 = (f3 + f0) * 0.5f;
|
||||
}
|
||||
|
||||
const T a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
||||
const T b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
||||
const T c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if (dfdx) {
|
||||
*dfdx = triangle_attribute_dfdx(sd->du, sd->dv, a, b, c);
|
||||
}
|
||||
if (dfdy) {
|
||||
*dfdy = triangle_attribute_dfdy(sd->du, sd->dv, a, b, c);
|
||||
}
|
||||
#endif
|
||||
|
||||
return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a;
|
||||
}
|
||||
|
||||
if (dfdx) {
|
||||
*dfdx = make_zero<T>();
|
||||
}
|
||||
if (dfdy) {
|
||||
*dfdy = make_zero<T>();
|
||||
}
|
||||
return make_zero<T>();
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
@@ -982,8 +982,7 @@ bool OSLRenderServices::get_attribute(OSL::ShaderGlobals *sg,
|
||||
}
|
||||
|
||||
/* find attribute on object */
|
||||
const AttributeDescriptor desc = find_attribute(
|
||||
kg, object, sd->prim, object == sd->object ? sd->type : PRIMITIVE_NONE, name.hash());
|
||||
const AttributeDescriptor desc = find_attribute(kg, object, sd->prim, name.hash());
|
||||
if (desc.offset != ATTR_STD_NOT_FOUND) {
|
||||
return get_object_attribute(kg, sd, desc, type, derivatives, val);
|
||||
}
|
||||
|
||||
@@ -1383,7 +1383,7 @@ ccl_device_extern bool osl_get_attribute(ccl_private ShaderGlobals *sg,
|
||||
object = sd->object;
|
||||
}
|
||||
|
||||
const AttributeDescriptor desc = find_attribute(kg, object, sd->prim, sd->type, name);
|
||||
const AttributeDescriptor desc = find_attribute(kg, object, sd->prim, name);
|
||||
if (desc.offset != ATTR_STD_NOT_FOUND) {
|
||||
return get_object_attribute(kg, sd, desc, type, derivatives, res);
|
||||
}
|
||||
|
||||
@@ -102,40 +102,37 @@ enum {
|
||||
/* Use volume materials. */
|
||||
KERNEL_FEATURE_VOLUME = (1U << 17U),
|
||||
|
||||
/* Use OpenSubdiv patch evaluation */
|
||||
KERNEL_FEATURE_PATCH_EVALUATION = (1U << 18U),
|
||||
|
||||
/* Use Transparent shadows */
|
||||
KERNEL_FEATURE_TRANSPARENT = (1U << 19U),
|
||||
KERNEL_FEATURE_TRANSPARENT = (1U << 18U),
|
||||
|
||||
/* Use shadow catcher. */
|
||||
KERNEL_FEATURE_SHADOW_CATCHER = (1U << 20U),
|
||||
KERNEL_FEATURE_SHADOW_CATCHER = (1U << 19U),
|
||||
|
||||
/* Light render passes. */
|
||||
KERNEL_FEATURE_LIGHT_PASSES = (1U << 21U),
|
||||
KERNEL_FEATURE_LIGHT_PASSES = (1U << 20U),
|
||||
|
||||
/* AO. */
|
||||
KERNEL_FEATURE_AO_PASS = (1U << 22U),
|
||||
KERNEL_FEATURE_AO_ADDITIVE = (1U << 23U),
|
||||
KERNEL_FEATURE_AO_PASS = (1U << 21U),
|
||||
KERNEL_FEATURE_AO_ADDITIVE = (1U << 22U),
|
||||
|
||||
/* MNEE. */
|
||||
KERNEL_FEATURE_MNEE = (1U << 24U),
|
||||
KERNEL_FEATURE_MNEE = (1U << 23U),
|
||||
|
||||
/* Path guiding. */
|
||||
KERNEL_FEATURE_PATH_GUIDING = (1U << 25U),
|
||||
KERNEL_FEATURE_PATH_GUIDING = (1U << 24U),
|
||||
|
||||
/* OSL. */
|
||||
KERNEL_FEATURE_OSL = (1U << 26U),
|
||||
KERNEL_FEATURE_OSL = (1U << 25U),
|
||||
|
||||
/* Light and shadow linking. */
|
||||
KERNEL_FEATURE_LIGHT_LINKING = (1U << 27U),
|
||||
KERNEL_FEATURE_SHADOW_LINKING = (1U << 28U),
|
||||
KERNEL_FEATURE_LIGHT_LINKING = (1U << 26U),
|
||||
KERNEL_FEATURE_SHADOW_LINKING = (1U << 27U),
|
||||
|
||||
/* Use denoising kernels and output denoising passes. */
|
||||
KERNEL_FEATURE_DENOISING = (1U << 29U),
|
||||
KERNEL_FEATURE_DENOISING = (1U << 28U),
|
||||
|
||||
/* Light tree. */
|
||||
KERNEL_FEATURE_LIGHT_TREE = (1U << 30U)
|
||||
KERNEL_FEATURE_LIGHT_TREE = (1U << 29U)
|
||||
};
|
||||
|
||||
#define KERNEL_FEATURE_AO (KERNEL_FEATURE_AO_PASS | KERNEL_FEATURE_AO_ADDITIVE)
|
||||
@@ -188,7 +185,6 @@ enum {
|
||||
#define __OBJECT_MOTION__
|
||||
#define __MNEE__
|
||||
#define __PASSES__
|
||||
#define __PATCH_EVAL__
|
||||
#define __POINTCLOUD__
|
||||
#define __PRINCIPLED_HAIR__
|
||||
#define __RAY_DIFFERENTIALS__
|
||||
@@ -244,9 +240,6 @@ enum {
|
||||
# if !(__KERNEL_FEATURES__ & KERNEL_FEATURE_SUBSURFACE)
|
||||
# undef __SUBSURFACE__
|
||||
# endif
|
||||
# if !(__KERNEL_FEATURES__ & KERNEL_FEATURE_PATCH_EVALUATION)
|
||||
# undef __PATCH_EVAL__
|
||||
# endif
|
||||
# if !(__KERNEL_FEATURES__ & KERNEL_FEATURE_SHADOW_CATCHER)
|
||||
# undef __SHADOW_CATCHER__
|
||||
# endif
|
||||
@@ -916,14 +909,13 @@ enum AttributeStandard {
|
||||
};
|
||||
|
||||
enum AttributeFlag {
|
||||
ATTR_FINAL_SIZE = (1 << 0),
|
||||
ATTR_SUBDIVIDED = (1 << 1),
|
||||
ATTR_SUBDIVIDE_SMOOTH_FVAR = (1 << 0), /* This attribute is face-varying and requirs smooth
|
||||
* subdivision (typically UV map). */
|
||||
};
|
||||
|
||||
struct AttributeDescriptor {
|
||||
AttributeElement element;
|
||||
NodeAttributeType type;
|
||||
uint flags; /* see enum AttributeFlag */
|
||||
int offset;
|
||||
};
|
||||
|
||||
@@ -933,7 +925,7 @@ struct AttributeMap {
|
||||
int offset; /* Offset into __attributes global arrays. */
|
||||
uint16_t element; /* AttributeElement. */
|
||||
uint8_t type; /* NodeAttributeType. */
|
||||
uint8_t flags; /* AttributeFlag. */
|
||||
uint8_t pad;
|
||||
};
|
||||
|
||||
/* Closure data */
|
||||
@@ -1041,7 +1033,7 @@ enum ShaderDataFlag {
|
||||
|
||||
/* Shader flags. */
|
||||
|
||||
/* Apply a correction term to smooth illumination on grazing angles when using bump mapping.. */
|
||||
/* Apply a correction term to smooth illumination on grazing angles when using bump mapping. */
|
||||
SD_USE_BUMP_MAP_CORRECTION = (1 << 15),
|
||||
/* Use front side for direct light sampling. */
|
||||
SD_MIS_FRONT = (1 << 16),
|
||||
@@ -1523,7 +1515,6 @@ struct KernelObject {
|
||||
int num_tfm_steps;
|
||||
int numverts;
|
||||
|
||||
uint patch_map_offset;
|
||||
uint attribute_map_offset;
|
||||
uint motion_offset;
|
||||
|
||||
@@ -1543,8 +1534,6 @@ struct KernelObject {
|
||||
/* Volume velocity scale. */
|
||||
float velocity_scale;
|
||||
|
||||
int pad[3];
|
||||
|
||||
/* TODO: separate array to avoid memory overhead when not used. */
|
||||
uint64_t light_set_membership;
|
||||
uint receiver_light_set;
|
||||
|
||||
@@ -76,7 +76,6 @@ void CachedData::clear()
|
||||
curve_keys.clear();
|
||||
curve_radius.clear();
|
||||
curve_shader.clear();
|
||||
num_ngons.clear();
|
||||
shader.clear();
|
||||
subd_creases_edge.clear();
|
||||
subd_creases_weight.clear();
|
||||
@@ -126,7 +125,6 @@ bool CachedData::is_constant() const
|
||||
CHECK_IF_CONSTANT(curve_keys)
|
||||
CHECK_IF_CONSTANT(curve_radius)
|
||||
CHECK_IF_CONSTANT(curve_shader)
|
||||
CHECK_IF_CONSTANT(num_ngons)
|
||||
CHECK_IF_CONSTANT(shader)
|
||||
CHECK_IF_CONSTANT(subd_creases_edge)
|
||||
CHECK_IF_CONSTANT(subd_creases_weight)
|
||||
@@ -168,7 +166,6 @@ void CachedData::invalidate_last_loaded_time(bool attributes_only)
|
||||
curve_keys.invalidate_last_loaded_time();
|
||||
curve_radius.invalidate_last_loaded_time();
|
||||
curve_shader.invalidate_last_loaded_time();
|
||||
num_ngons.invalidate_last_loaded_time();
|
||||
shader.invalidate_last_loaded_time();
|
||||
subd_creases_edge.invalidate_last_loaded_time();
|
||||
subd_creases_weight.invalidate_last_loaded_time();
|
||||
@@ -192,7 +189,6 @@ void CachedData::set_time_sampling(TimeSampling time_sampling)
|
||||
curve_keys.set_time_sampling(time_sampling);
|
||||
curve_radius.set_time_sampling(time_sampling);
|
||||
curve_shader.set_time_sampling(time_sampling);
|
||||
num_ngons.set_time_sampling(time_sampling);
|
||||
shader.set_time_sampling(time_sampling);
|
||||
subd_creases_edge.set_time_sampling(time_sampling);
|
||||
subd_creases_weight.set_time_sampling(time_sampling);
|
||||
@@ -222,7 +218,6 @@ size_t CachedData::memory_used() const
|
||||
mem_used += curve_keys.memory_used();
|
||||
mem_used += curve_radius.memory_used();
|
||||
mem_used += curve_shader.memory_used();
|
||||
mem_used += num_ngons.memory_used();
|
||||
mem_used += shader.memory_used();
|
||||
mem_used += subd_creases_edge.memory_used();
|
||||
mem_used += subd_creases_weight.memory_used();
|
||||
@@ -1205,8 +1200,6 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame
|
||||
cached_data.subd_face_corners.copy_to_socket(
|
||||
frame_time, mesh, mesh->get_subd_face_corners_socket());
|
||||
|
||||
cached_data.num_ngons.copy_to_socket(frame_time, mesh, mesh->get_num_ngons_socket());
|
||||
|
||||
cached_data.subd_creases_edge.copy_to_socket(
|
||||
frame_time, mesh, mesh->get_subd_creases_edge_socket());
|
||||
|
||||
|
||||
@@ -302,7 +302,6 @@ struct CachedData {
|
||||
DataStore<array<bool>> subd_smooth;
|
||||
DataStore<array<int>> subd_ptex_offset;
|
||||
DataStore<array<int>> subd_face_corners;
|
||||
DataStore<int> num_ngons;
|
||||
DataStore<array<int>> subd_creases_edge;
|
||||
DataStore<array<float>> subd_creases_weight;
|
||||
DataStore<array<int>> subd_vertex_crease_indices;
|
||||
|
||||
@@ -415,10 +415,8 @@ static void add_subd_polygons(CachedData &cached_data, const SubDSchemaData &dat
|
||||
const int *face_counts_array = face_counts->get();
|
||||
const int *face_indices_array = face_indices->get();
|
||||
|
||||
int num_ngons = 0;
|
||||
int num_corners = 0;
|
||||
for (size_t i = 0; i < face_counts->size(); i++) {
|
||||
num_ngons += (face_counts_array[i] == 4 ? 0 : 1);
|
||||
num_corners += face_counts_array[i];
|
||||
}
|
||||
|
||||
@@ -467,7 +465,6 @@ static void add_subd_polygons(CachedData &cached_data, const SubDSchemaData &dat
|
||||
cached_data.subd_smooth.add_data(subd_smooth, time);
|
||||
cached_data.subd_ptex_offset.add_data(subd_ptex_offset, time);
|
||||
cached_data.subd_face_corners.add_data(subd_face_corners, time);
|
||||
cached_data.num_ngons.add_data(num_ngons, time);
|
||||
cached_data.uv_loops.add_data(uv_loops, time);
|
||||
}
|
||||
|
||||
|
||||
@@ -193,10 +193,6 @@ size_t Attribute::data_sizeof() const
|
||||
|
||||
size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
|
||||
{
|
||||
if (flags & ATTR_FINAL_SIZE) {
|
||||
return buffer.size() / data_sizeof();
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
switch (element) {
|
||||
@@ -208,9 +204,11 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
|
||||
case ATTR_ELEMENT_VERTEX:
|
||||
if (geom->is_mesh() || geom->is_volume()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
size = mesh->get_verts().size() + mesh->get_num_ngons();
|
||||
if (prim == ATTR_PRIM_SUBD) {
|
||||
size -= mesh->get_num_subd_verts();
|
||||
size = mesh->get_num_subd_base_verts();
|
||||
}
|
||||
else {
|
||||
size = mesh->get_verts().size();
|
||||
}
|
||||
}
|
||||
else if (geom->is_pointcloud()) {
|
||||
@@ -222,9 +220,11 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
DCHECK_GT(mesh->get_motion_steps(), 0);
|
||||
size = (mesh->get_verts().size() + mesh->get_num_ngons()) * (mesh->get_motion_steps() - 1);
|
||||
if (prim == ATTR_PRIM_SUBD) {
|
||||
size -= mesh->get_num_subd_verts() * (mesh->get_motion_steps() - 1);
|
||||
size = mesh->get_num_subd_base_verts() * (mesh->get_motion_steps() - 1);
|
||||
}
|
||||
else {
|
||||
size = mesh->get_verts().size() * (mesh->get_motion_steps() - 1);
|
||||
}
|
||||
}
|
||||
else if (geom->is_pointcloud()) {
|
||||
@@ -235,11 +235,11 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
|
||||
case ATTR_ELEMENT_FACE:
|
||||
if (geom->is_mesh() || geom->is_volume()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (prim == ATTR_PRIM_GEOMETRY) {
|
||||
size = mesh->num_triangles();
|
||||
if (prim == ATTR_PRIM_SUBD) {
|
||||
size = mesh->get_num_subd_faces();
|
||||
}
|
||||
else {
|
||||
size = mesh->get_num_subd_faces() + mesh->get_num_ngons();
|
||||
size = mesh->num_triangles();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -247,11 +247,11 @@ size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const
|
||||
case ATTR_ELEMENT_CORNER_BYTE:
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (prim == ATTR_PRIM_GEOMETRY) {
|
||||
size = mesh->num_triangles() * 3;
|
||||
if (prim == ATTR_PRIM_SUBD) {
|
||||
size = mesh->get_subd_face_corners().size();
|
||||
}
|
||||
else {
|
||||
size = mesh->get_subd_face_corners().size() + mesh->get_num_ngons();
|
||||
size = mesh->num_triangles() * 3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -305,28 +305,6 @@ void Attribute::zero_data(void *dst)
|
||||
memset(dst, 0, data_sizeof());
|
||||
}
|
||||
|
||||
void Attribute::add_with_weight(void *dst, void *src, const float weight)
|
||||
{
|
||||
if (element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
((uchar *)dst)[i] += uchar(((uchar *)src)[i] * weight);
|
||||
}
|
||||
}
|
||||
else if (same_storage(type, TypeFloat)) {
|
||||
*((float *)dst) += *((float *)src) * weight;
|
||||
}
|
||||
else if (same_storage(type, TypeFloat2)) {
|
||||
*((float2 *)dst) += *((float2 *)src) * weight;
|
||||
}
|
||||
else if (same_storage(type, TypeVector)) {
|
||||
// Points are float3s and not float4s
|
||||
*((float3 *)dst) += *((float3 *)src) * weight;
|
||||
}
|
||||
else {
|
||||
assert(!"not implemented for this type");
|
||||
}
|
||||
}
|
||||
|
||||
const char *Attribute::standard_name(AttributeStandard std)
|
||||
{
|
||||
switch (std) {
|
||||
@@ -562,7 +540,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
|
||||
attr = add(name, TypeFloat, ATTR_ELEMENT_FACE);
|
||||
break;
|
||||
case ATTR_STD_PTEX_UV:
|
||||
attr = add(name, TypePoint, ATTR_ELEMENT_VERTEX);
|
||||
attr = add(name, TypeFloat2, ATTR_ELEMENT_CORNER);
|
||||
break;
|
||||
case ATTR_STD_GENERATED_TRANSFORM:
|
||||
attr = add(name, TypeMatrix, ATTR_ELEMENT_MESH);
|
||||
@@ -671,6 +649,13 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
|
||||
return attr;
|
||||
}
|
||||
|
||||
Attribute &AttributeSet::copy(const Attribute &attr)
|
||||
{
|
||||
Attribute ©_attr = *add(attr.name, attr.type, attr.element);
|
||||
copy_attr.std = attr.std;
|
||||
return copy_attr;
|
||||
}
|
||||
|
||||
Attribute *AttributeSet::find(AttributeStandard std) const
|
||||
{
|
||||
for (const Attribute &attr : attributes) {
|
||||
@@ -830,11 +815,6 @@ AttributeRequest::AttributeRequest(ustring name_)
|
||||
desc.element = ATTR_ELEMENT_NONE;
|
||||
desc.offset = 0;
|
||||
desc.type = NODE_ATTR_FLOAT;
|
||||
|
||||
subd_type = TypeFloat;
|
||||
subd_desc.element = ATTR_ELEMENT_NONE;
|
||||
subd_desc.offset = 0;
|
||||
subd_desc.type = NODE_ATTR_FLOAT;
|
||||
}
|
||||
|
||||
AttributeRequest::AttributeRequest(AttributeStandard std_)
|
||||
@@ -846,11 +826,6 @@ AttributeRequest::AttributeRequest(AttributeStandard std_)
|
||||
desc.element = ATTR_ELEMENT_NONE;
|
||||
desc.offset = 0;
|
||||
desc.type = NODE_ATTR_FLOAT;
|
||||
|
||||
subd_type = TypeFloat;
|
||||
subd_desc.element = ATTR_ELEMENT_NONE;
|
||||
subd_desc.offset = 0;
|
||||
subd_desc.type = NODE_ATTR_FLOAT;
|
||||
}
|
||||
|
||||
/* AttributeRequestSet */
|
||||
|
||||
@@ -149,7 +149,6 @@ class Attribute {
|
||||
}
|
||||
|
||||
void zero_data(void *dst);
|
||||
void add_with_weight(void *dst, void *src, const float weight);
|
||||
|
||||
void add(const float &f);
|
||||
void add(const float2 &f);
|
||||
@@ -193,6 +192,8 @@ class AttributeSet {
|
||||
Attribute *find(AttributeStandard std) const;
|
||||
void remove(AttributeStandard std);
|
||||
|
||||
Attribute ©(const Attribute &attr);
|
||||
|
||||
Attribute *find(AttributeRequest &req);
|
||||
Attribute *find_matching(const Attribute &other);
|
||||
|
||||
@@ -233,8 +234,8 @@ class AttributeRequest {
|
||||
AttributeStandard std;
|
||||
|
||||
/* temporary variables used by GeometryManager */
|
||||
TypeDesc type, subd_type;
|
||||
AttributeDescriptor desc, subd_desc;
|
||||
TypeDesc type;
|
||||
AttributeDescriptor desc;
|
||||
|
||||
explicit AttributeRequest(ustring name_);
|
||||
explicit AttributeRequest(AttributeStandard std);
|
||||
|
||||
@@ -21,12 +21,9 @@ DeviceScene::DeviceScene(Device *device)
|
||||
tri_shader(device, "tri_shader", MEM_GLOBAL),
|
||||
tri_vnormal(device, "tri_vnormal", MEM_GLOBAL),
|
||||
tri_vindex(device, "tri_vindex", MEM_GLOBAL),
|
||||
tri_patch(device, "tri_patch", MEM_GLOBAL),
|
||||
tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL),
|
||||
curves(device, "curves", MEM_GLOBAL),
|
||||
curve_keys(device, "curve_keys", MEM_GLOBAL),
|
||||
curve_segments(device, "curve_segments", MEM_GLOBAL),
|
||||
patches(device, "patches", MEM_GLOBAL),
|
||||
points(device, "points", MEM_GLOBAL),
|
||||
points_shader(device, "points_shader", MEM_GLOBAL),
|
||||
objects(device, "objects", MEM_GLOBAL),
|
||||
|
||||
@@ -28,15 +28,11 @@ class DeviceScene {
|
||||
device_vector<uint> tri_shader;
|
||||
device_vector<packed_float3> tri_vnormal;
|
||||
device_vector<packed_uint3> tri_vindex;
|
||||
device_vector<uint> tri_patch;
|
||||
device_vector<float2> tri_patch_uv;
|
||||
|
||||
device_vector<KernelCurve> curves;
|
||||
device_vector<float4> curve_keys;
|
||||
device_vector<KernelCurveSegment> curve_segments;
|
||||
|
||||
device_vector<uint> patches;
|
||||
|
||||
/* point-cloud */
|
||||
device_vector<float4> points;
|
||||
device_vector<uint> points_shader;
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "scene/stats.h"
|
||||
#include "scene/volume.h"
|
||||
|
||||
#include "subd/patch_table.h"
|
||||
#include "subd/split.h"
|
||||
|
||||
#ifdef WITH_OSL
|
||||
@@ -268,7 +267,6 @@ void GeometryManager::geom_calc_offset(Scene *scene, BVHLayout bvh_layout)
|
||||
|
||||
size_t point_size = 0;
|
||||
|
||||
size_t patch_size = 0;
|
||||
size_t face_size = 0;
|
||||
size_t corner_size = 0;
|
||||
|
||||
@@ -283,24 +281,12 @@ void GeometryManager::geom_calc_offset(Scene *scene, BVHLayout bvh_layout)
|
||||
mesh->vert_offset = vert_size;
|
||||
mesh->prim_offset = tri_size;
|
||||
|
||||
mesh->patch_offset = patch_size;
|
||||
mesh->face_offset = face_size;
|
||||
mesh->corner_offset = corner_size;
|
||||
|
||||
vert_size += mesh->verts.size();
|
||||
tri_size += mesh->num_triangles();
|
||||
|
||||
if (mesh->get_num_subd_faces()) {
|
||||
const 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 */
|
||||
if (mesh->patch_table) {
|
||||
mesh->patch_table_offset = patch_size;
|
||||
patch_size += mesh->patch_table->total_size();
|
||||
}
|
||||
}
|
||||
|
||||
face_size += mesh->get_num_subd_faces();
|
||||
corner_size += mesh->subd_face_corners.size();
|
||||
}
|
||||
@@ -512,10 +498,7 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
|
||||
dscene->tri_verts.tag_realloc();
|
||||
dscene->tri_vnormal.tag_realloc();
|
||||
dscene->tri_vindex.tag_realloc();
|
||||
dscene->tri_patch.tag_realloc();
|
||||
dscene->tri_patch_uv.tag_realloc();
|
||||
dscene->tri_shader.tag_realloc();
|
||||
dscene->patches.tag_realloc();
|
||||
}
|
||||
|
||||
if (device_update_flags & DEVICE_CURVE_DATA_NEEDS_REALLOC) {
|
||||
@@ -1049,15 +1032,12 @@ void GeometryManager::device_update(Device *device,
|
||||
dscene->tri_verts.clear_modified();
|
||||
dscene->tri_shader.clear_modified();
|
||||
dscene->tri_vindex.clear_modified();
|
||||
dscene->tri_patch.clear_modified();
|
||||
dscene->tri_vnormal.clear_modified();
|
||||
dscene->tri_patch_uv.clear_modified();
|
||||
dscene->curves.clear_modified();
|
||||
dscene->curve_keys.clear_modified();
|
||||
dscene->curve_segments.clear_modified();
|
||||
dscene->points.clear_modified();
|
||||
dscene->points_shader.clear_modified();
|
||||
dscene->patches.clear_modified();
|
||||
dscene->attributes_map.clear_modified();
|
||||
dscene->attributes_float.clear_modified();
|
||||
dscene->attributes_float2.clear_modified();
|
||||
@@ -1080,14 +1060,11 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool forc
|
||||
dscene->tri_shader.free_if_need_realloc(force_free);
|
||||
dscene->tri_vnormal.free_if_need_realloc(force_free);
|
||||
dscene->tri_vindex.free_if_need_realloc(force_free);
|
||||
dscene->tri_patch.free_if_need_realloc(force_free);
|
||||
dscene->tri_patch_uv.free_if_need_realloc(force_free);
|
||||
dscene->curves.free_if_need_realloc(force_free);
|
||||
dscene->curve_keys.free_if_need_realloc(force_free);
|
||||
dscene->curve_segments.free_if_need_realloc(force_free);
|
||||
dscene->points.free_if_need_realloc(force_free);
|
||||
dscene->points_shader.free_if_need_realloc(force_free);
|
||||
dscene->patches.free_if_need_realloc(force_free);
|
||||
dscene->attributes_map.free_if_need_realloc(force_free);
|
||||
dscene->attributes_float.free_if_need_realloc(force_free);
|
||||
dscene->attributes_float2.free_if_need_realloc(force_free);
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#include "scene/shader.h"
|
||||
#include "scene/shader_nodes.h"
|
||||
|
||||
#include "subd/split.h"
|
||||
|
||||
#include "util/progress.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
@@ -111,15 +109,13 @@ static void emit_attribute_map_entry(AttributeMap *attr_map,
|
||||
else {
|
||||
attr_map[index].type = NODE_ATTR_FLOAT3;
|
||||
}
|
||||
|
||||
attr_map[index].flags = desc.flags;
|
||||
}
|
||||
|
||||
/* Generate an attribute map end marker, optionally including a link to another map.
|
||||
* Links are used to connect object attribute maps to mesh attribute maps. */
|
||||
static void emit_attribute_map_terminator(AttributeMap *attr_map,
|
||||
const size_t index,
|
||||
bool chain,
|
||||
const bool chain,
|
||||
const uint chain_link)
|
||||
{
|
||||
for (int j = 0; j < ATTR_PRIM_TYPES; j++) {
|
||||
@@ -127,7 +123,6 @@ static void emit_attribute_map_terminator(AttributeMap *attr_map,
|
||||
attr_map[index + j].element = chain; /* link is valid flag */
|
||||
attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */
|
||||
attr_map[index + j].type = 0;
|
||||
attr_map[index + j].flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,17 +130,9 @@ static void emit_attribute_map_terminator(AttributeMap *attr_map,
|
||||
static void emit_attribute_mapping(AttributeMap *attr_map,
|
||||
const size_t index,
|
||||
const uint64_t id,
|
||||
AttributeRequest &req,
|
||||
Geometry *geom)
|
||||
AttributeRequest &req)
|
||||
{
|
||||
emit_attribute_map_entry(attr_map, index, id, req.type, req.desc);
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->get_num_subd_faces()) {
|
||||
emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryManager::update_svm_attributes(Device * /*unused*/,
|
||||
@@ -224,14 +211,14 @@ void GeometryManager::update_svm_attributes(Device * /*unused*/,
|
||||
id = scene->shader_manager->get_attribute_id(req.std);
|
||||
}
|
||||
|
||||
emit_attribute_mapping(attr_map, index, id, req, geom);
|
||||
emit_attribute_mapping(attr_map, index, id, req);
|
||||
index += ATTR_PRIM_TYPES;
|
||||
|
||||
#ifdef WITH_OSL
|
||||
/* Some standard attributes are explicitly referenced via their standard ID, so add those
|
||||
* again in case they were added under a different attribute ID. */
|
||||
if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) {
|
||||
emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req, geom);
|
||||
emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req);
|
||||
index += ATTR_PRIM_TYPES;
|
||||
}
|
||||
#endif
|
||||
@@ -257,7 +244,7 @@ void GeometryManager::update_svm_attributes(Device * /*unused*/,
|
||||
id = scene->shader_manager->get_attribute_id(req.std);
|
||||
}
|
||||
|
||||
emit_attribute_mapping(attr_map, index, id, req, object->geometry);
|
||||
emit_attribute_mapping(attr_map, index, id, req);
|
||||
index += ATTR_PRIM_TYPES;
|
||||
}
|
||||
|
||||
@@ -332,7 +319,6 @@ class AttributeTableBuilder {
|
||||
|
||||
/* store element and type */
|
||||
desc.element = mattr->element;
|
||||
desc.flags = mattr->flags;
|
||||
type = mattr->type;
|
||||
|
||||
/* store attribute data in arrays */
|
||||
@@ -369,33 +355,17 @@ class AttributeTableBuilder {
|
||||
* a correction for that in here */
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->get_subdivision_type() == Mesh::SUBDIVISION_CATMULL_CLARK &&
|
||||
desc.flags & ATTR_SUBDIVIDED)
|
||||
{
|
||||
/* Indices for subdivided attributes are retrieved
|
||||
* from patch table so no need for correction here. */
|
||||
}
|
||||
else if (element == ATTR_ELEMENT_VERTEX) {
|
||||
if (element == ATTR_ELEMENT_VERTEX) {
|
||||
offset -= mesh->vert_offset;
|
||||
}
|
||||
else if (element == ATTR_ELEMENT_VERTEX_MOTION) {
|
||||
offset -= mesh->vert_offset;
|
||||
}
|
||||
else if (element == ATTR_ELEMENT_FACE) {
|
||||
if (prim == ATTR_PRIM_GEOMETRY) {
|
||||
offset -= mesh->prim_offset;
|
||||
}
|
||||
else {
|
||||
offset -= mesh->face_offset;
|
||||
}
|
||||
offset -= mesh->prim_offset;
|
||||
}
|
||||
else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
if (prim == ATTR_PRIM_GEOMETRY) {
|
||||
offset -= 3 * mesh->prim_offset;
|
||||
}
|
||||
else {
|
||||
offset -= mesh->corner_offset;
|
||||
}
|
||||
offset -= 3 * mesh->prim_offset;
|
||||
}
|
||||
}
|
||||
else if (geom->is_hair()) {
|
||||
@@ -545,15 +515,7 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
AttributeRequestSet &attributes = geom_attributes[i];
|
||||
for (AttributeRequest &req : attributes.requests) {
|
||||
Attribute *attr = geom->attributes.find(req);
|
||||
|
||||
builder.reserve(geom, attr, ATTR_PRIM_GEOMETRY);
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
Attribute *subd_attr = mesh->subd_attributes.find(req);
|
||||
|
||||
builder.reserve(mesh, subd_attr, ATTR_PRIM_SUBD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,18 +555,6 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
|
||||
builder.add(geom, attr, ATTR_PRIM_GEOMETRY, req.type, req.desc);
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
Attribute *subd_attr = mesh->subd_attributes.find(req);
|
||||
|
||||
if (subd_attr) {
|
||||
/* force a copy if we need to reallocate all the data */
|
||||
subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)];
|
||||
}
|
||||
|
||||
builder.add(mesh, subd_attr, ATTR_PRIM_SUBD, req.subd_type, req.subd_desc);
|
||||
}
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
@@ -625,10 +575,6 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
|
||||
builder.add(object->geometry, attr, ATTR_PRIM_GEOMETRY, req.type, req.desc);
|
||||
|
||||
/* object attributes don't care about subdivision */
|
||||
req.subd_type = req.type;
|
||||
req.subd_desc = req.desc;
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
#include "scene/shader.h"
|
||||
#include "scene/shader_nodes.h"
|
||||
|
||||
#include "subd/patch_table.h"
|
||||
#include "subd/split.h"
|
||||
|
||||
#include "util/progress.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
@@ -41,25 +38,12 @@ void GeometryManager::device_update_mesh(Device * /*unused*/,
|
||||
|
||||
size_t point_size = 0;
|
||||
|
||||
size_t patch_size = 0;
|
||||
|
||||
for (Geometry *geom : scene->geometry) {
|
||||
if (geom->is_mesh() || geom->is_volume()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
|
||||
vert_size += mesh->verts.size();
|
||||
tri_size += mesh->num_triangles();
|
||||
|
||||
if (mesh->get_num_subd_faces()) {
|
||||
const 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 */
|
||||
if (mesh->patch_table) {
|
||||
mesh->patch_table_offset = patch_size;
|
||||
patch_size += mesh->patch_table->total_size();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (geom->is_hair()) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
@@ -83,14 +67,10 @@ void GeometryManager::device_update_mesh(Device * /*unused*/,
|
||||
uint *tri_shader = dscene->tri_shader.alloc(tri_size);
|
||||
packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size);
|
||||
packed_uint3 *tri_vindex = dscene->tri_vindex.alloc(tri_size);
|
||||
uint *tri_patch = dscene->tri_patch.alloc(tri_size);
|
||||
float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
|
||||
|
||||
const bool copy_all_data = dscene->tri_shader.need_realloc() ||
|
||||
dscene->tri_vindex.need_realloc() ||
|
||||
dscene->tri_vnormal.need_realloc() ||
|
||||
dscene->tri_patch.need_realloc() ||
|
||||
dscene->tri_patch_uv.need_realloc();
|
||||
dscene->tri_vnormal.need_realloc();
|
||||
|
||||
for (Geometry *geom : scene->geometry) {
|
||||
if (geom->is_mesh() || geom->is_volume()) {
|
||||
@@ -106,13 +86,8 @@ void GeometryManager::device_update_mesh(Device * /*unused*/,
|
||||
mesh->pack_normals(&vnormal[mesh->vert_offset]);
|
||||
}
|
||||
|
||||
if (mesh->verts_is_modified() || mesh->triangles_is_modified() ||
|
||||
mesh->vert_patch_uv_is_modified() || copy_all_data)
|
||||
{
|
||||
mesh->pack_verts(&tri_verts[mesh->vert_offset],
|
||||
&tri_vindex[mesh->prim_offset],
|
||||
&tri_patch[mesh->prim_offset],
|
||||
&tri_patch_uv[mesh->vert_offset]);
|
||||
if (mesh->verts_is_modified() || mesh->triangles_is_modified() || copy_all_data) {
|
||||
mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->prim_offset]);
|
||||
}
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
@@ -128,8 +103,6 @@ void GeometryManager::device_update_mesh(Device * /*unused*/,
|
||||
dscene->tri_shader.copy_to_device_if_modified();
|
||||
dscene->tri_vnormal.copy_to_device_if_modified();
|
||||
dscene->tri_vindex.copy_to_device_if_modified();
|
||||
dscene->tri_patch.copy_to_device_if_modified();
|
||||
dscene->tri_patch_uv.copy_to_device_if_modified();
|
||||
}
|
||||
|
||||
if (curve_segment_size != 0) {
|
||||
@@ -191,30 +164,6 @@ void GeometryManager::device_update_mesh(Device * /*unused*/,
|
||||
dscene->points.copy_to_device();
|
||||
dscene->points_shader.copy_to_device();
|
||||
}
|
||||
|
||||
if (patch_size != 0 && dscene->patches.need_realloc()) {
|
||||
progress.set_status("Updating Mesh", "Copying Patches to device");
|
||||
|
||||
uint *patch_data = dscene->patches.alloc(patch_size);
|
||||
|
||||
for (Geometry *geom : scene->geometry) {
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
mesh->pack_patches(&patch_data[mesh->patch_offset]);
|
||||
|
||||
if (mesh->patch_table) {
|
||||
mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset],
|
||||
mesh->patch_table_offset);
|
||||
}
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dscene->patches.copy_to_device();
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
@@ -118,9 +118,6 @@ 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);
|
||||
@@ -138,7 +135,6 @@ NODE_DEFINE(Mesh)
|
||||
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", 1.0f)
|
||||
@@ -176,15 +172,12 @@ Mesh::Mesh(const NodeType *node_type, Type geom_type_)
|
||||
{
|
||||
vert_offset = 0;
|
||||
|
||||
patch_offset = 0;
|
||||
face_offset = 0;
|
||||
corner_offset = 0;
|
||||
|
||||
num_subd_verts = 0;
|
||||
num_subd_added_verts = 0;
|
||||
num_subd_faces = 0;
|
||||
|
||||
num_ngons = 0;
|
||||
|
||||
subdivision_type = SUBDIVISION_NONE;
|
||||
}
|
||||
|
||||
@@ -198,8 +191,8 @@ void Mesh::resize_mesh(const int numverts, const int numtris)
|
||||
smooth.resize(numtris);
|
||||
|
||||
if (get_num_subd_faces()) {
|
||||
triangle_patch.resize(numtris);
|
||||
vert_patch_uv.resize(numverts);
|
||||
subd_triangle_patch_index.resize(numtris);
|
||||
subd_corner_patch_uv.resize(numtris * 3);
|
||||
}
|
||||
|
||||
attributes.resize();
|
||||
@@ -214,14 +207,14 @@ void Mesh::reserve_mesh(const int numverts, const int numtris)
|
||||
smooth.reserve(numtris);
|
||||
|
||||
if (get_num_subd_faces()) {
|
||||
triangle_patch.reserve(numtris);
|
||||
vert_patch_uv.reserve(numverts);
|
||||
subd_triangle_patch_index.reserve(numtris);
|
||||
subd_corner_patch_uv.reserve(numtris * 3);
|
||||
}
|
||||
|
||||
attributes.resize(true);
|
||||
}
|
||||
|
||||
void Mesh::resize_subd_faces(const int numfaces, const int num_ngons_, int numcorners)
|
||||
void Mesh::resize_subd_faces(const int numfaces, const int numcorners)
|
||||
{
|
||||
subd_start_corner.resize(numfaces);
|
||||
subd_num_corners.resize(numfaces);
|
||||
@@ -229,13 +222,12 @@ void Mesh::resize_subd_faces(const int numfaces, const int num_ngons_, int numco
|
||||
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(const int numfaces, const int num_ngons_, int numcorners)
|
||||
void Mesh::reserve_subd_faces(const int numfaces, const int numcorners)
|
||||
{
|
||||
subd_start_corner.reserve(numfaces);
|
||||
subd_num_corners.reserve(numfaces);
|
||||
@@ -243,7 +235,6 @@ void Mesh::reserve_subd_faces(const int numfaces, const int num_ngons_, int numc
|
||||
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);
|
||||
@@ -259,13 +250,11 @@ void Mesh::clear_non_sockets()
|
||||
{
|
||||
Geometry::clear(true);
|
||||
|
||||
num_subd_verts = 0;
|
||||
num_subd_added_verts = 0;
|
||||
num_subd_faces = 0;
|
||||
|
||||
vert_to_stitching_key_map.clear();
|
||||
vert_stitching_map.clear();
|
||||
|
||||
patch_table.reset();
|
||||
}
|
||||
|
||||
void Mesh::clear(bool preserve_shaders, bool preserve_voxel_data)
|
||||
@@ -278,9 +267,6 @@ void Mesh::clear(bool preserve_shaders, bool preserve_voxel_data)
|
||||
shader.clear();
|
||||
smooth.clear();
|
||||
|
||||
triangle_patch.clear();
|
||||
vert_patch_uv.clear();
|
||||
|
||||
subd_start_corner.clear();
|
||||
subd_num_corners.clear();
|
||||
subd_shader.clear();
|
||||
@@ -308,22 +294,12 @@ void Mesh::add_vertex(const float3 P)
|
||||
{
|
||||
verts.push_back_reserved(P);
|
||||
tag_verts_modified();
|
||||
|
||||
if (get_num_subd_faces()) {
|
||||
vert_patch_uv.push_back_reserved(zero_float2());
|
||||
tag_vert_patch_uv_modified();
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::add_vertex_slow(const float3 P)
|
||||
{
|
||||
verts.push_back_slow(P);
|
||||
tag_verts_modified();
|
||||
|
||||
if (get_num_subd_faces()) {
|
||||
vert_patch_uv.push_back_slow(zero_float2());
|
||||
tag_vert_patch_uv_modified();
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::add_triangle(const int v0, const int v1, const int v2, const int shader_, bool smooth_)
|
||||
@@ -339,8 +315,10 @@ void Mesh::add_triangle(const int v0, const int v1, const int v2, const int shad
|
||||
tag_smooth_modified();
|
||||
|
||||
if (get_num_subd_faces()) {
|
||||
triangle_patch.push_back_reserved(-1);
|
||||
tag_triangle_patch_modified();
|
||||
subd_triangle_patch_index.push_back_reserved(-1);
|
||||
subd_corner_patch_uv.push_back_reserved(zero_float2());
|
||||
subd_corner_patch_uv.push_back_reserved(zero_float2());
|
||||
subd_corner_patch_uv.push_back_reserved(zero_float2());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -647,19 +625,12 @@ void Mesh::add_undisplaced()
|
||||
|
||||
/* get attribute */
|
||||
Attribute *attr = attrs.add(ATTR_STD_POSITION_UNDISPLACED);
|
||||
attr->flags |= ATTR_SUBDIVIDED;
|
||||
|
||||
float3 *data = attr->data_float3();
|
||||
|
||||
/* copy verts */
|
||||
size_t size = attr->buffer_size(this, ATTR_PRIM_GEOMETRY) / sizeof(float3);
|
||||
|
||||
/* Center points for ngons aren't stored in Mesh::verts but are included in size since they will
|
||||
* be calculated later, we subtract them from size here so we don't have an overflow while
|
||||
* copying.
|
||||
*/
|
||||
size -= num_ngons;
|
||||
|
||||
if (size) {
|
||||
std::copy_n(verts.data(), size, data);
|
||||
}
|
||||
@@ -718,87 +689,20 @@ void Mesh::pack_normals(packed_float3 *vnormal)
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::pack_verts(packed_float3 *tri_verts,
|
||||
packed_uint3 *tri_vindex,
|
||||
uint *tri_patch,
|
||||
float2 *tri_patch_uv)
|
||||
void Mesh::pack_verts(packed_float3 *tri_verts, packed_uint3 *tri_vindex)
|
||||
{
|
||||
const size_t verts_size = verts.size();
|
||||
const size_t triangles_size = num_triangles();
|
||||
const int *p_tris = triangles.data();
|
||||
int off = 0;
|
||||
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++) {
|
||||
tri_verts[i] = verts[i];
|
||||
tri_patch_uv[i] = vert_patch_uv_ptr[i];
|
||||
}
|
||||
for (size_t i = 0; i < triangles_size; i++) {
|
||||
tri_vindex[i] = make_packed_uint3(p_tris[off + 0] + vert_offset,
|
||||
p_tris[off + 1] + vert_offset,
|
||||
p_tris[off + 2] + vert_offset);
|
||||
tri_patch[i] = triangle_patch[i] * 8 + patch_offset;
|
||||
off += 3;
|
||||
}
|
||||
for (size_t i = 0; i < verts_size; i++) {
|
||||
tri_verts[i] = verts[i];
|
||||
}
|
||||
else {
|
||||
for (size_t i = 0; i < verts_size; i++) {
|
||||
tri_verts[i] = verts[i];
|
||||
}
|
||||
for (size_t i = 0; i < triangles_size; i++) {
|
||||
tri_vindex[i] = make_packed_uint3(p_tris[off + 0] + vert_offset,
|
||||
p_tris[off + 1] + vert_offset,
|
||||
p_tris[off + 2] + vert_offset);
|
||||
tri_patch[i] = -1;
|
||||
off += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::pack_patches(uint *patch_data)
|
||||
{
|
||||
const size_t num_faces = get_num_subd_faces();
|
||||
int ngons = 0;
|
||||
|
||||
for (size_t f = 0; f < num_faces; f++) {
|
||||
SubdFace face = get_subd_face(f);
|
||||
|
||||
if (face.is_quad()) {
|
||||
int c[4];
|
||||
memcpy(c, &subd_face_corners[face.start_corner], sizeof(int) * 4);
|
||||
|
||||
*(patch_data++) = c[0] + vert_offset;
|
||||
*(patch_data++) = c[1] + vert_offset;
|
||||
*(patch_data++) = c[2] + vert_offset;
|
||||
*(patch_data++) = c[3] + vert_offset;
|
||||
|
||||
*(patch_data++) = f + face_offset;
|
||||
*(patch_data++) = face.num_corners;
|
||||
*(patch_data++) = face.start_corner + corner_offset;
|
||||
*(patch_data++) = 0;
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < face.num_corners; i++) {
|
||||
int c[4];
|
||||
c[0] = subd_face_corners[face.start_corner + mod(i + 0, face.num_corners)];
|
||||
c[1] = subd_face_corners[face.start_corner + mod(i + 1, face.num_corners)];
|
||||
c[2] = verts.size() - num_subd_verts + ngons;
|
||||
c[3] = subd_face_corners[face.start_corner + mod(i - 1, face.num_corners)];
|
||||
|
||||
*(patch_data++) = c[0] + vert_offset;
|
||||
*(patch_data++) = c[1] + vert_offset;
|
||||
*(patch_data++) = c[2] + vert_offset;
|
||||
*(patch_data++) = c[3] + vert_offset;
|
||||
|
||||
*(patch_data++) = f + face_offset;
|
||||
*(patch_data++) = face.num_corners | (i << 16);
|
||||
*(patch_data++) = face.start_corner + corner_offset;
|
||||
*(patch_data++) = subd_face_corners.size() + ngons + corner_offset;
|
||||
}
|
||||
|
||||
ngons++;
|
||||
}
|
||||
for (size_t i = 0; i < triangles_size; i++) {
|
||||
tri_vindex[i] = make_packed_uint3(p_tris[off + 0] + vert_offset,
|
||||
p_tris[off + 1] + vert_offset,
|
||||
p_tris[off + 2] + vert_offset);
|
||||
off += 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "scene/shader.h"
|
||||
|
||||
#include "subd/dice.h"
|
||||
#include "subd/patch_table.h"
|
||||
|
||||
#include "util/array.h"
|
||||
#include "util/boundbox.h"
|
||||
@@ -130,10 +129,6 @@ class Mesh : public Geometry {
|
||||
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 */
|
||||
NODE_SOCKET_API_ARRAY(array<int>, triangle_patch) /* must be < 0 for non subd triangles */
|
||||
NODE_SOCKET_API_ARRAY(array<float2>, vert_patch_uv)
|
||||
|
||||
/* SubdFaces */
|
||||
NODE_SOCKET_API_ARRAY(array<int>, subd_start_corner)
|
||||
NODE_SOCKET_API_ARRAY(array<int>, subd_num_corners)
|
||||
@@ -142,7 +137,6 @@ class Mesh : public Geometry {
|
||||
NODE_SOCKET_API_ARRAY(array<int>, subd_ptex_offset)
|
||||
|
||||
NODE_SOCKET_API_ARRAY(array<int>, subd_face_corners)
|
||||
NODE_SOCKET_API(int, num_ngons)
|
||||
|
||||
NODE_SOCKET_API_ARRAY(array<int>, subd_creases_edge)
|
||||
NODE_SOCKET_API_ARRAY(array<float>, subd_creases_weight)
|
||||
@@ -157,18 +151,18 @@ class Mesh : public Geometry {
|
||||
|
||||
AttributeSet subd_attributes;
|
||||
|
||||
/* Temporary storage for attribute interpolation, per triangle and per vertex. */
|
||||
array<int> subd_triangle_patch_index;
|
||||
array<float2> subd_corner_patch_uv;
|
||||
|
||||
/* BVH */
|
||||
size_t vert_offset;
|
||||
|
||||
size_t patch_offset;
|
||||
size_t patch_table_offset;
|
||||
size_t face_offset;
|
||||
size_t corner_offset;
|
||||
|
||||
private:
|
||||
unique_ptr<PackedPatchTable> patch_table;
|
||||
|
||||
size_t num_subd_verts;
|
||||
size_t num_subd_added_verts;
|
||||
size_t num_subd_faces;
|
||||
|
||||
unordered_map<int, int> vert_to_stitching_key_map; /* real vert index -> stitching index */
|
||||
@@ -191,8 +185,8 @@ class Mesh : public Geometry {
|
||||
|
||||
void resize_mesh(const int numverts, const int numtris);
|
||||
void reserve_mesh(const int numverts, const int numtris);
|
||||
void resize_subd_faces(const int numfaces, const int num_ngons, const int numcorners);
|
||||
void reserve_subd_faces(const int numfaces, const int num_ngons, const int numcorners);
|
||||
void resize_subd_faces(const int numfaces, const int numcorners);
|
||||
void reserve_subd_faces(const int numfaces, const int numcorners);
|
||||
void reserve_subd_creases(const size_t num_creases);
|
||||
void clear_non_sockets();
|
||||
void clear(bool preserve_shaders = false) override;
|
||||
@@ -214,11 +208,7 @@ class Mesh : public Geometry {
|
||||
|
||||
void pack_shaders(Scene *scene, uint *shader);
|
||||
void pack_normals(packed_float3 *vnormal);
|
||||
void pack_verts(packed_float3 *tri_verts,
|
||||
packed_uint3 *tri_vindex,
|
||||
uint *tri_patch,
|
||||
float2 *tri_patch_uv);
|
||||
void pack_patches(uint *patch_data);
|
||||
void pack_verts(packed_float3 *tri_verts, packed_uint3 *tri_vindex);
|
||||
|
||||
PrimitiveType primitive_type() const override;
|
||||
|
||||
@@ -232,15 +222,13 @@ class Mesh : public Geometry {
|
||||
{
|
||||
return num_subd_faces;
|
||||
}
|
||||
|
||||
void set_num_subd_faces(const size_t num_subd_faces_)
|
||||
{
|
||||
num_subd_faces = num_subd_faces_;
|
||||
}
|
||||
|
||||
size_t get_num_subd_verts()
|
||||
size_t get_num_subd_base_verts() const
|
||||
{
|
||||
return num_subd_verts;
|
||||
return verts.size() - num_subd_added_verts;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
#include "scene/attribute.h"
|
||||
#include "scene/mesh.h"
|
||||
|
||||
#include "subd/interpolation.h"
|
||||
#include "subd/osd.h"
|
||||
#include "subd/patch.h"
|
||||
#include "subd/patch_table.h"
|
||||
#include "subd/split.h"
|
||||
|
||||
#include "util/algorithm.h"
|
||||
@@ -19,12 +19,11 @@ 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;
|
||||
num_subd_added_verts = 0;
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
OsdMesh osd_mesh(*this);
|
||||
OsdData osd_data;
|
||||
bool need_packed_patch_table = false;
|
||||
|
||||
if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
|
||||
if (get_num_subd_faces()) {
|
||||
@@ -38,11 +37,6 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
* falling into catmull-clark code paths by accident
|
||||
*/
|
||||
subdivision_type = SUBDIVISION_LINEAR;
|
||||
|
||||
/* force disable attribute subdivision for same reason as above */
|
||||
for (Attribute &attr : subd_attributes.attributes) {
|
||||
attr.flags &= ~ATTR_SUBDIVIDED;
|
||||
}
|
||||
}
|
||||
|
||||
const int num_faces = get_num_subd_faces();
|
||||
@@ -88,7 +82,7 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
}
|
||||
}
|
||||
|
||||
/* split patches */
|
||||
/* Split patches. */
|
||||
split->split_patches(osd_patches.data(), sizeof(OsdPatch));
|
||||
}
|
||||
else
|
||||
@@ -101,6 +95,7 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
SubdFace face = get_subd_face(f);
|
||||
|
||||
if (face.is_quad()) {
|
||||
/* Simple quad case. */
|
||||
float3 *hull = patch->hull;
|
||||
float3 *normals = patch->normals;
|
||||
|
||||
@@ -130,7 +125,7 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
patch++;
|
||||
}
|
||||
else {
|
||||
/* ngon */
|
||||
/* N-gon split into N quads. */
|
||||
float3 center_vert = zero_float3();
|
||||
float3 center_normal = zero_float3();
|
||||
|
||||
@@ -184,115 +179,35 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
}
|
||||
}
|
||||
|
||||
/* split patches */
|
||||
/* Split patches. */
|
||||
split->split_patches(linear_patches.data(), sizeof(LinearQuadPatch));
|
||||
}
|
||||
|
||||
/* interpolate center points for attributes */
|
||||
for (Attribute &attr : subd_attributes.attributes) {
|
||||
if (get_num_subd_faces()) {
|
||||
/* Create a tessellated mesh attributes from subd base mesh attributes. */
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
if (subdivision_type == SUBDIVISION_CATMULL_CLARK && attr.flags & ATTR_SUBDIVIDED) {
|
||||
if (attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
/* keep subdivision for corner attributes disabled for now */
|
||||
attr.flags &= ~ATTR_SUBDIVIDED;
|
||||
}
|
||||
else if (get_num_subd_faces()) {
|
||||
osd_data.subdivide_attribute(attr);
|
||||
SubdAttributeInterpolation interpolation(*this, osd_mesh, osd_data, num_patches);
|
||||
#else
|
||||
SubdAttributeInterpolation interpolation(*this, num_patches);
|
||||
#endif
|
||||
|
||||
need_packed_patch_table = true;
|
||||
for (const Attribute &subd_attr : subd_attributes.attributes) {
|
||||
if (!interpolation.support_interp_attribute(subd_attr)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
char *data = attr.data();
|
||||
const size_t stride = attr.data_sizeof();
|
||||
int ngons = 0;
|
||||
|
||||
switch (attr.element) {
|
||||
case ATTR_ELEMENT_VERTEX: {
|
||||
for (int f = 0; f < num_faces; f++) {
|
||||
SubdFace face = get_subd_face(f);
|
||||
|
||||
if (!face.is_quad()) {
|
||||
char *center = data + (verts.size() - num_subd_verts + ngons) * stride;
|
||||
attr.zero_data(center);
|
||||
|
||||
const float inv_num_corners = 1.0f / float(face.num_corners);
|
||||
|
||||
for (int corner = 0; corner < face.num_corners; corner++) {
|
||||
attr.add_with_weight(center,
|
||||
data + subd_face_corners[face.start_corner + corner] * stride,
|
||||
inv_num_corners);
|
||||
}
|
||||
|
||||
ngons++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_ELEMENT_VERTEX_MOTION: {
|
||||
// TODO(mai): implement
|
||||
break;
|
||||
}
|
||||
case ATTR_ELEMENT_CORNER: {
|
||||
for (int f = 0; f < num_faces; f++) {
|
||||
SubdFace face = get_subd_face(f);
|
||||
|
||||
if (!face.is_quad()) {
|
||||
char *center = data + (subd_face_corners.size() + ngons) * stride;
|
||||
attr.zero_data(center);
|
||||
|
||||
const float inv_num_corners = 1.0f / float(face.num_corners);
|
||||
|
||||
for (int corner = 0; corner < face.num_corners; corner++) {
|
||||
attr.add_with_weight(
|
||||
center, data + (face.start_corner + corner) * stride, inv_num_corners);
|
||||
}
|
||||
|
||||
ngons++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_ELEMENT_CORNER_BYTE: {
|
||||
for (int f = 0; f < num_faces; f++) {
|
||||
SubdFace face = get_subd_face(f);
|
||||
|
||||
if (!face.is_quad()) {
|
||||
uchar *center = (uchar *)data + (subd_face_corners.size() + ngons) * stride;
|
||||
|
||||
const float inv_num_corners = 1.0f / float(face.num_corners);
|
||||
float4 val = zero_float4();
|
||||
|
||||
for (int corner = 0; corner < face.num_corners; corner++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
val[i] += float(*(data + (face.start_corner + corner) * stride + i)) *
|
||||
inv_num_corners;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
center[i] = uchar(min(max(val[i], 0.0f), 255.0f));
|
||||
}
|
||||
|
||||
ngons++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
Attribute &mesh_attr = attributes.copy(subd_attr);
|
||||
interpolation.interp_attribute(subd_attr, mesh_attr);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
/* pack patch tables */
|
||||
if (need_packed_patch_table) {
|
||||
patch_table = make_unique<PackedPatchTable>();
|
||||
patch_table->pack(osd_data.patch_table.get());
|
||||
}
|
||||
#endif
|
||||
// TODO: Free subd base data? Or will this break interactive updates?
|
||||
|
||||
// TODO: Use ATTR_STD_PTEX attributes instead, and create only for lifetime of this function
|
||||
// if there are attributes to interpolation. And then keep only if needed for ptex texturing
|
||||
|
||||
/* Clear temporary buffers needed for interpolation. */
|
||||
subd_triangle_patch_index.clear();
|
||||
subd_corner_patch_uv.clear();
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include "util/tbb.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
#include "subd/patch_table.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Global state of object transform update. */
|
||||
@@ -587,7 +585,6 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
|
||||
geom->is_hair() ? static_cast<Hair *>(geom)->get_curve_keys().size() :
|
||||
geom->is_pointcloud() ? static_cast<PointCloud *>(geom)->num_points() :
|
||||
0;
|
||||
kobject.patch_map_offset = 0;
|
||||
kobject.attribute_map_offset = 0;
|
||||
|
||||
if (ob->asset_name_is_modified() || update_all) {
|
||||
@@ -972,21 +969,6 @@ void ObjectManager::device_update_geom_offsets(Device * /*unused*/,
|
||||
for (Object *object : scene->objects) {
|
||||
Geometry *geom = object->geometry;
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->patch_table) {
|
||||
const uint patch_map_offset = 2 * (mesh->patch_table_offset +
|
||||
mesh->patch_table->total_size() -
|
||||
mesh->patch_table->num_nodes * PATCH_NODE_SIZE) -
|
||||
mesh->patch_offset;
|
||||
|
||||
if (kobjects[object->index].patch_map_offset != patch_map_offset) {
|
||||
kobjects[object->index].patch_map_offset = patch_map_offset;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t attr_map_offset = object->attr_map_offset;
|
||||
|
||||
/* An object attribute map cannot have a zero offset because mesh maps come first. */
|
||||
|
||||
@@ -501,15 +501,7 @@ void Scene::update_kernel_features()
|
||||
if (object->get_is_shadow_catcher() && !geom->is_light()) {
|
||||
kernel_features |= KERNEL_FEATURE_SHADOW_CATCHER;
|
||||
}
|
||||
if (geom->is_mesh()) {
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
|
||||
kernel_features |= KERNEL_FEATURE_PATCH_EVALUATION;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (geom->is_hair()) {
|
||||
if (geom->is_hair()) {
|
||||
kernel_features |= KERNEL_FEATURE_HAIR;
|
||||
}
|
||||
else if (geom->is_pointcloud()) {
|
||||
@@ -595,8 +587,6 @@ static void log_kernel_features(const uint features)
|
||||
VLOG_INFO << "Use Baking " << string_from_bool(features & KERNEL_FEATURE_BAKING) << "\n";
|
||||
VLOG_INFO << "Use Subsurface " << string_from_bool(features & KERNEL_FEATURE_SUBSURFACE) << "\n";
|
||||
VLOG_INFO << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_VOLUME) << "\n";
|
||||
VLOG_INFO << "Use Patch Evaluation "
|
||||
<< string_from_bool(features & KERNEL_FEATURE_PATCH_EVALUATION) << "\n";
|
||||
VLOG_INFO << "Use Shadow Catcher " << string_from_bool(features & KERNEL_FEATURE_SHADOW_CATCHER)
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ set(SRC
|
||||
osd.cpp
|
||||
patch.cpp
|
||||
split.cpp
|
||||
patch_table.cpp
|
||||
)
|
||||
|
||||
set(SRC_HEADERS
|
||||
@@ -24,7 +23,6 @@ set(SRC_HEADERS
|
||||
interpolation.h
|
||||
osd.h
|
||||
patch.h
|
||||
patch_table.h
|
||||
split.h
|
||||
subpatch.h
|
||||
)
|
||||
|
||||
@@ -14,15 +14,11 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
EdgeDice::EdgeDice(const SubdParams ¶ms_) : params(params_)
|
||||
{
|
||||
mesh_P = nullptr;
|
||||
mesh_N = nullptr;
|
||||
vert_offset = 0;
|
||||
|
||||
params.mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
|
||||
|
||||
if (params.ptex) {
|
||||
params.mesh->attributes.add(ATTR_STD_PTEX_UV);
|
||||
params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID);
|
||||
params.mesh->attributes.add(ATTR_STD_PTEX_UV);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,18 +26,24 @@ void EdgeDice::reserve(const int num_verts, const int num_triangles)
|
||||
{
|
||||
Mesh *mesh = params.mesh;
|
||||
|
||||
vert_offset = mesh->get_verts().size();
|
||||
tri_offset = mesh->num_triangles();
|
||||
mesh->num_subd_added_verts = num_verts;
|
||||
|
||||
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);
|
||||
|
||||
mesh_P = mesh->verts.data() + vert_offset;
|
||||
mesh_N = attr_vN->data_float3() + vert_offset;
|
||||
mesh_P = mesh->verts.data();
|
||||
mesh_N = attr_vN->data_float3();
|
||||
|
||||
params.mesh->num_subd_verts += num_verts;
|
||||
Attribute *attr_ptex_face_id = mesh->attributes.find(ATTR_STD_PTEX_FACE_ID);
|
||||
if (attr_ptex_face_id) {
|
||||
mesh_ptex_face_id = attr_ptex_face_id->data_float();
|
||||
}
|
||||
Attribute *attr_ptex_uv = mesh->attributes.find(ATTR_STD_PTEX_UV);
|
||||
if (attr_ptex_uv) {
|
||||
mesh_ptex_uv = attr_ptex_uv->data_float2();
|
||||
}
|
||||
}
|
||||
|
||||
void EdgeDice::set_vert(Patch *patch, const int index, const float2 uv)
|
||||
@@ -55,17 +57,36 @@ void EdgeDice::set_vert(Patch *patch, const int index, const float2 uv)
|
||||
|
||||
mesh_P[index] = P;
|
||||
mesh_N[index] = N;
|
||||
params.mesh->vert_patch_uv[index + vert_offset] = make_float2(uv.x, uv.y);
|
||||
}
|
||||
|
||||
void EdgeDice::add_triangle(Patch *patch, const int v0, const int v1, const int v2)
|
||||
void EdgeDice::add_triangle(const Patch *patch,
|
||||
const int v0,
|
||||
const int v1,
|
||||
const int v2,
|
||||
const float2 uv0,
|
||||
const float2 uv1,
|
||||
const float2 uv2)
|
||||
{
|
||||
Mesh *mesh = params.mesh;
|
||||
|
||||
mesh->add_triangle(v0 + vert_offset, v1 + vert_offset, v2 + vert_offset, patch->shader, true);
|
||||
params.mesh->triangle_patch[params.mesh->num_triangles() - 1] = patch->patch_index;
|
||||
mesh->add_triangle(v0, v1, v2, patch->shader, true);
|
||||
|
||||
tri_offset++;
|
||||
const int triangle_offset = params.mesh->num_triangles() - 1;
|
||||
|
||||
params.mesh->subd_triangle_patch_index[triangle_offset] = patch->patch_index;
|
||||
if (mesh_ptex_face_id) {
|
||||
mesh_ptex_face_id[triangle_offset] = patch->patch_index;
|
||||
}
|
||||
|
||||
params.mesh->subd_corner_patch_uv[(triangle_offset * 3) + 0] = uv0;
|
||||
params.mesh->subd_corner_patch_uv[(triangle_offset * 3) + 1] = uv1;
|
||||
params.mesh->subd_corner_patch_uv[(triangle_offset * 3) + 2] = uv2;
|
||||
|
||||
if (mesh_ptex_uv) {
|
||||
mesh_ptex_uv[(triangle_offset * 3) + 0] = uv0;
|
||||
mesh_ptex_uv[(triangle_offset * 3) + 0] = uv1;
|
||||
mesh_ptex_uv[(triangle_offset * 3) + 0] = uv2;
|
||||
}
|
||||
}
|
||||
|
||||
void EdgeDice::stitch_triangles(Subpatch &sub, const int edge)
|
||||
@@ -82,41 +103,80 @@ void EdgeDice::stitch_triangles(Subpatch &sub, const int edge)
|
||||
return; // XXX avoid crashes for Mu or Mv == 1, missing polygons
|
||||
}
|
||||
|
||||
/* stitch together two arrays of verts with triangles. at each step,
|
||||
* we compare using the next verts on both sides, to find the split
|
||||
* direction with the smallest diagonal, and use that in order to keep
|
||||
* the triangle shape reasonable. */
|
||||
const float du = 1.0f / (float)Mu;
|
||||
const float dv = 1.0f / (float)Mv;
|
||||
float2 inner_uv, outer_uv, inner_uv_step, outer_uv_step;
|
||||
switch (edge) {
|
||||
case 0:
|
||||
inner_uv = make_float2(du, dv);
|
||||
outer_uv = make_float2(0.0f, 0.0f);
|
||||
inner_uv_step = make_float2(du, 0.0f);
|
||||
outer_uv_step = make_float2(1.0f / (float)outer_T, 0.0f);
|
||||
break;
|
||||
case 1:
|
||||
inner_uv = make_float2(1.0f - du, dv);
|
||||
outer_uv = make_float2(1.0f, 0.0f);
|
||||
inner_uv_step = make_float2(0.0f, dv);
|
||||
outer_uv_step = make_float2(0.0f, 1.0f / (float)outer_T);
|
||||
break;
|
||||
case 2:
|
||||
inner_uv = make_float2(1.0f - du, 1.0f - dv);
|
||||
outer_uv = make_float2(1.0f, 1.0f);
|
||||
inner_uv_step = make_float2(-du, 0.0f);
|
||||
outer_uv_step = make_float2(-1.0f / (float)outer_T, 0.0f);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
inner_uv = make_float2(du, 1.0f - dv);
|
||||
outer_uv = make_float2(0.0f, 1.0f);
|
||||
inner_uv_step = make_float2(0.0f, -dv);
|
||||
outer_uv_step = make_float2(0.0f, -1.0f / (float)outer_T);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Stitch together two arrays of verts with triangles. at each step, we compare using the next
|
||||
* verts on both sides, to find the split direction with the smallest diagonal, and use that
|
||||
* in order to keep the triangle shape reasonable. */
|
||||
for (size_t i = 0, j = 0; i < inner_T || j < outer_T;) {
|
||||
int v0;
|
||||
int v1;
|
||||
const int v0 = sub.get_vert_along_grid_edge(edge, i);
|
||||
const int v1 = sub.get_vert_along_edge(edge, j);
|
||||
int v2;
|
||||
|
||||
v0 = sub.get_vert_along_grid_edge(edge, i);
|
||||
v1 = sub.get_vert_along_edge(edge, j);
|
||||
const float2 uv0 = sub.map_uv(inner_uv);
|
||||
const float2 uv1 = sub.map_uv(outer_uv);
|
||||
float2 uv2;
|
||||
|
||||
if (j == outer_T) {
|
||||
v2 = sub.get_vert_along_grid_edge(edge, ++i);
|
||||
inner_uv += inner_uv_step;
|
||||
uv2 = sub.map_uv(inner_uv);
|
||||
}
|
||||
else if (i == inner_T) {
|
||||
v2 = sub.get_vert_along_edge(edge, ++j);
|
||||
outer_uv += outer_uv_step;
|
||||
uv2 = sub.map_uv(outer_uv);
|
||||
}
|
||||
else {
|
||||
/* length of diagonals */
|
||||
/* Length of diagonals. */
|
||||
const float len1 = len_squared(mesh_P[sub.get_vert_along_grid_edge(edge, i)] -
|
||||
mesh_P[sub.get_vert_along_edge(edge, j + 1)]);
|
||||
const float len2 = len_squared(mesh_P[sub.get_vert_along_edge(edge, j)] -
|
||||
mesh_P[sub.get_vert_along_grid_edge(edge, i + 1)]);
|
||||
|
||||
/* use smallest diagonal */
|
||||
/* Use smallest diagonal. */
|
||||
if (len1 < len2) {
|
||||
v2 = sub.get_vert_along_edge(edge, ++j);
|
||||
outer_uv += outer_uv_step;
|
||||
uv2 = sub.map_uv(outer_uv);
|
||||
}
|
||||
else {
|
||||
v2 = sub.get_vert_along_grid_edge(edge, ++i);
|
||||
inner_uv += inner_uv_step;
|
||||
uv2 = sub.map_uv(inner_uv);
|
||||
}
|
||||
}
|
||||
|
||||
add_triangle(sub.patch, v1, v0, v2);
|
||||
add_triangle(sub.patch, v1, v0, v2, uv1, uv0, uv2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,17 +184,8 @@ void EdgeDice::stitch_triangles(Subpatch &sub, const int edge)
|
||||
|
||||
QuadDice::QuadDice(const SubdParams ¶ms_) : EdgeDice(params_) {}
|
||||
|
||||
float2 QuadDice::map_uv(Subpatch &sub, const float u, float v)
|
||||
float3 QuadDice::eval_projected(Subpatch &sub, const float2 uv)
|
||||
{
|
||||
/* map UV from subpatch to patch parametric coordinates */
|
||||
const float2 d0 = interp(sub.c00, sub.c01, v);
|
||||
const float2 d1 = interp(sub.c10, sub.c11, v);
|
||||
return interp(d0, d1, u);
|
||||
}
|
||||
|
||||
float3 QuadDice::eval_projected(Subpatch &sub, const float u, float v)
|
||||
{
|
||||
const float2 uv = map_uv(sub, u, v);
|
||||
float3 P;
|
||||
|
||||
sub.patch->eval(&P, nullptr, nullptr, nullptr, uv.x, uv.y);
|
||||
@@ -145,9 +196,9 @@ float3 QuadDice::eval_projected(Subpatch &sub, const float u, float v)
|
||||
return P;
|
||||
}
|
||||
|
||||
void QuadDice::set_vert(Subpatch &sub, const int index, const float u, float v)
|
||||
void QuadDice::set_vert(Subpatch &sub, const int index, const float2 uv)
|
||||
{
|
||||
EdgeDice::set_vert(sub.patch, index, map_uv(sub, u, v));
|
||||
EdgeDice::set_vert(sub.patch, index, sub.map_uv(uv));
|
||||
}
|
||||
|
||||
void QuadDice::set_side(Subpatch &sub, const int edge)
|
||||
@@ -158,29 +209,24 @@ void QuadDice::set_side(Subpatch &sub, const int edge)
|
||||
for (int i = 0; i < t; i++) {
|
||||
const float f = i / (float)t;
|
||||
|
||||
float u;
|
||||
float v;
|
||||
float2 uv;
|
||||
switch (edge) {
|
||||
case 0:
|
||||
u = 0;
|
||||
v = f;
|
||||
uv = make_float2(0.0f, f);
|
||||
break;
|
||||
case 1:
|
||||
u = f;
|
||||
v = 1;
|
||||
uv = make_float2(f, 1.0f);
|
||||
break;
|
||||
case 2:
|
||||
u = 1;
|
||||
v = 1.0f - f;
|
||||
uv = make_float2(1.0f, 1.0f - f);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
u = 1.0f - f;
|
||||
v = 0;
|
||||
uv = make_float2(1.0f - f, 0.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
set_vert(sub, sub.get_vert_along_edge(edge, i), u, v);
|
||||
set_vert(sub, sub.get_vert_along_edge(edge, i), uv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +242,7 @@ float QuadDice::scale_factor(Subpatch &sub, const int Mu, const int Mv)
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
P[i][j] = eval_projected(sub, i * 0.5f, j * 0.5f);
|
||||
P[i][j] = eval_projected(sub, sub.map_uv(make_float2(i * 0.5f, j * 0.5f)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,8 +276,9 @@ void QuadDice::add_grid(Subpatch &sub, const int Mu, const int Mv, const int off
|
||||
for (int i = 1; i < Mu; i++) {
|
||||
const float u = i * du;
|
||||
const float v = j * dv;
|
||||
const int center_i = offset + (i - 1) + (j - 1) * (Mu - 1);
|
||||
|
||||
set_vert(sub, offset + (i - 1) + (j - 1) * (Mu - 1), u, v);
|
||||
set_vert(sub, center_i, make_float2(u, v));
|
||||
|
||||
if (i < Mu - 1 && j < Mv - 1) {
|
||||
const int i1 = offset + (i - 1) + (j - 1) * (Mu - 1);
|
||||
@@ -239,8 +286,13 @@ void QuadDice::add_grid(Subpatch &sub, const int Mu, const int Mv, const int off
|
||||
const int i3 = offset + i + j * (Mu - 1);
|
||||
const int i4 = offset + (i - 1) + j * (Mu - 1);
|
||||
|
||||
add_triangle(sub.patch, i1, i2, i3);
|
||||
add_triangle(sub.patch, i1, i3, i4);
|
||||
const float2 uv1 = sub.map_uv(make_float2(u, v));
|
||||
const float2 uv2 = sub.map_uv(make_float2(u + du, v));
|
||||
const float2 uv3 = sub.map_uv(make_float2(u + du, v + dv));
|
||||
const float2 uv4 = sub.map_uv(make_float2(u, v + dv));
|
||||
|
||||
add_triangle(sub.patch, i1, i2, i3, uv1, uv2, uv3);
|
||||
add_triangle(sub.patch, i1, i3, i4, uv1, uv3, uv4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,17 +48,24 @@ struct SubdParams {
|
||||
class EdgeDice {
|
||||
public:
|
||||
SubdParams params;
|
||||
float3 *mesh_P;
|
||||
float3 *mesh_N;
|
||||
size_t vert_offset;
|
||||
size_t tri_offset;
|
||||
float3 *mesh_P = nullptr;
|
||||
float3 *mesh_N = nullptr;
|
||||
float *mesh_ptex_face_id = nullptr;
|
||||
float2 *mesh_ptex_uv = nullptr;
|
||||
|
||||
explicit EdgeDice(const SubdParams ¶ms);
|
||||
|
||||
void reserve(const int num_verts, const int num_triangles);
|
||||
|
||||
protected:
|
||||
void set_vert(Patch *patch, const int index, const float2 uv);
|
||||
void add_triangle(Patch *patch, const int v0, const int v1, const int v2);
|
||||
void add_triangle(const Patch *patch,
|
||||
const int v0,
|
||||
const int v1,
|
||||
const int v2,
|
||||
const float2 uv0,
|
||||
const float2 uv1,
|
||||
const float2 uv2);
|
||||
|
||||
void stitch_triangles(Subpatch &sub, const int edge);
|
||||
};
|
||||
@@ -69,10 +76,12 @@ class QuadDice : public EdgeDice {
|
||||
public:
|
||||
explicit QuadDice(const SubdParams ¶ms);
|
||||
|
||||
float3 eval_projected(Subpatch &sub, const float u, float v);
|
||||
void dice(Subpatch &sub);
|
||||
|
||||
float2 map_uv(Subpatch &sub, const float u, float v);
|
||||
void set_vert(Subpatch &sub, const int index, const float u, float v);
|
||||
protected:
|
||||
float3 eval_projected(Subpatch &sub, const float2 uv);
|
||||
|
||||
void set_vert(Subpatch &sub, const int index, const float2 uv);
|
||||
|
||||
void add_grid(Subpatch &sub, const int Mu, const int Mv, const int offset);
|
||||
|
||||
@@ -80,8 +89,6 @@ class QuadDice : public EdgeDice {
|
||||
|
||||
float quad_area(const float3 &a, const float3 &b, const float3 &c, const float3 &d);
|
||||
float scale_factor(Subpatch &sub, const int Mu, const int Mv);
|
||||
|
||||
void dice(Subpatch &sub);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
@@ -3,81 +3,302 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "subd/interpolation.h"
|
||||
#include "subd/osd.h"
|
||||
|
||||
#include "scene/attribute.h"
|
||||
#include "scene/mesh.h"
|
||||
|
||||
#include "util/color.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
/* Classes for interpolation to use float math for byte value, for precision. */
|
||||
template<typename T> struct SubdFloat {
|
||||
using Type = T;
|
||||
using AccumType = T;
|
||||
|
||||
void OsdData::subdivide_attribute(Attribute &attr)
|
||||
static Type read(const Type &value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
static Type output(const Type &value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
struct SubdByte {
|
||||
using Type = uchar4;
|
||||
using AccumType = float4;
|
||||
|
||||
static AccumType read(const Type &value)
|
||||
{
|
||||
return color_uchar4_to_float4(value);
|
||||
}
|
||||
|
||||
static Type output(const AccumType &value)
|
||||
{
|
||||
return color_float4_to_uchar4(value);
|
||||
}
|
||||
};
|
||||
|
||||
bool SubdAttributeInterpolation::support_interp_attribute(const Attribute &attr) const
|
||||
{
|
||||
const Far::PrimvarRefiner primvar_refiner(*refiner);
|
||||
|
||||
if (attr.element == ATTR_ELEMENT_VERTEX) {
|
||||
const int num_refiner_verts = refiner->GetNumVerticesTotal();
|
||||
const int num_local_points = patch_table->GetNumLocalPoints();
|
||||
|
||||
attr.resize(num_refiner_verts + num_local_points);
|
||||
attr.flags |= ATTR_FINAL_SIZE;
|
||||
|
||||
char *src = attr.buffer.data();
|
||||
|
||||
for (int i = 0; i < refiner->GetMaxLevel(); i++) {
|
||||
char *dest = src + refiner->GetLevel(i).GetNumVertices() * attr.data_sizeof();
|
||||
|
||||
if (Attribute::same_storage(attr.type, TypeFloat)) {
|
||||
primvar_refiner.Interpolate(i + 1, (OsdValue<float> *)src, (OsdValue<float> *&)dest);
|
||||
}
|
||||
else if (Attribute::same_storage(attr.type, TypeFloat2)) {
|
||||
primvar_refiner.Interpolate(i + 1, (OsdValue<float2> *)src, (OsdValue<float2> *&)dest);
|
||||
// float3 is not interchangeable with float4 and so needs to be handled
|
||||
// separately
|
||||
}
|
||||
else if (Attribute::same_storage(attr.type, TypeFloat4)) {
|
||||
primvar_refiner.Interpolate(i + 1, (OsdValue<float4> *)src, (OsdValue<float4> *&)dest);
|
||||
}
|
||||
else {
|
||||
primvar_refiner.Interpolate(i + 1, (OsdValue<float3> *)src, (OsdValue<float3> *&)dest);
|
||||
// TODO: Recompute UV tangent
|
||||
switch (attr.std) {
|
||||
/* Smooth normals are computed from derivatives, for linear interpolate. */
|
||||
case ATTR_STD_VERTEX_NORMAL:
|
||||
case ATTR_STD_MOTION_VERTEX_NORMAL:
|
||||
if (mesh.get_subdivision_type() == Mesh::SUBDIVISION_CATMULL_CLARK) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
/* Ptex coordinates will be computed by subdivision. */
|
||||
case ATTR_STD_PTEX_FACE_ID:
|
||||
case ATTR_STD_PTEX_UV:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
src = dest;
|
||||
}
|
||||
/* Skip element types that should not exist for subd attributes anyway. */
|
||||
switch (attr.element) {
|
||||
case ATTR_ELEMENT_VERTEX:
|
||||
case ATTR_ELEMENT_CORNER:
|
||||
case ATTR_ELEMENT_CORNER_BYTE:
|
||||
case ATTR_ELEMENT_VERTEX_MOTION:
|
||||
case ATTR_ELEMENT_FACE:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num_local_points) {
|
||||
if (Attribute::same_storage(attr.type, TypeFloat)) {
|
||||
patch_table->ComputeLocalPointValues(
|
||||
(OsdValue<float> *)attr.buffer.data(),
|
||||
(OsdValue<float> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
|
||||
}
|
||||
else if (Attribute::same_storage(attr.type, TypeFloat2)) {
|
||||
patch_table->ComputeLocalPointValues(
|
||||
(OsdValue<float2> *)attr.buffer.data(),
|
||||
(OsdValue<float2> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
|
||||
}
|
||||
else if (Attribute::same_storage(attr.type, TypeFloat4)) {
|
||||
// float3 is not interchangeable with float4 and so needs to be handled
|
||||
// separately
|
||||
patch_table->ComputeLocalPointValues(
|
||||
(OsdValue<float4> *)attr.buffer.data(),
|
||||
(OsdValue<float4> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
|
||||
}
|
||||
else {
|
||||
// float3 is not interchangeable with float4 and so needs to be handled
|
||||
// separately
|
||||
patch_table->ComputeLocalPointValues(
|
||||
(OsdValue<float3> *)attr.buffer.data(),
|
||||
(OsdValue<float3> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SubdAttributeInterpolation::interp_attribute(const Attribute &subd_attr, Attribute &mesh_attr)
|
||||
{
|
||||
if (subd_attr.element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
interp_attribute_type<SubdByte>(subd_attr, mesh_attr);
|
||||
}
|
||||
else if (Attribute::same_storage(subd_attr.type, TypeFloat)) {
|
||||
interp_attribute_type<SubdFloat<float>>(subd_attr, mesh_attr);
|
||||
}
|
||||
else if (Attribute::same_storage(subd_attr.type, TypeFloat2)) {
|
||||
interp_attribute_type<SubdFloat<float2>>(subd_attr, mesh_attr);
|
||||
}
|
||||
else if (Attribute::same_storage(subd_attr.type, TypeVector)) {
|
||||
interp_attribute_type<SubdFloat<float3>>(subd_attr, mesh_attr);
|
||||
}
|
||||
else if (Attribute::same_storage(subd_attr.type, TypeFloat4)) {
|
||||
interp_attribute_type<SubdFloat<float4>>(subd_attr, mesh_attr);
|
||||
}
|
||||
}
|
||||
const int *SubdAttributeInterpolation::get_ptex_face_mapping()
|
||||
{
|
||||
if (ptex_face_to_base_face.empty()) {
|
||||
ptex_face_to_base_face.resize(num_patches);
|
||||
|
||||
int *ptex_face_to_base_face_data = ptex_face_to_base_face.data();
|
||||
const size_t num_faces = mesh.get_num_subd_faces();
|
||||
int i = 0;
|
||||
|
||||
for (size_t f = 0; f < num_faces; f++) {
|
||||
Mesh::SubdFace face = mesh.get_subd_face(f);
|
||||
const int num_ptex_faces = (face.is_quad()) ? 1 : face.num_corners;
|
||||
for (int j = 0; j < num_ptex_faces; j++) {
|
||||
ptex_face_to_base_face_data[i++] = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
// TODO(mai): fvar interpolation
|
||||
|
||||
return ptex_face_to_base_face.data();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SubdAttributeInterpolation::interp_attribute_vertex_linear(const Attribute &subd_attr,
|
||||
Attribute &mesh_attr,
|
||||
const int motion_step)
|
||||
{
|
||||
const int *ptex_face_to_base_face_data = get_ptex_face_mapping();
|
||||
const int num_base_verts = mesh.get_num_subd_base_verts();
|
||||
|
||||
/* Interpolate values at vertices. */
|
||||
const size_t triangles_size = mesh.num_triangles();
|
||||
const int *patch_index = mesh.subd_triangle_patch_index.data();
|
||||
const float2 *patch_uv = mesh.subd_corner_patch_uv.data();
|
||||
const typename T::Type *subd_data = reinterpret_cast<const typename T::Type *>(
|
||||
subd_attr.data()) +
|
||||
motion_step * num_base_verts;
|
||||
typename T::Type *mesh_data = reinterpret_cast<typename T::Type *>(mesh_attr.data()) +
|
||||
motion_step * mesh.get_verts().size();
|
||||
const int *subd_face_corners = mesh.get_subd_face_corners().data();
|
||||
|
||||
for (size_t i = 0; i < triangles_size; i++) {
|
||||
const int p = patch_index[i];
|
||||
const int f = ptex_face_to_base_face_data[p];
|
||||
Mesh::SubdFace face = mesh.get_subd_face(f);
|
||||
Mesh::Triangle triangle = mesh.get_triangle(i);
|
||||
|
||||
if (face.is_quad()) {
|
||||
/* Simple case for quads. */
|
||||
const typename T::AccumType value0 = T::read(
|
||||
subd_data[subd_face_corners[face.start_corner + 0]]);
|
||||
const typename T::AccumType value1 = T::read(
|
||||
subd_data[subd_face_corners[face.start_corner + 1]]);
|
||||
const typename T::AccumType value2 = T::read(
|
||||
subd_data[subd_face_corners[face.start_corner + 2]]);
|
||||
const typename T::AccumType value3 = T::read(
|
||||
subd_data[subd_face_corners[face.start_corner + 3]]);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
const float2 uv = patch_uv[(i * 3) + j];
|
||||
const typename T::AccumType value = interp(
|
||||
interp(value0, value1, uv.x), interp(value3, value2, uv.x), uv.y);
|
||||
mesh_data[triangle.v[j]] = T::output(value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Other n-gons are split into n quads. */
|
||||
const int corner = p - face.ptex_offset;
|
||||
|
||||
/* Compute value at center of polygon. */
|
||||
typename T::AccumType value_center = T::read(
|
||||
subd_data[subd_face_corners[face.start_corner]]);
|
||||
for (int j = 1; j < face.num_corners; j++) {
|
||||
value_center += T::read(subd_data[subd_face_corners[face.start_corner + j]]);
|
||||
}
|
||||
value_center /= (float)face.num_corners;
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
const float2 uv = patch_uv[(i * 3) + j];
|
||||
|
||||
/* Compute value at corner at adjacent vertices. */
|
||||
const typename T::AccumType value_corner = T::read(
|
||||
subd_data[subd_face_corners[face.start_corner + corner]]);
|
||||
const typename T::AccumType value_prev =
|
||||
0.5f * (value_corner +
|
||||
T::read(subd_data[subd_face_corners[face.start_corner +
|
||||
mod(corner - 1, face.num_corners)]]));
|
||||
const typename T::AccumType value_next =
|
||||
0.5f * (value_corner +
|
||||
T::read(subd_data[subd_face_corners[face.start_corner +
|
||||
mod(corner + 1, face.num_corners)]]));
|
||||
|
||||
/* Interpolate. */
|
||||
const typename T::AccumType value = interp(
|
||||
interp(value_corner, value_next, uv.x), interp(value_prev, value_center, uv.x), uv.y);
|
||||
|
||||
mesh_data[triangle.v[j]] = T::output(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
template<typename T>
|
||||
void SubdAttributeInterpolation::interp_attribute_corner_linear(const Attribute &subd_attr,
|
||||
Attribute &mesh_attr)
|
||||
{
|
||||
const int *ptex_face_to_base_face_data = get_ptex_face_mapping();
|
||||
|
||||
/* Interpolate values at corners. */
|
||||
const size_t triangles_size = mesh.num_triangles();
|
||||
const int *patch_index = mesh.subd_triangle_patch_index.data();
|
||||
const float2 *patch_uv = mesh.subd_corner_patch_uv.data();
|
||||
const typename T::Type *subd_data = reinterpret_cast<const typename T::Type *>(subd_attr.data());
|
||||
typename T::Type *mesh_data = reinterpret_cast<typename T::Type *>(mesh_attr.data());
|
||||
|
||||
for (size_t i = 0; i < triangles_size; i++) {
|
||||
const int p = patch_index[i];
|
||||
const int f = ptex_face_to_base_face_data[p];
|
||||
Mesh::SubdFace face = mesh.get_subd_face(f);
|
||||
|
||||
if (face.is_quad()) {
|
||||
/* Simple case for quads. */
|
||||
const typename T::AccumType value0 = T::read(subd_data[face.start_corner + 0]);
|
||||
const typename T::AccumType value1 = T::read(subd_data[face.start_corner + 1]);
|
||||
const typename T::AccumType value2 = T::read(subd_data[face.start_corner + 2]);
|
||||
const typename T::AccumType value3 = T::read(subd_data[face.start_corner + 3]);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
const float2 uv = patch_uv[(i * 3) + j];
|
||||
const typename T::AccumType value = interp(
|
||||
interp(value0, value1, uv.x), interp(value3, value2, uv.x), uv.y);
|
||||
mesh_data[(i * 3) + j] = T::output(value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Other n-gons are split into n quads. */
|
||||
const int corner = p - face.ptex_offset;
|
||||
|
||||
/* Compute value at center of polygon. */
|
||||
typename T::AccumType value_center = T::read(subd_data[face.start_corner]);
|
||||
for (int j = 1; j < face.num_corners; j++) {
|
||||
value_center += T::read(subd_data[face.start_corner + j]);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
const float2 uv = patch_uv[(i * 3) + j];
|
||||
|
||||
/* Compute value at corner at adjacent vertices. */
|
||||
const typename T::AccumType value_corner = T::read(subd_data[face.start_corner + corner]);
|
||||
const typename T::AccumType value_prev =
|
||||
0.5f * (value_corner +
|
||||
T::read(subd_data[face.start_corner + mod(corner - 1, face.num_corners)]));
|
||||
const typename T::AccumType value_next =
|
||||
0.5f * (value_corner +
|
||||
T::read(subd_data[face.start_corner + mod(corner + 1, face.num_corners)]));
|
||||
|
||||
/* Interpolate. */
|
||||
const typename T::AccumType value = interp(
|
||||
interp(value_corner, value_next, uv.x), interp(value_prev, value_center, uv.x), uv.y);
|
||||
|
||||
mesh_data[(i * 3) + j] = T::output(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SubdAttributeInterpolation::interp_attribute_face(const Attribute &subd_attr,
|
||||
Attribute &mesh_attr)
|
||||
{
|
||||
const int *ptex_face_to_base_face_data = get_ptex_face_mapping();
|
||||
|
||||
/* Interpolate values at corners. */
|
||||
const size_t triangles_size = mesh.num_triangles();
|
||||
const int *patch_index = mesh.subd_triangle_patch_index.data();
|
||||
const typename T::Type *subd_data = reinterpret_cast<const typename T::Type *>(subd_attr.data());
|
||||
typename T::Type *mesh_data = reinterpret_cast<typename T::Type *>(mesh_attr.data());
|
||||
|
||||
for (size_t i = 0; i < triangles_size; i++) {
|
||||
const int p = patch_index[i];
|
||||
const int f = ptex_face_to_base_face_data[p];
|
||||
mesh_data[i] = subd_data[f];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SubdAttributeInterpolation::interp_attribute_type(const Attribute &subd_attr,
|
||||
Attribute &mesh_attr)
|
||||
{
|
||||
switch (subd_attr.element) {
|
||||
case ATTR_ELEMENT_VERTEX: {
|
||||
interp_attribute_vertex_linear<T>(subd_attr, mesh_attr);
|
||||
break;
|
||||
}
|
||||
case ATTR_ELEMENT_CORNER:
|
||||
case ATTR_ELEMENT_CORNER_BYTE: {
|
||||
interp_attribute_corner_linear<T>(subd_attr, mesh_attr);
|
||||
break;
|
||||
}
|
||||
case ATTR_ELEMENT_FACE: {
|
||||
interp_attribute_face<T>(subd_attr, mesh_attr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
@@ -4,6 +4,64 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "subd/osd.h"
|
||||
|
||||
#include "util/vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Mesh;
|
||||
class Attribute;
|
||||
|
||||
/* Attribute Interpolation. */
|
||||
|
||||
class SubdAttributeInterpolation {
|
||||
protected:
|
||||
Mesh &mesh;
|
||||
int num_patches;
|
||||
vector<int> ptex_face_to_base_face;
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
OsdMesh &osd_mesh;
|
||||
OsdData &osd_data;
|
||||
#endif
|
||||
|
||||
public:
|
||||
SubdAttributeInterpolation(Mesh &mesh,
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
OsdMesh &osd_mesh,
|
||||
OsdData &osd_data,
|
||||
#endif
|
||||
const int num_patches)
|
||||
: mesh(mesh),
|
||||
num_patches(num_patches)
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
,
|
||||
osd_mesh(osd_mesh),
|
||||
osd_data(osd_data)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
bool support_interp_attribute(const Attribute &attr) const;
|
||||
void interp_attribute(const Attribute &subd_attr, Attribute &mesh_attr);
|
||||
|
||||
protected:
|
||||
/* PTex face id to base mesh face mapping. */
|
||||
const int *get_ptex_face_mapping();
|
||||
|
||||
template<typename T>
|
||||
void interp_attribute_vertex_linear(const Attribute &subd_attr,
|
||||
Attribute &mesh_attr,
|
||||
const int motion_step = 0);
|
||||
template<typename T>
|
||||
void interp_attribute_corner_linear(const Attribute &subd_attr, Attribute &mesh_attr);
|
||||
|
||||
template<typename T>
|
||||
void interp_attribute_face(const Attribute &subd_attr, Attribute &mesh_attr);
|
||||
|
||||
template<typename T>
|
||||
void interp_attribute_type(const Attribute &subd_attr, Attribute &mesh_attr);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
@@ -23,7 +23,7 @@ bool TopologyRefinerFactory<OsdMesh>::resizeComponentTopology(TopologyRefiner &r
|
||||
{
|
||||
const Mesh &mesh = osd_mesh.mesh;
|
||||
|
||||
const int num_base_verts = mesh.get_verts().size();
|
||||
const int num_base_verts = mesh.get_num_subd_base_verts();
|
||||
const int num_base_faces = mesh.get_num_subd_faces();
|
||||
const int *subd_num_corners = mesh.get_subd_num_corners().data();
|
||||
|
||||
@@ -98,7 +98,7 @@ bool TopologyRefinerFactory<OsdMesh>::assignComponentTags(TopologyRefiner &refin
|
||||
vertex_creases[vertex_idx] = weight * CREASE_SCALE;
|
||||
}
|
||||
|
||||
const int num_base_verts = mesh.get_verts().size();
|
||||
const int num_base_verts = mesh.get_num_subd_base_verts();
|
||||
|
||||
for (int i = 0; i < num_base_verts; i++) {
|
||||
float sharpness = 0.0f;
|
||||
@@ -171,7 +171,7 @@ void OsdData::build(OsdMesh &osd_mesh)
|
||||
/* interpolate verts */
|
||||
const int num_refiner_verts = refiner->GetNumVerticesTotal();
|
||||
const int num_local_points = patch_table->GetNumLocalPoints();
|
||||
const int num_base_verts = osd_mesh.mesh.get_verts().size();
|
||||
const int num_base_verts = osd_mesh.mesh.get_num_subd_base_verts();
|
||||
const float3 *verts_data = osd_mesh.mesh.get_verts().data();
|
||||
|
||||
refined_verts.resize(num_refiner_verts + num_local_points);
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2014 DreamWorks Animation LLC
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/** \file
|
||||
* Based on code from OpenSubdiv.
|
||||
*/
|
||||
|
||||
#include "subd/patch_table.h"
|
||||
#include "kernel/types.h"
|
||||
|
||||
#include "util/math.h"
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
# include <opensubdiv/far/patchTable.h>
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
/* functions for building patch maps */
|
||||
|
||||
struct PatchMapQuadNode {
|
||||
/* sets all the children to point to the patch of index */
|
||||
void set_child(const int index)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF;
|
||||
}
|
||||
}
|
||||
|
||||
/* sets the child in quadrant to point to the node or patch of the given index */
|
||||
void set_child(unsigned char quadrant, const int index, bool is_leaf = true)
|
||||
{
|
||||
assert(quadrant < 4);
|
||||
children[quadrant] = index | PATCH_MAP_NODE_IS_SET | (is_leaf ? PATCH_MAP_NODE_IS_LEAF : 0);
|
||||
}
|
||||
|
||||
uint children[4];
|
||||
};
|
||||
|
||||
template<class T> static int resolve_quadrant(T &median, T &u, T &v)
|
||||
{
|
||||
int quadrant = -1;
|
||||
|
||||
if (u < median) {
|
||||
if (v < median) {
|
||||
quadrant = 0;
|
||||
}
|
||||
else {
|
||||
quadrant = 1;
|
||||
v -= median;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (v < median) {
|
||||
quadrant = 3;
|
||||
}
|
||||
else {
|
||||
quadrant = 2;
|
||||
v -= median;
|
||||
}
|
||||
u -= median;
|
||||
}
|
||||
|
||||
return quadrant;
|
||||
}
|
||||
|
||||
static void build_patch_map(PackedPatchTable &table,
|
||||
OpenSubdiv::Far::PatchTable *patch_table,
|
||||
int offset)
|
||||
{
|
||||
int num_faces = 0;
|
||||
|
||||
for (int array = 0; array < table.num_arrays; array++) {
|
||||
const Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
|
||||
|
||||
for (int j = 0; j < patch_table->GetNumPatches(array); j++) {
|
||||
num_faces = max(num_faces, (int)params[j].GetFaceId());
|
||||
}
|
||||
}
|
||||
num_faces++;
|
||||
|
||||
vector<PatchMapQuadNode> quadtree;
|
||||
quadtree.reserve(num_faces + table.num_patches);
|
||||
quadtree.resize(num_faces);
|
||||
|
||||
/* adjust offsets to make indices relative to the table */
|
||||
int handle_index = -(table.num_patches * PATCH_HANDLE_SIZE);
|
||||
offset += table.total_size();
|
||||
|
||||
/* populate the quadtree from the FarPatchArrays sub-patches */
|
||||
for (int array = 0; array < table.num_arrays; array++) {
|
||||
const Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
|
||||
|
||||
for (int i = 0; i < patch_table->GetNumPatches(array); i++, handle_index += PATCH_HANDLE_SIZE)
|
||||
{
|
||||
const Far::PatchParam ¶m = params[i];
|
||||
const unsigned short depth = param.GetDepth();
|
||||
|
||||
PatchMapQuadNode *node = &quadtree[params[i].GetFaceId()];
|
||||
|
||||
if (depth == (param.NonQuadRoot() ? 1 : 0)) {
|
||||
/* special case : regular BSpline face w/ no sub-patches */
|
||||
node->set_child(handle_index + offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
int u = param.GetU();
|
||||
int v = param.GetV();
|
||||
const int pdepth = param.NonQuadRoot() ? depth - 2 : depth - 1;
|
||||
int half = 1 << pdepth;
|
||||
|
||||
for (int j = 0; j < depth; j++) {
|
||||
const int delta = half >> 1;
|
||||
|
||||
const int quadrant = resolve_quadrant(half, u, v);
|
||||
assert(quadrant >= 0);
|
||||
|
||||
half = delta;
|
||||
|
||||
if (j == pdepth) {
|
||||
/* we have reached the depth of the sub-patch : add a leaf */
|
||||
assert(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET));
|
||||
node->set_child(quadrant, handle_index + offset, true);
|
||||
break;
|
||||
}
|
||||
/* travel down the child node of the corresponding quadrant */
|
||||
if (!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET)) {
|
||||
/* create a new branch in the quadrant */
|
||||
quadtree.push_back(PatchMapQuadNode());
|
||||
|
||||
const int idx = (int)quadtree.size() - 1;
|
||||
node->set_child(quadrant, idx * 4 + offset, false);
|
||||
|
||||
node = &quadtree[idx];
|
||||
}
|
||||
else {
|
||||
/* travel down an existing branch */
|
||||
const uint idx = node->children[quadrant] & PATCH_MAP_NODE_INDEX_MASK;
|
||||
node = &(quadtree[(idx - offset) / 4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* copy into table */
|
||||
assert(table.table.size() == table.total_size());
|
||||
const uint map_offset = table.total_size();
|
||||
|
||||
table.num_nodes = quadtree.size() * 4;
|
||||
table.table.resize(table.total_size());
|
||||
|
||||
uint *data = &table.table[map_offset];
|
||||
|
||||
for (int i = 0; i < quadtree.size(); i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
assert(quadtree[i].children[j] & PATCH_MAP_NODE_IS_SET);
|
||||
*(data++) = quadtree[i].children[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* packed patch table functions */
|
||||
|
||||
size_t PackedPatchTable::total_size()
|
||||
{
|
||||
return num_arrays * PATCH_ARRAY_SIZE + num_indices +
|
||||
num_patches * (PATCH_PARAM_SIZE + PATCH_HANDLE_SIZE) + num_nodes * PATCH_NODE_SIZE;
|
||||
}
|
||||
|
||||
void PackedPatchTable::pack(Far::PatchTable *patch_table, const int offset)
|
||||
{
|
||||
num_arrays = 0;
|
||||
num_patches = 0;
|
||||
num_indices = 0;
|
||||
num_nodes = 0;
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
num_arrays = patch_table->GetNumPatchArrays();
|
||||
|
||||
for (int i = 0; i < num_arrays; i++) {
|
||||
const int patches = patch_table->GetNumPatches(i);
|
||||
const int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
|
||||
|
||||
num_patches += patches;
|
||||
num_indices += patches * num_control;
|
||||
}
|
||||
|
||||
table.resize(total_size());
|
||||
uint *data = table.data();
|
||||
|
||||
uint *array = data;
|
||||
uint *index = array + num_arrays * PATCH_ARRAY_SIZE;
|
||||
uint *param = index + num_indices;
|
||||
uint *handle = param + num_patches * PATCH_PARAM_SIZE;
|
||||
|
||||
uint current_param = 0;
|
||||
|
||||
for (int i = 0; i < num_arrays; i++) {
|
||||
*(array++) = patch_table->GetPatchArrayDescriptor(i).GetType();
|
||||
*(array++) = patch_table->GetNumPatches(i);
|
||||
*(array++) = (index - data) + offset;
|
||||
*(array++) = (param - data) + offset;
|
||||
|
||||
const Far::ConstIndexArray indices = patch_table->GetPatchArrayVertices(i);
|
||||
|
||||
for (int j = 0; j < indices.size(); j++) {
|
||||
*(index++) = indices[j];
|
||||
}
|
||||
|
||||
const Far::PatchParamTable ¶m_table = patch_table->GetPatchParamTable();
|
||||
|
||||
const int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
|
||||
const int patches = patch_table->GetNumPatches(i);
|
||||
|
||||
for (int j = 0; j < patches; j++, current_param++) {
|
||||
*(param++) = param_table[current_param].field0;
|
||||
*(param++) = param_table[current_param].field1;
|
||||
|
||||
*(handle++) = (array - data) - PATCH_ARRAY_SIZE + offset;
|
||||
*(handle++) = (param - data) - PATCH_PARAM_SIZE + offset;
|
||||
*(handle++) = j * num_control;
|
||||
}
|
||||
}
|
||||
|
||||
build_patch_map(*this, patch_table, offset);
|
||||
#else
|
||||
(void)patch_table;
|
||||
(void)offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PackedPatchTable::copy_adjusting_offsets(uint *dest, const int doffset)
|
||||
{
|
||||
uint *src = table.data();
|
||||
|
||||
/* arrays */
|
||||
for (int i = 0; i < num_arrays; i++) {
|
||||
*(dest++) = *(src++);
|
||||
*(dest++) = *(src++);
|
||||
*(dest++) = *(src++) + doffset;
|
||||
*(dest++) = *(src++) + doffset;
|
||||
}
|
||||
|
||||
/* indices */
|
||||
for (int i = 0; i < num_indices; i++) {
|
||||
*(dest++) = *(src++);
|
||||
}
|
||||
|
||||
/* params */
|
||||
for (int i = 0; i < num_patches; i++) {
|
||||
*(dest++) = *(src++);
|
||||
*(dest++) = *(src++);
|
||||
}
|
||||
|
||||
/* handles */
|
||||
for (int i = 0; i < num_patches; i++) {
|
||||
*(dest++) = *(src++) + doffset;
|
||||
*(dest++) = *(src++) + doffset;
|
||||
*(dest++) = *(src++);
|
||||
}
|
||||
|
||||
/* nodes */
|
||||
for (int i = 0; i < num_nodes; i++) {
|
||||
*(dest++) = *(src++) + doffset;
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
@@ -1,51 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/array.h"
|
||||
#include "util/types.h"
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
# ifdef _MSC_VER
|
||||
# include "iso646.h"
|
||||
# endif
|
||||
|
||||
# include <opensubdiv/far/patchTable.h>
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
using namespace OpenSubdiv;
|
||||
#else
|
||||
/* forward declare for when OpenSubdiv is unavailable */
|
||||
namespace Far {
|
||||
struct PatchTable;
|
||||
}
|
||||
#endif
|
||||
|
||||
// NOLINTBEGIN
|
||||
#define PATCH_ARRAY_SIZE 4
|
||||
#define PATCH_PARAM_SIZE 2
|
||||
#define PATCH_HANDLE_SIZE 3
|
||||
#define PATCH_NODE_SIZE 1
|
||||
// NOLINTEND
|
||||
|
||||
struct PackedPatchTable {
|
||||
array<uint> table;
|
||||
|
||||
size_t num_arrays;
|
||||
size_t num_indices;
|
||||
size_t num_patches;
|
||||
size_t num_nodes;
|
||||
|
||||
/* calculated size from num_* members */
|
||||
size_t total_size();
|
||||
|
||||
void pack(Far::PatchTable *patch_table, const int offset = 0);
|
||||
void copy_adjusting_offsets(uint *dest, const int doffset);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
@@ -115,6 +115,14 @@ class Subpatch {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
float2 map_uv(float2 uv)
|
||||
{
|
||||
/* Map UV from subpatch to patch parametric coordinates. */
|
||||
const float2 d0 = interp(c00, c01, uv.y);
|
||||
const float2 d1 = interp(c10, c11, uv.y);
|
||||
return clamp(interp(d0, d1, uv.x), zero_float2(), one_float2());
|
||||
}
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
|
||||
@@ -499,7 +499,12 @@ ccl_device_inline int mod(const int x, const int m)
|
||||
return (x % m + m) % m;
|
||||
}
|
||||
|
||||
ccl_device_inline float inverse_lerp(const float a, const float b, float x)
|
||||
ccl_device_inline float interp(const float a, const float b, const float t)
|
||||
{
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
ccl_device_inline float inverse_lerp(const float a, const float b, const float x)
|
||||
{
|
||||
return (x - a) / (b - a);
|
||||
}
|
||||
|
||||
@@ -608,6 +608,11 @@ ccl_device_inline float4 power(const float4 v, const float e)
|
||||
return make_float4(powf(v.x, e), powf(v.y, e), powf(v.z, e), powf(v.w, e));
|
||||
}
|
||||
|
||||
ccl_device_inline float4 interp(float4 a, float4 b, float t)
|
||||
{
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
#if !defined(__KERNEL_METAL__) && !defined(__KERNEL_ONEAPI__)
|
||||
/* Int/Float conversion */
|
||||
ccl_device_inline int4 __float4_as_int4(const float4 f)
|
||||
|
||||
@@ -18,6 +18,7 @@ using OIIO::ParamValue;
|
||||
using OIIO::TypeColor;
|
||||
using OIIO::TypeDesc;
|
||||
using OIIO::TypeFloat;
|
||||
using OIIO::TypeFloat2;
|
||||
using OIIO::TypeFloat4;
|
||||
using OIIO::TypeInt;
|
||||
using OIIO::TypeMatrix;
|
||||
@@ -27,7 +28,6 @@ using OIIO::TypeString;
|
||||
using OIIO::TypeUnknown;
|
||||
using OIIO::TypeVector;
|
||||
|
||||
static constexpr TypeDesc TypeFloat2(TypeDesc::FLOAT, TypeDesc::VEC2);
|
||||
static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR);
|
||||
static constexpr TypeDesc TypeFloatArray4(TypeDesc::FLOAT,
|
||||
TypeDesc::SCALAR,
|
||||
|
||||
@@ -34,6 +34,12 @@ ccl_device_inline uchar4 make_uchar4(const uchar x, const uchar y, uchar z, cons
|
||||
uchar4 a = {x, y, z, w};
|
||||
return a;
|
||||
}
|
||||
|
||||
ccl_device_inline bool operator==(const uchar4 a, const uchar4 b)
|
||||
{
|
||||
return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
|
||||
}
|
||||
|
||||
#endif /* __KERNEL_NATIVE_VECTOR_TYPES__ */
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
Reference in New Issue
Block a user