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:
		@@ -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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user