Cycles microdisplacement: Support for Catmull-Clark subdivision via OpenSubdiv

Enables Catmull-Clark subdivision meshes with support for creases and attribute
subdivision. Still waiting on OpenSubdiv to fully support face varying
interpolation for subdividing uv coordinates tho. Also there may be some
inconsistencies with Blender's subdivision which will be resolved at a
later time.

Code for reading patch tables and creating patch maps is borrowed
from OpenSubdiv.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D2111
This commit is contained in:
2016-07-16 22:57:06 -04:00
parent fc9747fa89
commit 0b68c68006
21 changed files with 1436 additions and 126 deletions

View File

@@ -30,6 +30,8 @@
#include "osl_globals.h"
#include "subd_patch_table.h"
#include "util_foreach.h"
#include "util_logging.h"
#include "util_progress.h"
@@ -112,7 +114,6 @@ float3 Mesh::SubdFace::normal(const Mesh *mesh) const
return safe_normalize(cross(v1 - v0, v2 - v0));
}
/* Mesh */
NODE_DEFINE(Mesh)
@@ -177,11 +178,14 @@ Mesh::Mesh()
num_ngons = 0;
subdivision_type = SUBDIVISION_NONE;
patch_table = NULL;
}
Mesh::~Mesh()
{
delete bvh;
delete patch_table;
}
void Mesh::resize_mesh(int numverts, int numtris)
@@ -274,6 +278,8 @@ void Mesh::clear()
num_subd_verts = 0;
subd_creases.clear();
attributes.clear();
curve_attributes.clear();
subd_attributes.clear();
@@ -283,6 +289,9 @@ void Mesh::clear()
transform_negative_scaled = false;
transform_normal = transform_identity();
geometry_flags = GEOMETRY_NONE;
delete patch_table;
patch_table = NULL;
}
int Mesh::split_vertex(int vertex)
@@ -705,7 +714,6 @@ void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, ui
}
}
void Mesh::compute_bvh(DeviceScene *dscene,
SceneParams *params,
Progress *progress,
@@ -834,6 +842,7 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
osl_attr.desc.element = ATTR_ELEMENT_OBJECT;
osl_attr.value = attr;
osl_attr.desc.offset = 0;
osl_attr.desc.flags = 0;
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][attr.name()] = osl_attr;
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr;
@@ -977,6 +986,8 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
attr_map[index].w = NODE_ATTR_MATRIX;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
attr_map[index].w |= req.triangle_desc.flags << 8;
}
index++;
@@ -992,6 +1003,8 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
attr_map[index].w = NODE_ATTR_MATRIX;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
attr_map[index].w |= req.curve_desc.flags << 8;
}
index++;
@@ -1007,6 +1020,8 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
attr_map[index].w = NODE_ATTR_MATRIX;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
attr_map[index].w |= req.subd_desc.flags << 8;
}
index++;
@@ -1071,6 +1086,7 @@ static void update_attribute_element_offset(Mesh *mesh,
if(mattr) {
/* store element and type */
desc.element = mattr->element;
desc.flags = mattr->flags;
type = mattr->type;
/* store attribute data in arrays */
@@ -1127,7 +1143,11 @@ static void update_attribute_element_offset(Mesh *mesh,
/* mesh vertex/curve index is global, not per object, so we sneak
* a correction for that in here */
if(element == ATTR_ELEMENT_VERTEX)
if(mesh->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)
offset -= mesh->vert_offset;
else if(element == ATTR_ELEMENT_VERTEX_MOTION)
offset -= mesh->vert_offset;
@@ -1323,6 +1343,12 @@ void MeshManager::mesh_calc_offset(Scene *scene)
if(mesh->subd_faces.size()) {
Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-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->subd_faces.size();
corner_size += mesh->subd_face_corners.size();
@@ -1354,6 +1380,12 @@ void MeshManager::device_update_mesh(Device *device,
if(mesh->subd_faces.size()) {
Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-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();
}
}
}
@@ -1436,6 +1468,11 @@ void MeshManager::device_update_mesh(Device *device,
foreach(Mesh *mesh, scene->meshes) {
mesh->pack_patches(&patch_data[mesh->patch_offset], mesh->vert_offset, mesh->face_offset, mesh->corner_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;
}
@@ -1648,6 +1685,10 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
}
if(progress.get_cancel()) return;
/* after mesh data has been copied to device memory we need to update
* offsets for patch tables as this can't be known before hand */
scene->object_manager->device_update_patch_map_offsets(device, dscene, scene);
device_update_attributes(device, dscene, scene, progress);
if(progress.get_cancel()) return;