diff options
author | Mai Lavelle <mai.lavelle@gmail.com> | 2016-07-17 02:42:28 +0300 |
---|---|---|
committer | Mai Lavelle <mai.lavelle@gmail.com> | 2016-07-29 10:36:30 +0300 |
commit | c96ae81160ad1a943fafaca44a7d5e97c2d7a0d7 (patch) | |
tree | 83905d5a6bf2583f44d9dcf90410b5a0c024822c /intern/cycles/render | |
parent | f74645578c9dd38c2543d1211b779a019363b04f (diff) |
Cycles microdisplacement: ngons and attributes for subdivision meshes
This adds support for ngons and attributes on subdivision meshes. Ngons are
needed for proper attribute interpolation as well as correct Catmull-Clark
subdivision. Several changes are made to achieve this:
- new primitive `SubdFace` added to `Mesh`
- 3 more textures are used to store info on patches from subd meshes
- Blender export uses loop interface instead of tessface for subd meshes
- `Attribute` class is updated with a simplified way to pass primitive counts
around and to support ngons.
- extra points for ngons are generated for O(1) attribute interpolation
- curves are temporally disabled on subd meshes to avoid various bugs with
implementation
- old unneeded code is removed from `subd/`
- various fixes and improvements
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D2108
Diffstat (limited to 'intern/cycles/render')
-rw-r--r-- | intern/cycles/render/CMakeLists.txt | 1 | ||||
-rw-r--r-- | intern/cycles/render/attribute.cpp | 96 | ||||
-rw-r--r-- | intern/cycles/render/attribute.h | 16 | ||||
-rw-r--r-- | intern/cycles/render/mesh.cpp | 427 | ||||
-rw-r--r-- | intern/cycles/render/mesh.h | 38 | ||||
-rw-r--r-- | intern/cycles/render/mesh_subdivision.cpp | 224 | ||||
-rw-r--r-- | intern/cycles/render/scene.h | 4 |
7 files changed, 656 insertions, 150 deletions
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index a632ddc0598..8eaa9de3874 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -30,6 +30,7 @@ set(SRC light.cpp mesh.cpp mesh_displace.cpp + mesh_subdivision.cpp nodes.cpp object.cpp osl.cpp diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index 71a3cba6811..e8ff81fe08e 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -51,13 +51,13 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_) type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix); } -void Attribute::resize(int numverts, int numtris, int numsteps, int numcurves, int numkeys, bool reserve_only) +void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only) { if(reserve_only) { - buffer.reserve(buffer_size(numverts, numtris, numsteps, numcurves, numkeys)); + buffer.reserve(buffer_size(mesh, prim)); } else { - buffer.resize(buffer_size(numverts, numtris, numsteps, numcurves, numkeys), 0); + buffer.resize(buffer_size(mesh, prim), 0); } } @@ -118,6 +118,8 @@ size_t Attribute::data_sizeof() const { if(element == ATTR_ELEMENT_VOXEL) return sizeof(VoxelAttribute); + else if(element == ATTR_ELEMENT_CORNER_BYTE) + return sizeof(uchar4); else if(type == TypeDesc::TypeFloat) return sizeof(float); else if(type == TypeDesc::TypeMatrix) @@ -126,10 +128,10 @@ size_t Attribute::data_sizeof() const return sizeof(float3); } -size_t Attribute::element_size(int numverts, int numtris, int numsteps, int numcurves, int numkeys) const +size_t Attribute::element_size(Mesh *mesh, AttributePrimitive prim) const { size_t size; - + switch(element) { case ATTR_ELEMENT_OBJECT: case ATTR_ELEMENT_MESH: @@ -137,38 +139,54 @@ size_t Attribute::element_size(int numverts, int numtris, int numsteps, int numc size = 1; break; case ATTR_ELEMENT_VERTEX: - size = numverts; + size = mesh->verts.size() + mesh->num_ngons; + if(prim == ATTR_PRIM_SUBD) { + size -= mesh->num_subd_verts; + } break; case ATTR_ELEMENT_VERTEX_MOTION: - size = numverts * (numsteps - 1); + size = (mesh->verts.size() + mesh->num_ngons) * (mesh->motion_steps - 1); + if(prim == ATTR_PRIM_SUBD) { + size -= mesh->num_subd_verts * (mesh->motion_steps - 1); + } break; case ATTR_ELEMENT_FACE: - size = numtris; + if(prim == ATTR_PRIM_TRIANGLE) { + size = mesh->num_triangles(); + } + else { + size = mesh->subd_faces.size() + mesh->num_ngons; + } break; case ATTR_ELEMENT_CORNER: case ATTR_ELEMENT_CORNER_BYTE: - size = numtris*3; + if(prim == ATTR_PRIM_TRIANGLE) { + size = mesh->num_triangles()*3; + } + else { + size = mesh->subd_face_corners.size() + mesh->num_ngons; + } break; case ATTR_ELEMENT_CURVE: - size = numcurves; + size = mesh->num_curves(); break; case ATTR_ELEMENT_CURVE_KEY: - size = numkeys; + size = mesh->curve_keys.size(); break; case ATTR_ELEMENT_CURVE_KEY_MOTION: - size = numkeys * (numsteps - 1); + size = mesh->curve_keys.size() * (mesh->motion_steps - 1); break; default: size = 0; break; } - + return size; } -size_t Attribute::buffer_size(int numverts, int numtris, int numsteps, int numcurves, int numkeys) const +size_t Attribute::buffer_size(Mesh *mesh, AttributePrimitive prim) const { - return element_size(numverts, numtris, numsteps, numcurves, numkeys)*data_sizeof(); + return element_size(mesh, prim)*data_sizeof(); } bool Attribute::same_storage(TypeDesc a, TypeDesc b) @@ -188,6 +206,29 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b) return false; } +void Attribute::zero_data(void* dst) +{ + memset(dst, 0, data_sizeof()); +} + +void Attribute::add_with_weight(void* dst, void* src, 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, TypeDesc::TypeFloat)) { + *((float*)dst) += *((float*)src) * weight; + } + else if(same_storage(type, TypeDesc::TypeVector)) { + *((float4*)dst) += *((float4*)src) * weight; + } + else { + assert(!"not implemented for this type"); + } +} + const char *Attribute::standard_name(AttributeStandard std) { switch(std) { @@ -257,6 +298,7 @@ AttributeSet::AttributeSet() { triangle_mesh = NULL; curve_mesh = NULL; + subd_mesh = NULL; } AttributeSet::~AttributeSet() @@ -291,10 +333,12 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme /* this is weak .. */ if(triangle_mesh) - attr->resize(triangle_mesh->verts.size(), triangle_mesh->num_triangles(), triangle_mesh->motion_steps, 0, 0, false); + attr->resize(triangle_mesh, ATTR_PRIM_TRIANGLE, false); if(curve_mesh) - attr->resize(0, 0, curve_mesh->motion_steps, curve_mesh->num_curves(), curve_mesh->curve_keys.size(), false); - + attr->resize(curve_mesh, ATTR_PRIM_CURVE, false); + if(subd_mesh) + attr->resize(subd_mesh, ATTR_PRIM_SUBD, false); + return attr; } @@ -330,7 +374,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) if(name == ustring()) name = Attribute::standard_name(std); - if(triangle_mesh) { + if(triangle_mesh || subd_mesh) { switch(std) { case ATTR_STD_VERTEX_NORMAL: attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX); @@ -452,9 +496,11 @@ void AttributeSet::resize(bool reserve_only) { foreach(Attribute& attr, attributes) { if(triangle_mesh) - attr.resize(triangle_mesh->verts.size(), triangle_mesh->num_triangles(), triangle_mesh->motion_steps, 0, 0, reserve_only); + attr.resize(triangle_mesh, ATTR_PRIM_TRIANGLE, reserve_only); if(curve_mesh) - attr.resize(0, 0, 0, curve_mesh->num_curves(), curve_mesh->curve_keys.size(), reserve_only); + attr.resize(curve_mesh, ATTR_PRIM_CURVE, reserve_only); + if(subd_mesh) + attr.resize(subd_mesh, ATTR_PRIM_SUBD, reserve_only); } } @@ -477,6 +523,10 @@ AttributeRequest::AttributeRequest(ustring name_) curve_type = TypeDesc::TypeFloat; curve_element = ATTR_ELEMENT_NONE; curve_offset = 0; + + subd_type = TypeDesc::TypeFloat; + subd_element = ATTR_ELEMENT_NONE; + subd_offset = 0; } AttributeRequest::AttributeRequest(AttributeStandard std_) @@ -491,6 +541,10 @@ AttributeRequest::AttributeRequest(AttributeStandard std_) curve_type = TypeDesc::TypeFloat; curve_element = ATTR_ELEMENT_NONE; curve_offset = 0; + + subd_type = TypeDesc::TypeFloat; + subd_element = ATTR_ELEMENT_NONE; + subd_offset = 0; } /* AttributeRequestSet */ diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index 41b3626afd3..e51bdf28d66 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -58,11 +58,11 @@ public: Attribute() {} ~Attribute(); void set(ustring name, TypeDesc type, AttributeElement element); - void resize(int numverts, int numfaces, int numsteps, int numcurves, int numkeys, bool reserve_only); + void resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only); size_t data_sizeof() const; - size_t element_size(int numverts, int numfaces, int numsteps, int numcurves, int numkeys) const; - size_t buffer_size(int numverts, int numfaces, int numsteps, int numcurves, int numkeys) const; + size_t element_size(Mesh *mesh, AttributePrimitive prim) const; + size_t buffer_size(Mesh *mesh, AttributePrimitive prim) const; char *data() { return (buffer.size())? &buffer[0]: NULL; }; float3 *data_float3() { return (float3*)data(); } @@ -79,6 +79,9 @@ public: const Transform *data_transform() const { return (const Transform*)data(); } const VoxelAttribute *data_voxel() const { return (const VoxelAttribute*)data(); } + void zero_data(void* dst); + void add_with_weight(void* dst, void* src, float weight); + void add(const float& f); void add(const float3& f); void add(const uchar4& f); @@ -99,6 +102,7 @@ class AttributeSet { public: Mesh *triangle_mesh; Mesh *curve_mesh; + Mesh *subd_mesh; list<Attribute> attributes; AttributeSet(); @@ -130,9 +134,9 @@ public: AttributeStandard std; /* temporary variables used by MeshManager */ - TypeDesc triangle_type, curve_type; - AttributeElement triangle_element, curve_element; - int triangle_offset, curve_offset; + TypeDesc triangle_type, curve_type, subd_type; + AttributeElement triangle_element, curve_element, subd_element; + int triangle_offset, curve_offset, subd_offset; explicit AttributeRequest(ustring name_); explicit AttributeRequest(AttributeStandard std); diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 8b0ed9f77b2..8d7c8fa9adb 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -35,9 +35,6 @@ #include "util_progress.h" #include "util_set.h" -#include "subd_split.h" -#include "subd_patch.h" - CCL_NAMESPACE_BEGIN /* Triangle */ @@ -104,6 +101,18 @@ void Mesh::Curve::bounds_grow(const int k, bounds.grow(upper, mr); } +/* SubdFace */ + +float3 Mesh::SubdFace::normal(const Mesh *mesh) const +{ + float3 v0 = mesh->verts[mesh->subd_face_corners[start_corner+0]]; + float3 v1 = mesh->verts[mesh->subd_face_corners[start_corner+1]]; + float3 v2 = mesh->verts[mesh->subd_face_corners[start_corner+2]]; + + return safe_normalize(cross(v1 - v0, v2 - v0)); +} + + /* Mesh */ NODE_DEFINE(Mesh) @@ -150,13 +159,22 @@ Mesh::Mesh() curve_offset = 0; curvekey_offset = 0; + patch_offset = 0; + face_offset = 0; + corner_offset = 0; + + num_subd_verts = 0; + attributes.triangle_mesh = this; curve_attributes.curve_mesh = this; + subd_attributes.subd_mesh = this; geometry_flags = GEOMETRY_NONE; has_volume = false; has_surface_bssrdf = false; + + num_ngons = 0; } Mesh::~Mesh() @@ -171,7 +189,10 @@ void Mesh::resize_mesh(int numverts, int numtris) shader.resize(numtris); smooth.resize(numtris); - forms_quad.resize(numtris); + if(subd_faces.size()) { + triangle_patch.resize(numtris); + vert_patch_uv.resize(numverts); + } attributes.resize(); } @@ -184,7 +205,10 @@ void Mesh::reserve_mesh(int numverts, int numtris) shader.reserve(numtris); smooth.reserve(numtris); - forms_quad.reserve(numtris); + if(subd_faces.size()) { + triangle_patch.reserve(numtris); + vert_patch_uv.reserve(numverts); + } attributes.resize(true); } @@ -209,6 +233,24 @@ void Mesh::reserve_curves(int numcurves, int numkeys) curve_attributes.resize(true); } +void Mesh::resize_subd_faces(int numfaces, int num_ngons_, int numcorners) +{ + subd_faces.resize(numfaces); + subd_face_corners.resize(numcorners); + num_ngons = num_ngons_; + + subd_attributes.resize(); +} + +void Mesh::reserve_subd_faces(int numfaces, int num_ngons_, int numcorners) +{ + subd_faces.reserve(numfaces); + subd_face_corners.reserve(numcorners); + num_ngons = num_ngons_; + + subd_attributes.resize(true); +} + void Mesh::clear() { /* clear all verts and triangles */ @@ -217,15 +259,22 @@ void Mesh::clear() shader.clear(); smooth.clear(); - forms_quad.clear(); + triangle_patch.clear(); + vert_patch_uv.clear(); curve_keys.clear(); curve_radius.clear(); curve_first_key.clear(); curve_shader.clear(); + subd_faces.clear(); + subd_face_corners.clear(); + + num_subd_verts = 0; + attributes.clear(); curve_attributes.clear(); + subd_attributes.clear(); used_shaders.clear(); transform_applied = false; @@ -247,27 +296,46 @@ int Mesh::split_vertex(int vertex) } } + foreach(Attribute& attr, subd_attributes.attributes) { + if(attr.element == ATTR_ELEMENT_VERTEX) { + vector<char> tmp(attr.data_sizeof()); + memcpy(&tmp[0], attr.data() + tmp.size()*vertex, tmp.size()); + attr.add(&tmp[0]); + } + } + return verts.size() - 1; } void Mesh::add_vertex(float3 P) { verts.push_back_reserved(P); + + if(subd_faces.size()) { + vert_patch_uv.push_back_reserved(make_float2(0.0f, 0.0f)); + } } void Mesh::add_vertex_slow(float3 P) { verts.push_back_slow(P); + + if(subd_faces.size()) { + vert_patch_uv.push_back_slow(make_float2(0.0f, 0.0f)); + } } -void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_) +void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_) { triangles.push_back_reserved(v0); triangles.push_back_reserved(v1); triangles.push_back_reserved(v2); shader.push_back_reserved(shader_); smooth.push_back_reserved(smooth_); - forms_quad.push_back_reserved(forms_quad_); + + if(subd_faces.size()) { + triangle_patch.push_back_reserved(-1); + } } void Mesh::add_curve_key(float3 co, float radius) @@ -282,6 +350,25 @@ void Mesh::add_curve(int first_key, int shader) curve_shader.push_back_reserved(shader); } +void Mesh::add_subd_face(int* corners, int num_corners, int shader_, bool smooth_) +{ + size_t start_corner = subd_face_corners.size(); + + for(int i = 0; i < num_corners; i++) { + subd_face_corners.push_back_reserved(corners[i]); + } + + int ptex_offset = 0; + + if(subd_faces.size()) { + SubdFace& s = subd_faces[subd_faces.size()-1]; + ptex_offset = s.ptex_offset + s.num_ptex_faces(); + } + + SubdFace face = {start_corner, num_corners, shader_, smooth_, ptex_offset}; + subd_faces.push_back_reserved(face); +} + void Mesh::compute_bounds() { BoundBox bnds = BoundBox::empty; @@ -505,10 +592,23 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal) void Mesh::pack_verts(const vector<uint>& tri_prim_index, uint4 *tri_vindex, + uint *tri_patch, + float2 *tri_patch_uv, size_t vert_offset, size_t tri_offset) { - const size_t triangles_size = num_triangles(); + size_t verts_size = verts.size(); + + if(verts_size && subd_faces.size()) { + float2 *vert_patch_uv_ptr = &vert_patch_uv[0]; + + for(size_t i = 0; i < verts_size; i++) { + tri_patch_uv[i] = vert_patch_uv_ptr[i]; + } + } + + size_t triangles_size = num_triangles(); + if(triangles_size) { for(size_t i = 0; i < triangles_size; i++) { Triangle t = get_triangle(i); @@ -516,6 +616,8 @@ void Mesh::pack_verts(const vector<uint>& tri_prim_index, t.v[1] + vert_offset, t.v[2] + vert_offset, tri_prim_index[i + tri_offset]); + + tri_patch[i] = (!subd_faces.size()) ? -1 : (triangle_patch[i]*8 + patch_offset); } } } @@ -553,6 +655,55 @@ void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, s } } +void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset) +{ + size_t num_faces = subd_faces.size(); + int ngons = 0; + + if(num_faces) { + for(size_t f = 0; f < num_faces; f++) { + SubdFace face = subd_faces[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++; + } + } + } +} + + void Mesh::compute_bvh(DeviceScene *dscene, SceneParams *params, Progress *progress, @@ -682,8 +833,9 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att osl_attr.value = attr; osl_attr.offset = 0; - og->attribute_map[i*ATTR_PRIM_TYPES][attr.name()] = osl_attr; + 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; + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][attr.name()] = osl_attr; } /* find mesh attributes */ @@ -713,11 +865,11 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att if(req.std != ATTR_STD_NONE) { /* if standard attribute, add lookup by geom: name convention */ ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); - og->attribute_map[i*ATTR_PRIM_TYPES][stdname] = osl_attr; + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][stdname] = osl_attr; } else if(req.name != ustring()) { /* add lookup by mesh attribute name */ - og->attribute_map[i*ATTR_PRIM_TYPES][req.name] = osl_attr; + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][req.name] = osl_attr; } } @@ -742,6 +894,28 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr; } } + + if(req.subd_element != ATTR_ELEMENT_NONE) { + osl_attr.elem = req.subd_element; + osl_attr.offset = req.subd_offset; + + if(req.subd_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else if(req.subd_type == TypeDesc::TypeMatrix) + osl_attr.type = TypeDesc::TypeMatrix; + else + osl_attr.type = TypeDesc::TypeColor; + + if(req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][stdname] = osl_attr; + } + else if(req.name != ustring()) { + /* add lookup by mesh attribute name */ + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][req.name] = osl_attr; + } + } } } #else @@ -822,22 +996,32 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce } index++; - } - /* terminator */ - attr_map[index].x = ATTR_STD_NONE; - attr_map[index].y = 0; - attr_map[index].z = 0; - attr_map[index].w = 0; + if(mesh->subd_faces.size()) { + attr_map[index].x = id; + attr_map[index].y = req.subd_element; + attr_map[index].z = as_uint(req.subd_offset); - index++; + if(req.subd_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else if(req.subd_type == TypeDesc::TypeMatrix) + attr_map[index].w = NODE_ATTR_MATRIX; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + } - attr_map[index].x = ATTR_STD_NONE; - attr_map[index].y = 0; - attr_map[index].z = 0; - attr_map[index].w = 0; + index++; + } - index++; + /* terminator */ + for(int i = 0; i < ATTR_PRIM_TYPES; i++) { + attr_map[index].x = ATTR_STD_NONE; + attr_map[index].y = 0; + attr_map[index].z = 0; + attr_map[index].w = 0; + + index++; + } } /* copy to device */ @@ -847,17 +1031,13 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce static void update_attribute_element_size(Mesh *mesh, Attribute *mattr, + AttributePrimitive prim, size_t *attr_float_size, size_t *attr_float3_size, size_t *attr_uchar4_size) { if(mattr) { - size_t size = mattr->element_size( - mesh->verts.size(), - mesh->num_triangles(), - mesh->motion_steps, - mesh->num_curves(), - mesh->curve_keys.size()); + size_t size = mattr->element_size(mesh, prim); if(mattr->element == ATTR_ELEMENT_VOXEL) { /* pass */ @@ -885,6 +1065,7 @@ static void update_attribute_element_offset(Mesh *mesh, vector<uchar4>& attr_uchar4, size_t& attr_uchar4_offset, Attribute *mattr, + AttributePrimitive prim, TypeDesc& type, int& offset, AttributeElement& element) @@ -895,12 +1076,7 @@ static void update_attribute_element_offset(Mesh *mesh, type = mattr->type; /* store attribute data in arrays */ - size_t size = mattr->element_size( - mesh->verts.size(), - mesh->num_triangles(), - mesh->motion_steps, - mesh->num_curves(), - mesh->curve_keys.size()); + size_t size = mattr->element_size(mesh, prim); if(mattr->element == ATTR_ELEMENT_VOXEL) { /* store slot in offset value */ @@ -954,10 +1130,18 @@ static void update_attribute_element_offset(Mesh *mesh, offset -= mesh->vert_offset; else if(element == ATTR_ELEMENT_VERTEX_MOTION) offset -= mesh->vert_offset; - else if(element == ATTR_ELEMENT_FACE) - offset -= mesh->tri_offset; - else if(element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) - offset -= 3*mesh->tri_offset; + else if(element == ATTR_ELEMENT_FACE) { + if(prim == ATTR_PRIM_TRIANGLE) + offset -= mesh->tri_offset; + else + offset -= mesh->face_offset; + } + else if(element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { + if(prim == ATTR_PRIM_TRIANGLE) + offset -= 3*mesh->tri_offset; + else + offset -= mesh->corner_offset; + } else if(element == ATTR_ELEMENT_CURVE) offset -= mesh->curve_offset; else if(element == ATTR_ELEMENT_CURVE_KEY) @@ -1007,23 +1191,23 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, foreach(AttributeRequest& req, attributes.requests) { Attribute *triangle_mattr = mesh->attributes.find(req); Attribute *curve_mattr = mesh->curve_attributes.find(req); - - /* todo: get rid of this exception, it's only here for giving some - * working texture coordinate for subdivision as we can't preserve - * any attributes yet */ - if(!triangle_mattr && req.std == ATTR_STD_GENERATED) { - triangle_mattr = mesh->attributes.add(ATTR_STD_GENERATED); - if(mesh->verts.size()) - memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size()); - } + Attribute *subd_mattr = mesh->subd_attributes.find(req); update_attribute_element_size(mesh, triangle_mattr, + ATTR_PRIM_TRIANGLE, &attr_float_size, &attr_float3_size, &attr_uchar4_size); update_attribute_element_size(mesh, curve_mattr, + ATTR_PRIM_CURVE, + &attr_float_size, + &attr_float3_size, + &attr_uchar4_size); + update_attribute_element_size(mesh, + subd_mattr, + ATTR_PRIM_SUBD, &attr_float_size, &attr_float3_size, &attr_uchar4_size); @@ -1048,12 +1232,14 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, foreach(AttributeRequest& req, attributes.requests) { Attribute *triangle_mattr = mesh->attributes.find(req); Attribute *curve_mattr = mesh->curve_attributes.find(req); + Attribute *subd_mattr = mesh->subd_attributes.find(req); update_attribute_element_offset(mesh, attr_float, attr_float_offset, attr_float3, attr_float3_offset, attr_uchar4, attr_uchar4_offset, triangle_mattr, + ATTR_PRIM_TRIANGLE, req.triangle_type, req.triangle_offset, req.triangle_element); @@ -1063,10 +1249,21 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, attr_float3, attr_float3_offset, attr_uchar4, attr_uchar4_offset, curve_mattr, + ATTR_PRIM_CURVE, req.curve_type, req.curve_offset, req.curve_element); + update_attribute_element_offset(mesh, + attr_float, attr_float_offset, + attr_float3, attr_float3_offset, + attr_uchar4, attr_uchar4_offset, + subd_mattr, + ATTR_PRIM_SUBD, + req.subd_type, + req.subd_offset, + req.subd_element); + if(progress.get_cancel()) return; } } @@ -1100,19 +1297,37 @@ void MeshManager::mesh_calc_offset(Scene *scene) { size_t vert_size = 0; size_t tri_size = 0; + size_t curve_key_size = 0; size_t curve_size = 0; + size_t patch_size = 0; + size_t face_size = 0; + size_t corner_size = 0; + foreach(Mesh *mesh, scene->meshes) { mesh->vert_offset = vert_size; mesh->tri_offset = tri_size; + mesh->curvekey_offset = curve_key_size; mesh->curve_offset = curve_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(); + curve_key_size += mesh->curve_keys.size(); curve_size += mesh->num_curves(); + + 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; + } + face_size += mesh->subd_faces.size(); + corner_size += mesh->subd_face_corners.size(); } } @@ -1125,14 +1340,25 @@ void MeshManager::device_update_mesh(Device *device, /* Count. */ size_t vert_size = 0; size_t tri_size = 0; + size_t curve_key_size = 0; size_t curve_size = 0; + + size_t patch_size = 0; + foreach(Mesh *mesh, scene->meshes) { vert_size += mesh->verts.size(); tri_size += mesh->num_triangles(); + curve_key_size += mesh->curve_keys.size(); curve_size += mesh->num_curves(); + + 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; + } } + /* Create mapping from triangle to primitive triangle array. */ vector<uint> tri_prim_index(tri_size); if(for_displacement) { @@ -1155,6 +1381,7 @@ void MeshManager::device_update_mesh(Device *device, } } } + /* Fill in all the arrays. */ if(tri_size != 0) { /* normals */ @@ -1163,6 +1390,8 @@ void MeshManager::device_update_mesh(Device *device, uint *tri_shader = dscene->tri_shader.resize(tri_size); float4 *vnormal = dscene->tri_vnormal.resize(vert_size); uint4 *tri_vindex = dscene->tri_vindex.resize(tri_size); + uint *tri_patch = dscene->tri_patch.resize(tri_size); + float2 *tri_patch_uv = dscene->tri_patch_uv.resize(vert_size); foreach(Mesh *mesh, scene->meshes) { mesh->pack_normals(scene, @@ -1170,6 +1399,8 @@ void MeshManager::device_update_mesh(Device *device, &vnormal[mesh->vert_offset]); mesh->pack_verts(tri_prim_index, &tri_vindex[mesh->tri_offset], + &tri_patch[mesh->tri_offset], + &tri_patch_uv[mesh->vert_offset], mesh->vert_offset, mesh->tri_offset); if(progress.get_cancel()) return; @@ -1181,7 +1412,10 @@ void MeshManager::device_update_mesh(Device *device, device->tex_alloc("__tri_shader", dscene->tri_shader); device->tex_alloc("__tri_vnormal", dscene->tri_vnormal); device->tex_alloc("__tri_vindex", dscene->tri_vindex); + device->tex_alloc("__tri_patch", dscene->tri_patch); + device->tex_alloc("__tri_patch_uv", dscene->tri_patch_uv); } + if(curve_size != 0) { progress.set_status("Updating Mesh", "Copying Strands to device"); @@ -1196,6 +1430,20 @@ void MeshManager::device_update_mesh(Device *device, device->tex_alloc("__curve_keys", dscene->curve_keys); device->tex_alloc("__curves", dscene->curves); } + + if(patch_size != 0) { + progress.set_status("Updating Mesh", "Copying Patches to device"); + + uint *patch_data = dscene->patches.resize(patch_size); + + foreach(Mesh *mesh, scene->meshes) { + mesh->pack_patches(&patch_data[mesh->patch_offset], mesh->vert_offset, mesh->face_offset, mesh->corner_offset); + if(progress.get_cancel()) return; + } + + device->tex_alloc("__patches", dscene->patches); + } + if(for_displacement) { float4 *prim_tri_verts = dscene->prim_tri_verts.resize(tri_size * 3); foreach(Mesh *mesh, scene->meshes) { @@ -1433,7 +1681,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen num_bvh++; } } + TaskPool pool; + foreach(Mesh *mesh, scene->meshes) { if(mesh->need_update) { pool.push(function_bind(&Mesh::compute_bvh, @@ -1448,6 +1698,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen } } } + TaskPool::Summary summary; pool.wait_work(&summary); VLOG(2) << "Objects BVH build pool statistics:\n" @@ -1505,8 +1756,11 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->tri_shader); device->tex_free(dscene->tri_vnormal); device->tex_free(dscene->tri_vindex); + device->tex_free(dscene->tri_patch); + device->tex_free(dscene->tri_patch_uv); device->tex_free(dscene->curves); device->tex_free(dscene->curve_keys); + device->tex_free(dscene->patches); device->tex_free(dscene->attributes_map); device->tex_free(dscene->attributes_float); device->tex_free(dscene->attributes_float3); @@ -1523,8 +1777,11 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->tri_shader.clear(); dscene->tri_vnormal.clear(); dscene->tri_vindex.clear(); + dscene->tri_patch.clear(); + dscene->tri_patch_uv.clear(); dscene->curves.clear(); dscene->curve_keys.clear(); + dscene->patches.clear(); dscene->attributes_map.clear(); dscene->attributes_float.clear(); dscene->attributes_float3.clear(); @@ -1574,77 +1831,5 @@ bool Mesh::need_attribute(Scene * /*scene*/, ustring name) return false; } -void Mesh::tessellate(DiagSplit *split) -{ - int num_faces = num_triangles(); - - add_face_normals(); - add_vertex_normals(); - - Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL); - float3 *fN = attr_fN->data_float3(); - - Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); - float3 *vN = attr_vN->data_float3(); - - for(int f = 0; f < num_faces; f++) { - if(!forms_quad[f]) { - /* triangle */ - LinearTrianglePatch patch; - Triangle triangle = get_triangle(f); - float3 *hull = patch.hull; - float3 *normals = patch.normals; - - for(int i = 0; i < 3; i++) { - hull[i] = verts[triangle.v[i]]; - } - - if(smooth[f]) { - for(int i = 0; i < 3; i++) { - normals[i] = vN[triangle.v[i]]; - } - } - else { - for(int i = 0; i < 3; i++) { - normals[i] = fN[f]; - } - } - - split->split_triangle(&patch); - } - else { - /* quad */ - LinearQuadPatch patch; - Triangle triangle0 = get_triangle(f); - Triangle triangle1 = get_triangle(f+1); - float3 *hull = patch.hull; - float3 *normals = patch.normals; - - hull[0] = verts[triangle0.v[0]]; - hull[1] = verts[triangle0.v[1]]; - hull[3] = verts[triangle0.v[2]]; - hull[2] = verts[triangle1.v[2]]; - - if(smooth[f]) { - normals[0] = vN[triangle0.v[0]]; - normals[1] = vN[triangle0.v[1]]; - normals[3] = vN[triangle0.v[2]]; - normals[2] = vN[triangle1.v[2]]; - } - else { - for(int i = 0; i < 4; i++) { - normals[i] = fN[f]; - } - } - - split->split_quad(&patch); - - // consume second triangle in quad - f++; - } - - } -} - CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 0aea55544f2..adb639201ce 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -97,6 +97,19 @@ public: return curve_first_key.size(); } + /* Mesh SubdFace */ + struct SubdFace { + int start_corner; + int num_corners; + int shader; + bool smooth; + int ptex_offset; + + bool is_quad() { return num_corners == 4; } + float3 normal(const Mesh *mesh) const; + int num_ptex_faces() const { return num_corners == 4 ? 1 : num_corners; } + }; + /* Displacement */ enum DisplacementMethod { DISPLACE_BUMP = 0, @@ -119,7 +132,10 @@ public: array<float3> verts; array<int> shader; array<bool> smooth; - array<bool> forms_quad; /* used to tell if triangle is part of a quad patch */ + + /* used for storing patch info for subd triangles, only allocated if there are patches */ + array<int> triangle_patch; /* must be < 0 for non subd triangles */ + array<float2> vert_patch_uv; bool has_volume; /* Set in the device_update_flags(). */ bool has_surface_bssrdf; /* Set in the device_update_flags(). */ @@ -129,9 +145,14 @@ public: array<int> curve_first_key; array<int> curve_shader; + array<SubdFace> subd_faces; + array<int> subd_face_corners; + int num_ngons; + vector<Shader*> used_shaders; AttributeSet attributes; AttributeSet curve_attributes; + AttributeSet subd_attributes; BoundBox bounds; bool transform_applied; @@ -154,6 +175,12 @@ public: size_t curve_offset; size_t curvekey_offset; + size_t patch_offset; + size_t face_offset; + size_t corner_offset; + + size_t num_subd_verts; + /* Functions */ Mesh(); ~Mesh(); @@ -162,12 +189,15 @@ public: void reserve_mesh(int numverts, int numfaces); void resize_curves(int numcurves, int numkeys); void reserve_curves(int numcurves, int numkeys); + void resize_subd_faces(int numfaces, int num_ngons, int numcorners); + void reserve_subd_faces(int numfaces, int num_ngons, int numcorners); void clear(); void add_vertex(float3 P); void add_vertex_slow(float3 P); - void add_triangle(int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false); + void add_triangle(int v0, int v1, int v2, int shader, bool smooth); void add_curve_key(float3 loc, float radius); void add_curve(int first_key, int shader); + void add_subd_face(int* corners, int num_corners, int shader_, bool smooth_); int split_vertex(int vertex); void compute_bounds(); @@ -177,9 +207,13 @@ public: void pack_normals(Scene *scene, uint *shader, float4 *vnormal); void pack_verts(const vector<uint>& tri_prim_index, uint4 *tri_vindex, + uint *tri_patch, + float2 *tri_patch_uv, size_t vert_offset, size_t tri_offset); void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset); + void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset); + void compute_bvh(DeviceScene *dscene, SceneParams *params, Progress *progress, diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp new file mode 100644 index 00000000000..fe8e41e8d35 --- /dev/null +++ b/intern/cycles/render/mesh_subdivision.cpp @@ -0,0 +1,224 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mesh.h" +#include "attribute.h" + +#include "subd_split.h" +#include "subd_patch.h" + +#include "util_foreach.h" + +CCL_NAMESPACE_BEGIN + +void Mesh::tessellate(DiagSplit *split) +{ + int num_faces = subd_faces.size(); + + Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL); + float3* vN = attr_vN->data_float3(); + + for(int f = 0; f < num_faces; f++) { + SubdFace& face = subd_faces[f]; + + if(face.is_quad()) { + /* quad */ + LinearQuadPatch patch; + float3 *hull = patch.hull; + float3 *normals = patch.normals; + + patch.patch_index = face.ptex_offset; + patch.shader = face.shader; + + for(int i = 0; i < 4; i++) { + hull[i] = verts[subd_face_corners[face.start_corner+i]]; + } + + if(face.smooth) { + for(int i = 0; i < 4; i++) { + normals[i] = vN[subd_face_corners[face.start_corner+i]]; + } + } + else { + float3 N = face.normal(this); + for(int i = 0; i < 4; i++) { + normals[i] = N; + } + } + + swap(hull[2], hull[3]); + swap(normals[2], normals[3]); + + /* Quad faces need to be split at least once to line up with split ngons, we do this + * here in this manner because if we do it later edge factors may end up slightly off. + */ + QuadDice::SubPatch subpatch; + subpatch.patch = &patch; + + subpatch.P00 = make_float2(0.0f, 0.0f); + subpatch.P10 = make_float2(0.5f, 0.0f); + subpatch.P01 = make_float2(0.0f, 0.5f); + subpatch.P11 = make_float2(0.5f, 0.5f); + split->split_quad(&patch, &subpatch); + + subpatch.P00 = make_float2(0.5f, 0.0f); + subpatch.P10 = make_float2(1.0f, 0.0f); + subpatch.P01 = make_float2(0.5f, 0.5f); + subpatch.P11 = make_float2(1.0f, 0.5f); + split->split_quad(&patch, &subpatch); + + subpatch.P00 = make_float2(0.0f, 0.5f); + subpatch.P10 = make_float2(0.5f, 0.5f); + subpatch.P01 = make_float2(0.0f, 1.0f); + subpatch.P11 = make_float2(0.5f, 1.0f); + split->split_quad(&patch, &subpatch); + + subpatch.P00 = make_float2(0.5f, 0.5f); + subpatch.P10 = make_float2(1.0f, 0.5f); + subpatch.P01 = make_float2(0.5f, 1.0f); + subpatch.P11 = make_float2(1.0f, 1.0f); + split->split_quad(&patch, &subpatch); + } + else { + /* ngon */ + float3 center_vert = make_float3(0.0f, 0.0f, 0.0f); + float3 center_normal = make_float3(0.0f, 0.0f, 0.0f); + + float inv_num_corners = 1.0f/float(face.num_corners); + for(int corner = 0; corner < face.num_corners; corner++) { + center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners; + center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners; + } + + for(int corner = 0; corner < face.num_corners; corner++) { + LinearQuadPatch patch; + float3 *hull = patch.hull; + float3 *normals = patch.normals; + + patch.patch_index = face.ptex_offset + corner; + + patch.shader = face.shader; + + hull[0] = verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]]; + hull[1] = verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]]; + hull[2] = verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]]; + hull[3] = center_vert; + + hull[1] = (hull[1] + hull[0]) * 0.5; + hull[2] = (hull[2] + hull[0]) * 0.5; + + if(face.smooth) { + normals[0] = vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]]; + normals[1] = vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]]; + normals[2] = vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]]; + normals[3] = center_normal; + + normals[1] = (normals[1] + normals[0]) * 0.5; + normals[2] = (normals[2] + normals[0]) * 0.5; + } + else { + float3 N = face.normal(this); + for(int i = 0; i < 4; i++) { + normals[i] = N; + } + } + + split->split_quad(&patch); + } + } + } + + /* interpolate center points for attributes */ + foreach(Attribute& attr, subd_attributes.attributes) { + char* data = attr.data(); + 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 = subd_faces[f]; + + if(!face.is_quad()) { + char* center = data + (verts.size() - num_subd_verts + ngons) * stride; + attr.zero_data(center); + + 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 = subd_faces[f]; + + if(!face.is_quad()) { + char* center = data + (subd_face_corners.size() + ngons) * stride; + attr.zero_data(center); + + 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 = subd_faces[f]; + + if(!face.is_quad()) { + uchar* center = (uchar*)data + (subd_face_corners.size() + ngons) * stride; + + float inv_num_corners = 1.0f / float(face.num_corners); + float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f); + + 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; + } + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 05e807ff60c..9e72f197cce 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -74,10 +74,14 @@ public: device_vector<uint> tri_shader; device_vector<float4> tri_vnormal; device_vector<uint4> tri_vindex; + device_vector<uint> tri_patch; + device_vector<float2> tri_patch_uv; device_vector<float4> curves; device_vector<float4> curve_keys; + device_vector<uint> patches; + /* objects */ device_vector<float4> objects; device_vector<float4> objects_vector; |