diff options
Diffstat (limited to 'intern')
30 files changed, 1229 insertions, 1193 deletions
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 3aca46e2dc7..3d3aca33881 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -35,7 +35,6 @@ #include "shader.h" #include "scene.h" -#include "subd_mesh.h" #include "subd_patch.h" #include "subd_split.h" @@ -417,6 +416,7 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node) xml_read_int_array(verts, node, "verts"); xml_read_int_array(nverts, node, "nverts"); +#if 0 if(xml_equal_string(node, "subdivision", "catmull-clark")) { /* create subd mesh */ SubdMesh sdmesh; @@ -460,7 +460,9 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node) DiagSplit dsplit(sdparams); sdmesh.tessellate(&dsplit); } - else { + else +#endif + { /* create vertices */ mesh->verts = P; @@ -568,7 +570,7 @@ static void xml_read_patch(const XMLReadState& state, pugi::xml_node node) mesh->used_shaders.push_back(state.shader); /* split */ - SubdParams sdparams(mesh, 0, state.smooth); + SubdParams sdparams(mesh); xml_read_float(&sdparams.dicing_rate, node, "dicing_rate"); DiagSplit dsplit(sdparams); diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index ec11a893b5a..0744bbf1a0a 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -24,7 +24,6 @@ #include "blender_session.h" #include "blender_util.h" -#include "subd_mesh.h" #include "subd_patch.h" #include "subd_split.h" @@ -335,44 +334,71 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector<int>& nverts, - const vector<int>& face_flags) + const vector<int>& face_flags, + bool subdivision) { - BL::Mesh::tessface_vertex_colors_iterator l; - for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) { - if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) - continue; + if(subdivision) { + BL::Mesh::vertex_colors_iterator l; - Attribute *attr = mesh->attributes.add( - ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); + for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { + if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) + continue; - BL::MeshColorLayer::data_iterator c; - uchar4 *cdata = attr->data_uchar4(); - size_t i = 0; + Attribute *attr = mesh->subd_attributes.add(ustring(l->name().c_str()), + TypeDesc::TypeColor, + ATTR_ELEMENT_CORNER_BYTE); - for(l->data.begin(c); c != l->data.end(); ++c, ++i) { - int tri_a[3], tri_b[3]; - face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); + BL::Mesh::polygons_iterator p; + uchar4 *cdata = attr->data_uchar4(); - uchar4 colors[4]; - colors[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1()))); - colors[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2()))); - colors[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3()))); - if(nverts[i] == 4) { - colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4()))); + for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + int n = p->loop_total(); + for(int i = 0; i < n; i++) { + float3 color = get_float3(l->data[p->loop_start() + i].color()); + *(cdata++) = color_float_to_byte(color_srgb_to_scene_linear(color)); + } } + } + } + else { + BL::Mesh::tessface_vertex_colors_iterator l; + for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) { + if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) + continue; + + Attribute *attr = mesh->attributes.add(ustring(l->name().c_str()), + TypeDesc::TypeColor, + ATTR_ELEMENT_CORNER_BYTE); + + BL::MeshColorLayer::data_iterator c; + uchar4 *cdata = attr->data_uchar4(); + size_t i = 0; + + for(l->data.begin(c); c != l->data.end(); ++c, ++i) { + int tri_a[3], tri_b[3]; + face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b); + + uchar4 colors[4]; + colors[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1()))); + colors[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2()))); + colors[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3()))); + if(nverts[i] == 4) { + colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4()))); + } - cdata[0] = colors[tri_a[0]]; - cdata[1] = colors[tri_a[1]]; - cdata[2] = colors[tri_a[2]]; + cdata[0] = colors[tri_a[0]]; + cdata[1] = colors[tri_a[1]]; + cdata[2] = colors[tri_a[2]]; - if(nverts[i] == 4) { - cdata[3] = colors[tri_b[0]]; - cdata[4] = colors[tri_b[1]]; - cdata[5] = colors[tri_b[2]]; - cdata += 6; + if(nverts[i] == 4) { + cdata[3] = colors[tri_b[0]]; + cdata[4] = colors[tri_b[1]]; + cdata[5] = colors[tri_b[2]]; + cdata += 6; + } + else + cdata += 3; } - else - cdata += 3; } } } @@ -382,9 +408,40 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector<int>& nverts, - const vector<int>& face_flags) + const vector<int>& face_flags, + bool subdivision) { - if(b_mesh.tessface_uv_textures.length() != 0) { + if(subdivision) { + BL::Mesh::uv_layers_iterator l; + int i = 0; + + for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { + bool active_render = b_mesh.uv_textures[i].active_render(); + AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; + ustring name = ustring(l->name().c_str()); + + /* UV map */ + if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) { + Attribute *attr; + + if(active_render) + attr = mesh->subd_attributes.add(std, name); + else + attr = mesh->subd_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); + + BL::Mesh::polygons_iterator p; + float3 *fdata = attr->data_float3(); + + for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + int n = p->loop_total(); + for(int j = 0; j < n; j++) { + *(fdata++) = get_float3(l->data[p->loop_start() + j].uv()); + } + } + } + } + } + else if(b_mesh.tessface_uv_textures.length() != 0) { BL::Mesh::tessface_uv_textures_iterator l; for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) { @@ -465,11 +522,13 @@ static void attr_create_uv_map(Scene *scene, /* Create vertex pointiness attributes. */ static void attr_create_pointiness(Scene *scene, Mesh *mesh, - BL::Mesh& b_mesh) + BL::Mesh& b_mesh, + bool subdivision) { if(mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { const int numverts = b_mesh.vertices.length(); - Attribute *attr = mesh->attributes.add(ATTR_STD_POINTINESS); + AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; + Attribute *attr = attributes.add(ATTR_STD_POINTINESS); float *data = attr->data_float(); int *counter = new int[numverts]; float *raw_data = new float[numverts]; @@ -532,30 +591,44 @@ static void attr_create_pointiness(Scene *scene, static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, - const vector<Shader*>& used_shaders) + const vector<Shader*>& used_shaders, + bool subdivision=false) { /* count vertices and faces */ int numverts = b_mesh.vertices.length(); - int numfaces = b_mesh.tessfaces.length(); + int numfaces = (!subdivision) ? b_mesh.tessfaces.length() : b_mesh.polygons.length(); int numtris = 0; + int numcorners = 0; + int numngons = 0; bool use_loop_normals = b_mesh.use_auto_smooth(); BL::Mesh::vertices_iterator v; BL::Mesh::tessfaces_iterator f; + BL::Mesh::polygons_iterator p; - for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) { - int4 vi = get_int4(f->vertices_raw()); - numtris += (vi[3] == 0)? 1: 2; + if(!subdivision) { + for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) { + int4 vi = get_int4(f->vertices_raw()); + numtris += (vi[3] == 0)? 1: 2; + } + } + else { + for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + numngons += (p->loop_total() == 4)? 0: 1; + numcorners += p->loop_total(); + } } /* allocate memory */ mesh->reserve_mesh(numverts, numtris); + mesh->reserve_subd_faces(numfaces, numngons, numcorners); /* create vertex coordinates and normals */ for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) mesh->add_vertex(get_float3(v->co())); - Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); + AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; + Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL); float3 *N = attr_N->data_float3(); for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N) @@ -564,7 +637,7 @@ static void create_mesh(Scene *scene, /* create generated coordinates from undeformed coordinates */ if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) { - Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); + Attribute *attr = attributes.add(ATTR_STD_GENERATED); float3 loc, size; mesh_texture_space(b_mesh, loc, size); @@ -577,67 +650,103 @@ static void create_mesh(Scene *scene, } /* Create needed vertex attributes. */ - attr_create_pointiness(scene, mesh, b_mesh); + attr_create_pointiness(scene, mesh, b_mesh, subdivision); /* create faces */ vector<int> nverts(numfaces); vector<int> face_flags(numfaces, FACE_FLAG_NONE); int fi = 0; - for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) { - int4 vi = get_int4(f->vertices_raw()); - int n = (vi[3] == 0)? 3: 4; - int shader = clamp(f->material_index(), 0, used_shaders.size()-1); - bool smooth = f->use_smooth() || use_loop_normals; - - /* split vertices if normal is different - * - * note all vertex attributes must have been set here so we can split - * and copy attributes in split_vertex without remapping later */ - if(use_loop_normals) { - BL::Array<float, 12> loop_normals = f->split_normals(); - - for(int i = 0; i < n; i++) { - float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); - - if(N[vi[i]] != loop_N) { - int new_vi = mesh->split_vertex(vi[i]); - - /* set new normal and vertex index */ - N = attr_N->data_float3(); - N[new_vi] = loop_N; - vi[i] = new_vi; + if(!subdivision) { + for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) { + int4 vi = get_int4(f->vertices_raw()); + int n = (vi[3] == 0)? 3: 4; + int shader = clamp(f->material_index(), 0, used_shaders.size()-1); + bool smooth = f->use_smooth() || use_loop_normals; + + /* split vertices if normal is different + * + * note all vertex attributes must have been set here so we can split + * and copy attributes in split_vertex without remapping later */ + if(use_loop_normals) { + BL::Array<float, 12> loop_normals = f->split_normals(); + + for(int i = 0; i < n; i++) { + float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); + + if(N[vi[i]] != loop_N) { + int new_vi = mesh->split_vertex(vi[i]); + + /* set new normal and vertex index */ + N = attr_N->data_float3(); + N[new_vi] = loop_N; + vi[i] = new_vi; + } } } - } - /* create triangles */ - if(n == 4) { - if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) || - is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) - { - // TODO(mai): order here is probably wrong - mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth, true); - mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth, true); - face_flags[fi] |= FACE_FLAG_DIVIDE_24; + /* create triangles */ + if(n == 4) { + if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) || + is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) + { + mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth); + mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth); + face_flags[fi] |= FACE_FLAG_DIVIDE_24; + } + else { + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); + mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth); + face_flags[fi] |= FACE_FLAG_DIVIDE_13; + } } else { - mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth, true); - mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth, true); - face_flags[fi] |= FACE_FLAG_DIVIDE_13; + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); } + + nverts[fi] = n; } - else - mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth, false); + } + else { + vector<int> vi; + + for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + int n = p->loop_total(); + int shader = clamp(p->material_index(), 0, used_shaders.size()-1); + bool smooth = p->use_smooth() || use_loop_normals; - nverts[fi] = n; + vi.reserve(n); + for(int i = 0; i < n; i++) { + vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index(); + + /* split vertices if normal is different + * + * note all vertex attributes must have been set here so we can split + * and copy attributes in split_vertex without remapping later */ + if(use_loop_normals) { + float3 loop_N = get_float3(b_mesh.loops[p->loop_start() + i].normal()); + + if(N[vi[i]] != loop_N) { + int new_vi = mesh->split_vertex(vi[i]); + + /* set new normal and vertex index */ + N = attr_N->data_float3(); + N[new_vi] = loop_N; + vi[i] = new_vi; + } + } + } + + /* create subd faces */ + mesh->add_subd_face(&vi[0], n, shader, smooth); + } } /* Create all needed attributes. * The calculate functions will check whether they're needed or not. */ - attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags); - attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags); + attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision); + attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision); /* for volume objects, create a matrix to transform from object space to * mesh texture space. this does not work with deformations but that can @@ -662,10 +771,9 @@ static void create_subd_mesh(Scene *scene, float dicing_rate, int max_subdivisions) { - Mesh basemesh; - create_mesh(scene, &basemesh, b_mesh, used_shaders); + create_mesh(scene, mesh, b_mesh, used_shaders, true); - SubdParams sdparams(mesh, 0, true, false); + SubdParams sdparams(mesh); sdparams.dicing_rate = max(0.1f, RNA_float_get(cmesh, "dicing_rate") * dicing_rate); sdparams.max_level = max_subdivisions; @@ -675,7 +783,7 @@ static void create_subd_mesh(Scene *scene, /* tesselate */ DiagSplit dsplit(sdparams); - basemesh.tessellate(&dsplit); + mesh->tessellate(&dsplit); } /* Sync */ @@ -817,20 +925,21 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, b_ob.update_from_editmode(); bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); - BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed); + bool subdivision = experimental && cmesh.data && RNA_enum_get(&cmesh, "subdivision_type"); + BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed, subdivision); if(b_mesh) { if(render_layer.use_surfaces && !hide_tris) { - if(cmesh.data && experimental && RNA_enum_get(&cmesh, "subdivision_type")) + if(subdivision) create_subd_mesh(scene, mesh, b_ob, b_mesh, &cmesh, used_shaders, dicing_rate, max_subdivisions); else - create_mesh(scene, mesh, b_mesh, used_shaders); + create_mesh(scene, mesh, b_mesh, used_shaders, false); create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current()); } - if(render_layer.use_hair) + if(render_layer.use_hair && !subdivision) sync_curves(mesh, b_mesh, b_ob, false); if(can_free_caches) { @@ -957,7 +1066,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { /* get derived mesh */ - b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false); + b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false, false); } if(!b_mesh) { diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 188d23d0c59..34405c3ea1a 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -45,14 +45,17 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, BL::Scene& scene, bool apply_modifiers, bool render, - bool calc_undeformed) + bool calc_undeformed, + bool subdivision) { BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed); if((bool)me) { if(me.use_auto_smooth()) { me.calc_normals_split(); } - me.calc_tessface(true); + if(!subdivision) { + me.calc_tessface(true); + } } return me; } diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index bd3969b2889..685574eb394 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -161,6 +161,7 @@ set(SRC_GEOM_HEADERS geom/geom_motion_triangle.h geom/geom_object.h geom/geom_primitive.h + geom/geom_subd_triangle.h geom/geom_triangle.h geom/geom_triangle_intersect.h geom/geom_volume.h diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h index d2c7edb11ea..493afdc4f62 100644 --- a/intern/cycles/kernel/geom/geom.h +++ b/intern/cycles/kernel/geom/geom.h @@ -18,6 +18,7 @@ #include "geom_attribute.h" #include "geom_object.h" #include "geom_triangle.h" +#include "geom_subd_triangle.h" #include "geom_triangle_intersect.h" #include "geom_motion_triangle.h" #include "geom_motion_curve.h" diff --git a/intern/cycles/kernel/geom/geom_attribute.h b/intern/cycles/kernel/geom/geom_attribute.h index c7364e9edac..5d78cf8f9fc 100644 --- a/intern/cycles/kernel/geom/geom_attribute.h +++ b/intern/cycles/kernel/geom/geom_attribute.h @@ -25,6 +25,24 @@ CCL_NAMESPACE_BEGIN * Lookup of attributes is different between OSL and SVM, as OSL is ustring * based while for SVM we use integer ids. */ +ccl_device_inline uint subd_triangle_patch(KernelGlobals *kg, const ShaderData *sd); + +ccl_device_inline uint attribute_primitive_type(KernelGlobals *kg, const ShaderData *sd) +{ +#ifdef __HAIR__ + if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) { + return ATTR_PRIM_CURVE; + } + else +#endif + if(subd_triangle_patch(kg, sd) != ~0) { + return ATTR_PRIM_SUBD; + } + else { + return ATTR_PRIM_TRIANGLE; + } +} + /* Find attribute based on ID */ ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem) @@ -34,9 +52,7 @@ ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, ui /* for SVM, find attribute by unique id */ uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride; -#ifdef __HAIR__ - attr_offset = (ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset; -#endif + attr_offset += attribute_primitive_type(kg, sd); uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); while(attr_map.x != id) { diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h index b1b1e919e00..44734d1b70d 100644 --- a/intern/cycles/kernel/geom/geom_primitive.h +++ b/intern/cycles/kernel/geom/geom_primitive.h @@ -26,7 +26,10 @@ CCL_NAMESPACE_BEGIN ccl_device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) { if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) { - return triangle_attribute_float(kg, sd, elem, offset, dx, dy); + if(subd_triangle_patch(kg, sd) == ~0) + return triangle_attribute_float(kg, sd, elem, offset, dx, dy); + else + return subd_triangle_attribute_float(kg, sd, elem, offset, dx, dy); } #ifdef __HAIR__ else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) { @@ -48,7 +51,10 @@ ccl_device float primitive_attribute_float(KernelGlobals *kg, const ShaderData * ccl_device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) { if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) { - return triangle_attribute_float3(kg, sd, elem, offset, dx, dy); + if(subd_triangle_patch(kg, sd) == ~0) + return triangle_attribute_float3(kg, sd, elem, offset, dx, dy); + else + return subd_triangle_attribute_float3(kg, sd, elem, offset, dx, dy); } #ifdef __HAIR__ else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) { diff --git a/intern/cycles/kernel/geom/geom_subd_triangle.h b/intern/cycles/kernel/geom/geom_subd_triangle.h new file mode 100644 index 00000000000..e4597aba56e --- /dev/null +++ b/intern/cycles/kernel/geom/geom_subd_triangle.h @@ -0,0 +1,262 @@ +/* + * 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. + */ + +/* Functions for retrieving attributes on triangles produced from subdivision meshes */ + +CCL_NAMESPACE_BEGIN + +/* Patch index for triangle, -1 if not subdivision triangle */ + +ccl_device_inline uint subd_triangle_patch(KernelGlobals *kg, const ShaderData *sd) +{ + return kernel_tex_fetch(__tri_patch, ccl_fetch(sd, prim)); +} + +/* UV coords of triangle within patch */ + +ccl_device_inline void subd_triangle_patch_uv(KernelGlobals *kg, const ShaderData *sd, float2 uv[3]) +{ + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + + uv[0] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.x); + uv[1] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.y); + uv[2] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.z); +} + +/* Vertex indices of patch */ + +ccl_device_inline uint4 subd_triangle_patch_indices(KernelGlobals *kg, int patch) +{ + uint4 indices; + + indices.x = kernel_tex_fetch(__patches, patch+0); + indices.y = kernel_tex_fetch(__patches, patch+1); + indices.z = kernel_tex_fetch(__patches, patch+2); + indices.w = kernel_tex_fetch(__patches, patch+3); + + return indices; +} + +/* Originating face for patch */ + +ccl_device_inline uint subd_triangle_patch_face(KernelGlobals *kg, int patch) +{ + return kernel_tex_fetch(__patches, patch+4); +} + +/* Number of corners on originating face */ + +ccl_device_inline uint subd_triangle_patch_num_corners(KernelGlobals *kg, int patch) +{ + return kernel_tex_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, int patch, int corners[4]) +{ + uint4 data; + + data.x = kernel_tex_fetch(__patches, patch+4); + data.y = kernel_tex_fetch(__patches, patch+5); + data.z = kernel_tex_fetch(__patches, patch+6); + data.w = kernel_tex_fetch(__patches, patch+7); + + 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 */ + 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); + } +} + +/* Reading attributes on various subdivision triangle elements */ + +ccl_device float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) +{ + int patch = subd_triangle_patch(kg, sd); + + if(elem == ATTR_ELEMENT_FACE) { + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; + + return kernel_tex_fetch(__attributes_float, offset + subd_triangle_patch_face(kg, patch)); + } + else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) { + float2 uv[3]; + subd_triangle_patch_uv(kg, sd, uv); + uint4 v = subd_triangle_patch_indices(kg, patch); + + float a, b, c; + + float f0 = kernel_tex_fetch(__attributes_float, offset + v.x); + float f1 = kernel_tex_fetch(__attributes_float, offset + v.y); + float f2 = kernel_tex_fetch(__attributes_float, offset + v.z); + float f3 = kernel_tex_fetch(__attributes_float, offset + v.w); + + if(subd_triangle_patch_num_corners(kg, patch) != 4) { + f1 = (f1+f0)*0.5f; + f3 = (f3+f0)*0.5f; + } + + a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y); + b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y); + c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c; + if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c; +#endif + + return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c; + } + else if(elem == ATTR_ELEMENT_CORNER) { + int corners[4]; + subd_triangle_patch_corners(kg, patch, corners); + + float2 uv[3]; + subd_triangle_patch_uv(kg, sd, uv); + + float a, b, c; + + float f0 = kernel_tex_fetch(__attributes_float, corners[0] + offset); + float f1 = kernel_tex_fetch(__attributes_float, corners[1] + offset); + float f2 = kernel_tex_fetch(__attributes_float, corners[2] + offset); + float f3 = kernel_tex_fetch(__attributes_float, corners[3] + offset); + + if(subd_triangle_patch_num_corners(kg, patch) != 4) { + f1 = (f1+f0)*0.5f; + f3 = (f3+f0)*0.5f; + } + + a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y); + b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y); + c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c; + if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c; +#endif + + return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c; + } + else { + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; + + return 0.0f; + } +} + +ccl_device float3 subd_triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) +{ + int patch = subd_triangle_patch(kg, sd); + + if(elem == ATTR_ELEMENT_FACE) { + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); + + return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + subd_triangle_patch_face(kg, patch))); + } + else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) { + float2 uv[3]; + subd_triangle_patch_uv(kg, sd, uv); + uint4 v = subd_triangle_patch_indices(kg, patch); + + float3 a, b, c; + + float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.x)); + float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.y)); + float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.z)); + float3 f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.w)); + + if(subd_triangle_patch_num_corners(kg, patch) != 4) { + f1 = (f1+f0)*0.5f; + f3 = (f3+f0)*0.5f; + } + + a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y); + b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y); + c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c; + if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c; +#endif + + return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c; + } + else if(elem == ATTR_ELEMENT_CORNER || elem == ATTR_ELEMENT_CORNER_BYTE) { + int corners[4]; + subd_triangle_patch_corners(kg, patch, corners); + + float2 uv[3]; + subd_triangle_patch_uv(kg, sd, uv); + + float3 a, b, c; + float3 f0, f1, f2, f3; + + if(elem == ATTR_ELEMENT_CORNER) { + f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + offset)); + f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + offset)); + f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + offset)); + f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + offset)); + } + else { + f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[0] + offset)); + f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[1] + offset)); + f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[2] + offset)); + f3 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[3] + offset)); + } + + if(subd_triangle_patch_num_corners(kg, patch) != 4) { + f1 = (f1+f0)*0.5f; + f3 = (f3+f0)*0.5f; + } + + a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y); + b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y); + c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c; + if(dy) *dy = ccl_fetch(sd, du).dy*a + ccl_fetch(sd, dv).dy*b - (ccl_fetch(sd, du).dy + ccl_fetch(sd, dv).dy)*c; +#endif + + return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c; + } + else { + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); + + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 5ba262c1044..7d6fec02331 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -41,11 +41,16 @@ KERNEL_TEX(float4, texture_float4, __objects_vector) KERNEL_TEX(uint, texture_uint, __tri_shader) KERNEL_TEX(float4, texture_float4, __tri_vnormal) KERNEL_TEX(uint4, texture_uint4, __tri_vindex) +KERNEL_TEX(uint, texture_uint, __tri_patch) +KERNEL_TEX(float2, texture_float2, __tri_patch_uv) /* curves */ KERNEL_TEX(float4, texture_float4, __curves) KERNEL_TEX(float4, texture_float4, __curve_keys) +/* patches */ +KERNEL_TEX(uint, texture_uint, __patches) + /* attributes */ KERNEL_TEX(uint4, texture_uint4, __attributes_map) KERNEL_TEX(float, texture_float, __attributes_float) @@ -173,9 +178,6 @@ KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_086) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_087) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_088) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_089) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_090) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_091) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_092) # else /* bindless textures */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index a9be2ae717a..b7021dbf7f1 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -573,8 +573,13 @@ typedef enum PrimitiveType { /* Attributes */ -#define ATTR_PRIM_TYPES 2 -#define ATTR_PRIM_CURVE 1 +typedef enum AttributePrimitive { + ATTR_PRIM_TRIANGLE = 0, + ATTR_PRIM_CURVE, + ATTR_PRIM_SUBD, + + ATTR_PRIM_TYPES +} AttributePrimitive; typedef enum AttributeElement { ATTR_ELEMENT_NONE, diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 2bb2be5e6b3..caae24405f1 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -787,7 +787,7 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring TypeDesc type, ustring name, void *val) { KernelGlobals *kg = sd->osl_globals; - bool is_curve; + int prim_type = 0; int object; /* lookup of attribute on another object */ @@ -798,18 +798,17 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring return false; object = it->second; - is_curve = false; } else { object = sd->object; - is_curve = (sd->type & PRIMITIVE_ALL_CURVE) != 0; + prim_type = attribute_primitive_type(kg, sd); if(object == OBJECT_NONE) return get_background_attribute(kg, sd, name, type, derivatives, val); } /* find attribute on object */ - object = object*ATTR_PRIM_TYPES + (is_curve == true); + object = object*ATTR_PRIM_TYPES + prim_type; OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object]; OSLGlobals::AttributeMap::iterator it = attribute_map.find(name); diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h index 63bbb27d873..6c557684099 100644 --- a/intern/cycles/kernel/svm/svm_attribute.h +++ b/intern/cycles/kernel/svm/svm_attribute.h @@ -28,9 +28,7 @@ ccl_device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd, /* find attribute by unique id */ uint id = node.y; uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride; -#ifdef __HAIR__ - attr_offset = (ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset; -#endif + attr_offset += attribute_primitive_type(kg, sd); uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); while(attr_map.x != id) { diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 44732734c31..b6b90dfff81 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -271,9 +271,6 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, case 87: r = kernel_tex_image_interp(__tex_image_byte4_087, x, y); break; case 88: r = kernel_tex_image_interp(__tex_image_byte4_088, x, y); break; case 89: r = kernel_tex_image_interp(__tex_image_byte4_089, x, y); break; - case 90: r = kernel_tex_image_interp(__tex_image_byte4_090, x, y); break; - case 91: r = kernel_tex_image_interp(__tex_image_byte4_091, x, y); break; - case 92: r = kernel_tex_image_interp(__tex_image_byte4_092, x, y); break; default: kernel_assert(0); return make_float4(0.0f, 0.0f, 0.0f, 0.0f); 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; diff --git a/intern/cycles/subd/CMakeLists.txt b/intern/cycles/subd/CMakeLists.txt index d1708868fd0..db497013693 100644 --- a/intern/cycles/subd/CMakeLists.txt +++ b/intern/cycles/subd/CMakeLists.txt @@ -14,14 +14,12 @@ set(INC_SYS set(SRC subd_dice.cpp - subd_mesh.cpp subd_patch.cpp subd_split.cpp ) set(SRC_HEADERS subd_dice.h - subd_mesh.h subd_patch.h subd_split.h ) diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index 7c74f21950e..36981a20f3c 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -48,6 +48,11 @@ void EdgeDice::reserve(int num_verts) vert_offset = mesh->verts.size(); tri_offset = mesh->num_triangles(); + /* todo: optimize so we can reserve in advance, this is like push_back_slow() */ + if(vert_offset + num_verts > mesh->verts.capacity()) { + mesh->reserve_mesh(size_t((vert_offset + num_verts) * 1.2), mesh->num_triangles()); + } + mesh->resize_mesh(vert_offset + num_verts, tri_offset); Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); @@ -66,6 +71,7 @@ int EdgeDice::add_vert(Patch *patch, float2 uv) mesh_P[vert_offset] = P; mesh_N[vert_offset] = N; + params.mesh->vert_patch_uv[vert_offset] = make_float2(uv.x, uv.y); if(params.ptex) { Attribute *attr_ptex_uv = params.mesh->attributes.add(ATTR_STD_PTEX_UV); @@ -75,6 +81,8 @@ int EdgeDice::add_vert(Patch *patch, float2 uv) ptex_uv[vert_offset] = make_float3(uv.x, uv.y, 0.0f); } + params.mesh->num_subd_verts++; + return vert_offset++; } @@ -86,7 +94,8 @@ void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2) if(mesh->triangles.size() == mesh->triangles.capacity()) mesh->reserve_mesh(mesh->verts.size(), size_t(max(mesh->num_triangles() + 1, 1) * 1.2)); - mesh->add_triangle(v0, v1, v2, params.shader, params.smooth, false); + mesh->add_triangle(v0, v1, v2, patch->shader, true); + params.mesh->triangle_patch[params.mesh->num_triangles()-1] = patch->patch_index; if(params.ptex) { Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID); @@ -340,160 +349,5 @@ void QuadDice::dice(SubPatch& sub, EdgeFactors& ef) assert(vert_offset == params.mesh->verts.size()); } -/* TriangleDice */ - -TriangleDice::TriangleDice(const SubdParams& params_) -: EdgeDice(params_) -{ -} - -void TriangleDice::reserve(EdgeFactors& ef, int M) -{ - int num_verts = ef.tu + ef.tv + ef.tw; - - for(int m = M-2; m > 0; m -= 2) - num_verts += 3 + (m-1)*3; - - if(!(M & 1)) - num_verts++; - - EdgeDice::reserve(num_verts); -} - -float2 TriangleDice::map_uv(SubPatch& sub, float2 uv) -{ - /* map UV from subpatch to patch parametric coordinates */ - return uv.x*sub.Pu + uv.y*sub.Pv + (1.0f - uv.x - uv.y)*sub.Pw; -} - -int TriangleDice::add_vert(SubPatch& sub, float2 uv) -{ - return EdgeDice::add_vert(sub.patch, map_uv(sub, uv)); -} - -void TriangleDice::add_grid(SubPatch& sub, EdgeFactors& ef, int M) -{ - // XXX normals are flipped, why? - - /* grid is constructed starting from the outside edges, and adding - * progressively smaller inner triangles that connected to the outer - * one, until M = 1 or 2, the we fill up the last part. */ - vector<int> outer_u, outer_v, outer_w; - int m; - - /* add outer corners vertices */ - { - float2 p_u = make_float2(1.0f, 0.0f); - float2 p_v = make_float2(0.0f, 1.0f); - float2 p_w = make_float2(0.0f, 0.0f); - - int corner_u = add_vert(sub, p_u); - int corner_v = add_vert(sub, p_v); - int corner_w = add_vert(sub, p_w); - - outer_u.push_back(corner_v); - outer_v.push_back(corner_w); - outer_w.push_back(corner_u); - - for(int i = 1; i < ef.tu; i++) - outer_u.push_back(add_vert(sub, interp(p_v, p_w, i/(float)ef.tu))); - for(int i = 1; i < ef.tv; i++) - outer_v.push_back(add_vert(sub, interp(p_w, p_u, i/(float)ef.tv))); - for(int i = 1; i < ef.tw; i++) - outer_w.push_back(add_vert(sub, interp(p_u, p_v, i/(float)ef.tw))); - - outer_u.push_back(corner_w); - outer_v.push_back(corner_u); - outer_w.push_back(corner_v); - } - - for(m = M-2; m > 0; m -= 2) { - vector<int> inner_u, inner_v, inner_w; - - const float t0 = m / (float)M; - float2 center = make_float2(1.0f/3.0f, 1.0f/3.0f); - - /* 3 corner vertices */ - float2 p_u = interp(center, make_float2(1.0f, 0.0f), t0); - float2 p_v = interp(center, make_float2(0.0f, 1.0f), t0); - float2 p_w = interp(center, make_float2(0.0f, 0.0f), t0); - - int corner_u = add_vert(sub, p_u); - int corner_v = add_vert(sub, p_v); - int corner_w = add_vert(sub, p_w); - - /* construct array of vertex indices for each side */ - inner_u.push_back(corner_v); - inner_v.push_back(corner_w); - inner_w.push_back(corner_u); - - for(int i = 1; i < m; i++) { - /* add vertices between corners */ - const float t1 = i / (float)m; - - inner_u.push_back(add_vert(sub, interp(p_v, p_w, t1))); - inner_v.push_back(add_vert(sub, interp(p_w, p_u, t1))); - inner_w.push_back(add_vert(sub, interp(p_u, p_v, t1))); - } - - inner_u.push_back(corner_w); - inner_v.push_back(corner_u); - inner_w.push_back(corner_v); - - /* stitch together inner/outer with triangles */ - stitch_triangles(sub.patch, outer_u, inner_u); - stitch_triangles(sub.patch, outer_v, inner_v); - stitch_triangles(sub.patch, outer_w, inner_w); - - outer_u = inner_u; - outer_v = inner_v; - outer_w = inner_w; - } - - /* fill up last part */ - if(m == -1) { - /* single triangle */ - add_triangle(sub.patch, outer_w[0], outer_u[0], outer_v[0]); - } - else { - /* center vertex + up to 6 triangles */ - int center = add_vert(sub, make_float2(1.0f/3.0f, 1.0f/3.0f)); - - add_triangle(sub.patch, outer_w[0], outer_w[1], center); - /* if this is false then there is only one triangle on this side */ - if(outer_w.size() > 2) - add_triangle(sub.patch, outer_w[1], outer_w[2], center); - - add_triangle(sub.patch, outer_u[0], outer_u[1], center); - if(outer_u.size() > 2) - add_triangle(sub.patch, outer_u[1], outer_u[2], center); - - add_triangle(sub.patch, outer_v[0], outer_v[1], center); - if(outer_v.size() > 2) - add_triangle(sub.patch, outer_v[1], outer_v[2], center); - } -} - -void TriangleDice::dice(SubPatch& sub, EdgeFactors& ef) -{ - /* todo: handle 2 1 1 resolution */ - int M = max(ef.tu, max(ef.tv, ef.tw)); - - /* Due to the "slant" of the edges of a triangle compared to a quad, the internal - * triangles end up smaller, causing over-tessellation. This is to correct for this - * difference in area. Technically its only correct for equilateral triangles, but - * its better than how it was. - * - * (2*cos(radians(30))/3)**0.5 - */ - float S = 0.7598356856515927f; - M = max((int)ceil(S*M), 1); - - reserve(ef, M); - add_grid(sub, ef, M); - - assert(vert_offset == params.mesh->verts.size()); -} - CCL_NAMESPACE_END diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h index 85bd0ea28f0..3002ec780e8 100644 --- a/intern/cycles/subd/subd_dice.h +++ b/intern/cycles/subd/subd_dice.h @@ -33,8 +33,6 @@ class Patch; struct SubdParams { Mesh *mesh; - int shader; - bool smooth; bool ptex; int test_steps; @@ -44,11 +42,9 @@ struct SubdParams { Camera *camera; Transform objecttoworld; - SubdParams(Mesh *mesh_, int shader_, bool smooth_ = true, bool ptex_ = false) + SubdParams(Mesh *mesh_, bool ptex_ = false) { mesh = mesh_; - shader = shader_; - smooth = smooth_; ptex = ptex_; test_steps = 3; @@ -136,46 +132,6 @@ public: void dice(SubPatch& sub, EdgeFactors& ef); }; -/* Triangle EdgeDice - * - * Edge tessellation factors and subpatch coordinates are as follows: - * - * Pw - * /\ - * tv / \ tu - * / \ - * / \ - * Pu -------- Pv - * tw - */ - -class TriangleDice : public EdgeDice { -public: - struct SubPatch { - Patch *patch; - - float2 Pu; - float2 Pv; - float2 Pw; - }; - - struct EdgeFactors { - int tu; - int tv; - int tw; - }; - - explicit TriangleDice(const SubdParams& params); - - void reserve(EdgeFactors& ef, int M); - - float2 map_uv(SubPatch& sub, float2 uv); - int add_vert(SubPatch& sub, float2 uv); - - void add_grid(SubPatch& sub, EdgeFactors& ef, int M); - void dice(SubPatch& sub, EdgeFactors& ef); -}; - CCL_NAMESPACE_END #endif /* __SUBD_DICE_H__ */ diff --git a/intern/cycles/subd/subd_mesh.cpp b/intern/cycles/subd/subd_mesh.cpp deleted file mode 100644 index 56d7d2b2303..00000000000 --- a/intern/cycles/subd/subd_mesh.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Original code in the public domain -- castanyo@yahoo.es - * - * Modifications copyright (c) 2011, Blender Foundation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdio.h> - -#include "subd_mesh.h" -#include "subd_patch.h" -#include "subd_split.h" - -#include "util_debug.h" -#include "util_foreach.h" - -#ifdef WITH_OPENSUBDIV - -#include <osd/vertex.h> -#include <osd/mesh.h> -#include <osd/cpuComputeController.h> -#include <osd/cpuVertexBuffer.h> -#include <osd/cpuEvalLimitController.h> -#include <osd/evalLimitContext.h> - -CCL_NAMESPACE_BEGIN - -/* typedefs */ -typedef OpenSubdiv::OsdVertex OsdVertex; -typedef OpenSubdiv::FarMesh<OsdVertex> OsdFarMesh; -typedef OpenSubdiv::FarMeshFactory<OsdVertex> OsdFarMeshFactory; -typedef OpenSubdiv::HbrCatmarkSubdivision<OsdVertex> OsdHbrCatmarkSubdivision; -typedef OpenSubdiv::HbrFace<OsdVertex> OsdHbrFace; -typedef OpenSubdiv::HbrHalfedge<OsdVertex> OsdHbrHalfEdge; -typedef OpenSubdiv::HbrMesh<OsdVertex> OsdHbrMesh; -typedef OpenSubdiv::HbrVertex<OsdVertex> OsdHbrVertex; -typedef OpenSubdiv::OsdCpuComputeContext OsdCpuComputeContext; -typedef OpenSubdiv::OsdCpuComputeController OsdCpuComputeController; -typedef OpenSubdiv::OsdCpuEvalLimitContext OsdCpuEvalLimitContext; -typedef OpenSubdiv::OsdCpuEvalLimitController OsdCpuEvalLimitController; -typedef OpenSubdiv::OsdCpuVertexBuffer OsdCpuVertexBuffer; -typedef OpenSubdiv::OsdEvalCoords OsdEvalCoords; -typedef OpenSubdiv::OsdVertexBufferDescriptor OsdVertexBufferDescriptor; - -/* OpenSubdiv Patch */ - -class OpenSubdPatch : public Patch { -public: - int face_id; - - OpenSubdPatch(OsdFarMesh *farmesh, OsdCpuVertexBuffer *vbuf_base) - { - face_id = 0; - - /* create buffers for evaluation */ - vbuf_P = OsdCpuVertexBuffer::Create(3, 1); - vbuf_dPdu = OsdCpuVertexBuffer::Create(3, 1); - vbuf_dPdv = OsdCpuVertexBuffer::Create(3, 1); - - P = vbuf_P->BindCpuBuffer(); - dPdu = vbuf_dPdu->BindCpuBuffer(); - dPdv = vbuf_dPdv->BindCpuBuffer(); - - /* setup evaluation context */ - OsdVertexBufferDescriptor in_desc(0, 3, 3), out_desc(0, 3, 3); /* offset, length, stride */ - - evalctx = OsdCpuEvalLimitContext::Create(farmesh, false); - evalctx->GetVertexData().Bind(in_desc, vbuf_base, out_desc, vbuf_P, vbuf_dPdu, vbuf_dPdv); - } - - ~OpenSubdPatch() - { - evalctx->GetVertexData().Unbind(); - - delete evalctx; - delete vbuf_P; - delete vbuf_dPdu; - delete vbuf_dPdv; - } - - void eval(float3 *P_, float3 *dPdu_, float3 *dPdv_, float u, float v) - { - OsdEvalCoords coords; - coords.u = u; - coords.v = v; - coords.face = face_id; - - evalctrl.EvalLimitSample<OsdCpuVertexBuffer,OsdCpuVertexBuffer>(coords, evalctx, 0); - - *P_ = make_float3(P[0], P[1], P[2]); - if(dPdu_) *dPdu_ = make_float3(dPdv[0], dPdv[1], dPdv[2]); - if(dPdv_) *dPdv_ = make_float3(dPdu[0], dPdu[1], dPdu[2]); - - /* optimize: skip evaluating derivatives when not needed */ - /* todo: swapped derivatives, different winding convention? */ - } - - BoundBox bound() - { - /* not implemented */ - BoundBox bbox = BoundBox::empty; - return bbox; - } - - int ptex_face_id() - { - return face_id; - } - -protected: - OsdCpuEvalLimitController evalctrl; - OsdCpuEvalLimitContext *evalctx; - OsdCpuVertexBuffer *vbuf_P; - OsdCpuVertexBuffer *vbuf_dPdu; - OsdCpuVertexBuffer *vbuf_dPdv; - float *P; - float *dPdu; - float *dPdv; -}; - -/* OpenSubdiv Mesh */ - -OpenSubdMesh::OpenSubdMesh() -{ - /* create osd mesh */ - static OsdHbrCatmarkSubdivision catmark; - OsdHbrMesh *hbrmesh = new OsdHbrMesh(&catmark); - - /* initialize class */ - num_verts = 0; - num_ptex_faces = 0; - _hbrmesh = (void*)hbrmesh; -} - -OpenSubdMesh::~OpenSubdMesh() -{ - OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - - if(hbrmesh) - delete hbrmesh; -} - -void OpenSubdMesh::add_vert(const float3& co) -{ - OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - - OsdVertex v; - positions.push_back(co.x); - positions.push_back(co.y); - positions.push_back(co.z); - hbrmesh->NewVertex(num_verts++, v); -} - -void OpenSubdMesh::add_face(int v0, int v1, int v2) -{ - int index[3] = {v0, v1, v2}; - return add_face(index, 3); -} - -void OpenSubdMesh::add_face(int v0, int v1, int v2, int v3) -{ - int index[4] = {v0, v1, v2, v3}; - add_face(index, 4); -} - -void OpenSubdMesh::add_face(int *index, int num) -{ - OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - -#ifndef NDEBUG - /* sanity checks */ - for(int j = 0; j < num; j++) { - OsdHbrVertex *origin = hbrmesh->GetVertex(index[j]); - OsdHbrVertex *destination = hbrmesh->GetVertex(index[(j+1)%num]); - OsdHbrHalfEdge *opposite = destination->GetEdge(origin); - - if(origin==NULL || destination==NULL) - assert(!"An edge was specified that connected a nonexistent vertex\n"); - - if(origin == destination) - assert(!"An edge was specified that connected a vertex to itself\n"); - - if(opposite && opposite->GetOpposite()) - assert(!"A non-manifold edge incident to more than 2 faces was found\n"); - - if(origin->GetEdge(destination)) { - assert(!"An edge connecting two vertices was specified more than once." - "It's likely that an incident face was flipped\n"); - } - } -#endif - - OsdHbrFace *face = hbrmesh->NewFace(num, index, 0); - - /* this is required for limit eval patch table? */ - face->SetPtexIndex(num_ptex_faces); - - if(num == 4) - num_ptex_faces++; - else - num_ptex_faces += num; -} - -bool OpenSubdMesh::finish() -{ - OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - - /* finish hbr mesh construction */ - hbrmesh->SetInterpolateBoundaryMethod(OsdHbrMesh::k_InterpolateBoundaryEdgeOnly); - hbrmesh->Finish(); - - return true; -} - -void OpenSubdMesh::tessellate(DiagSplit *split) -{ - if(num_ptex_faces == 0) - return; - - const int level = 3; - const bool requirefvar = false; - - /* convert HRB to FAR mesh */ - OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh; - - OsdFarMeshFactory meshFactory(hbrmesh, level, true); - OsdFarMesh *farmesh = meshFactory.Create(requirefvar); - int num_hbr_verts = hbrmesh->GetNumVertices(); - - delete hbrmesh; - hbrmesh = NULL; - _hbrmesh = NULL; - - /* refine HBR mesh with vertex coordinates */ - OsdCpuComputeController *compute_controller = new OsdCpuComputeController(); - OsdCpuComputeContext *compute_context = OsdCpuComputeContext::Create(farmesh); - - OsdCpuVertexBuffer *vbuf_base = OsdCpuVertexBuffer::Create(3, num_hbr_verts); - vbuf_base->UpdateData(&positions[0], 0, num_verts); - - compute_controller->Refine(compute_context, farmesh->GetKernelBatches(), vbuf_base); - compute_controller->Synchronize(); - - /* split & dice patches */ - OpenSubdPatch patch(farmesh, vbuf_base); - - for(int f = 0; f < num_ptex_faces; f++) { - patch.face_id = f; - split->split_quad(&patch); - } - - /* clean up */ - delete farmesh; - delete compute_controller; - delete compute_context; - delete vbuf_base; -} - -CCL_NAMESPACE_END - -#else /* WITH_OPENSUBDIV */ - -CCL_NAMESPACE_BEGIN - -/* Subd Vertex */ - -class SubdVert -{ -public: - int id; - float3 co; - - explicit SubdVert(int id_) - { - id = id_; - co = make_float3(0.0f, 0.0f, 0.0f); - } -}; - -/* Subd Face */ - -class SubdFace -{ -public: - int id; - int numverts; - int verts[4]; - - explicit SubdFace(int id_) - { - id = id_; - numverts = 0; - } -}; - -/* Subd Mesh */ - -SubdMesh::SubdMesh() -{ -} - -SubdMesh::~SubdMesh() -{ - foreach(SubdVert *vertex, verts) - delete vertex; - foreach(SubdFace *face, faces) - delete face; - - verts.clear(); - faces.clear(); -} - -SubdVert *SubdMesh::add_vert(const float3& co) -{ - SubdVert *v = new SubdVert(verts.size()); - v->co = co; - verts.push_back(v); - - return v; -} - -SubdFace *SubdMesh::add_face(int v0, int v1, int v2) -{ - int index[3] = {v0, v1, v2}; - return add_face(index, 3); -} - -SubdFace *SubdMesh::add_face(int v0, int v1, int v2, int v3) -{ - int index[4] = {v0, v1, v2, v3}; - return add_face(index, 4); -} - -SubdFace *SubdMesh::add_face(int *index, int num) -{ - /* skip ngons */ - if(num < 3 || num > 4) - return NULL; - - SubdFace *f = new SubdFace(faces.size()); - - for(int i = 0; i < num; i++) - f->verts[i] = index[i]; - - f->numverts = num; - faces.push_back(f); - - return f; -} - -bool SubdMesh::finish() -{ - return true; -} - -void SubdMesh::tessellate(DiagSplit *split) -{ - int num_faces = faces.size(); - - for(int f = 0; f < num_faces; f++) { - SubdFace *face = faces[f]; - Patch *patch; - float3 *hull; - - if(face->numverts == 3) { - LinearTrianglePatch *lpatch = new LinearTrianglePatch(); - hull = lpatch->hull; - patch = lpatch; - } - else if(face->numverts == 4) { - LinearQuadPatch *lpatch = new LinearQuadPatch(); - hull = lpatch->hull; - patch = lpatch; - } - else { - assert(0); /* n-gons should have been split already */ - continue; - } - - for(int i = 0; i < face->numverts; i++) - hull[i] = verts[face->verts[i]]->co; - - if(face->numverts == 4) - swap(hull[2], hull[3]); - - if(patch->is_triangle()) - split->split_triangle(patch); - else - split->split_quad(patch); - - delete patch; - } -} - -CCL_NAMESPACE_END - -#endif /* WITH_OPENSUBDIV */ - diff --git a/intern/cycles/subd/subd_mesh.h b/intern/cycles/subd/subd_mesh.h deleted file mode 100644 index f6aefc20318..00000000000 --- a/intern/cycles/subd/subd_mesh.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Original code in the public domain -- castanyo@yahoo.es - * - * Modifications copyright (c) 2011, Blender Foundation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SUBD_MESH_H__ -#define __SUBD_MESH_H__ - -#include "util_map.h" -#include "util_types.h" -#include "util_vector.h" - -CCL_NAMESPACE_BEGIN - -#ifndef WITH_OPENSUBDIV -class SubdVert; -class SubdFace; -#endif - -class DiagSplit; -class Mesh; - -/* Subd Mesh with simple linear subdivision */ - -class SubdMesh -{ -public: - SubdMesh(); - ~SubdMesh(); - - SubdVert *add_vert(const float3& co); - - SubdFace *add_face(int v0, int v1, int v2); - SubdFace *add_face(int v0, int v1, int v2, int v3); - SubdFace *add_face(int *index, int num); - - bool finish(); - void tessellate(DiagSplit *split); - -protected: -#ifdef WITH_OPENSUBDIV - void *_hbrmesh; - vector<float> positions; - int num_verts, num_ptex_faces; -#else - vector<SubdVert*> verts; - vector<SubdFace*> faces; -#endif - -}; - -CCL_NAMESPACE_END - -#endif /* __SUBD_MESH_H__ */ - diff --git a/intern/cycles/subd/subd_patch.cpp b/intern/cycles/subd/subd_patch.cpp index 60a78016054..d3319c5ccf5 100644 --- a/intern/cycles/subd/subd_patch.cpp +++ b/intern/cycles/subd/subd_patch.cpp @@ -84,32 +84,6 @@ BoundBox LinearQuadPatch::bound() return bbox; } -/* Linear Triangle Patch */ - -void LinearTrianglePatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) -{ - *P = u*hull[0] + v*hull[1] + (1.0f - u - v)*hull[2]; - - if(dPdu && dPdv) { - *dPdu = hull[0] - hull[2]; - *dPdv = hull[1] - hull[2]; - } - - if(N) { - *N = normalize(u*normals[0] + v*normals[1] + (1.0f - u - v)*normals[2]); - } -} - -BoundBox LinearTrianglePatch::bound() -{ - BoundBox bbox = BoundBox::empty; - - for(int i = 0; i < 3; i++) - bbox.grow(hull[i]); - - return bbox; -} - /* Bicubic Patch */ void BicubicPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) diff --git a/intern/cycles/subd/subd_patch.h b/intern/cycles/subd/subd_patch.h index bfa04412c66..360c1abf27b 100644 --- a/intern/cycles/subd/subd_patch.h +++ b/intern/cycles/subd/subd_patch.h @@ -26,9 +26,11 @@ class Patch { public: virtual ~Patch() {} virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) = 0; - virtual bool is_triangle() { return false; } virtual BoundBox bound() = 0; virtual int ptex_face_id() { return -1; } + + int patch_index; + int shader; }; /* Linear Quad Patch */ @@ -39,19 +41,6 @@ public: float3 normals[4]; void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v); - bool is_triangle() { return false; } - BoundBox bound(); -}; - -/* Linear Triangle Patch */ - -class LinearTrianglePatch : public Patch { -public: - float3 hull[3]; - float3 normals[3]; - - void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v); - bool is_triangle() { return true; } BoundBox bound(); }; @@ -62,7 +51,6 @@ public: float3 hull[16]; void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v); - bool is_triangle() { return false; } BoundBox bound(); }; diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp index c4af8cc8c43..3c91ad8ab0d 100644 --- a/intern/cycles/subd/subd_split.cpp +++ b/intern/cycles/subd/subd_split.cpp @@ -40,12 +40,6 @@ void DiagSplit::dispatch(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef) edgefactors_quad.push_back(ef); } -void DiagSplit::dispatch(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef) -{ - subpatches_triangle.push_back(sub); - edgefactors_triangle.push_back(ef); -} - float3 DiagSplit::to_world(Patch *patch, float2 uv) { float3 P; @@ -112,34 +106,6 @@ void DiagSplit::partition_edge(Patch *patch, float2 *P, int *t0, int *t1, float2 } } -static float2 right_to_equilateral(float2 P) -{ - static const float2 A = make_float2(1.0f, 0.5f); - static const float2 B = make_float2(0.0f, sinf(M_PI_F/3.0f)); - return make_float2(dot(P, A), dot(P, B)); -} - -static void limit_edge_factors(const TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int max_t) -{ - float2 Pu = sub.Pu; - float2 Pv = sub.Pv; - float2 Pw = sub.Pw; - - if(sub.patch->is_triangle()) { - Pu = right_to_equilateral(Pu); - Pv = right_to_equilateral(Pv); - Pw = right_to_equilateral(Pw); - } - - int tu = int(max_t * len(Pw - Pv)); - int tv = int(max_t * len(Pw - Pu)); - int tw = int(max_t * len(Pv - Pu)); - - ef.tu = tu <= 1 ? 1 : min(ef.tu, tu); - ef.tv = tv <= 1 ? 1 : min(ef.tv, tv); - ef.tw = tw <= 1 ? 1 : min(ef.tw, tw); -} - static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int max_t) { float2 P00 = sub.P00; @@ -147,13 +113,6 @@ static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFact float2 P10 = sub.P10; float2 P11 = sub.P11; - if(sub.patch->is_triangle()) { - P00 = right_to_equilateral(P00); - P01 = right_to_equilateral(P01); - P10 = right_to_equilateral(P10); - P11 = right_to_equilateral(P11); - } - int tu0 = int(max_t * len(P10 - P00)); int tu1 = int(max_t * len(P11 - P01)); int tv0 = int(max_t * len(P01 - P00)); @@ -165,84 +124,6 @@ static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFact ef.tv1 = tv1 <= 1 ? 1 : min(ef.tv1, tv1); } -void DiagSplit::split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth) -{ - if(depth > 32) { - /* We should never get here, but just in case end recursion safely. */ - ef.tu = 1; - ef.tv = 1; - ef.tw = 1; - - dispatch(sub, ef); - return; - } - - assert(ef.tu == T(sub.patch, sub.Pv, sub.Pw)); - assert(ef.tv == T(sub.patch, sub.Pw, sub.Pu)); - assert(ef.tw == T(sub.patch, sub.Pu, sub.Pv)); - - int non_uniform_count = int(ef.tu == DSPLIT_NON_UNIFORM) + - int(ef.tv == DSPLIT_NON_UNIFORM) + - int(ef.tw == DSPLIT_NON_UNIFORM); - - switch(non_uniform_count) { - case 1: { - /* TODO(mai): one edge is non-uniform, split into two triangles */ - // fallthru - } - case 2: { - /* TODO(mai): two edges are non-uniform, split into triangle and quad */ - // fallthru - } - case 3: { - /* all three edges are non-uniform, split into three quads */ - - /* partition edges */ - QuadDice::EdgeFactors ef0, ef1, ef2; - float2 Pu, Pv, Pw, Pcenter; - - partition_edge(sub.patch, &Pu, &ef1.tv0, &ef2.tu0, sub.Pw, sub.Pv, ef.tu); - partition_edge(sub.patch, &Pv, &ef0.tv0, &ef1.tu0, sub.Pu, sub.Pw, ef.tv); - partition_edge(sub.patch, &Pw, &ef2.tv0, &ef0.tu0, sub.Pv, sub.Pu, ef.tw); - Pcenter = (Pu + Pv + Pw) * (1.0f / 3.0f); - - /* split */ - int tsplit01 = T(sub.patch, Pv, Pcenter); - int tsplit12 = T(sub.patch, Pu, Pcenter); - int tsplit20 = T(sub.patch, Pw, Pcenter); - - ef0.tu1 = tsplit01; - ef0.tv1 = tsplit20; - - ef1.tu1 = tsplit12; - ef1.tv1 = tsplit01; - - ef2.tu1 = tsplit20; - ef2.tv1 = tsplit12; - - /* create subpatches */ - QuadDice::SubPatch sub0 = {sub.patch, sub.Pu, Pw, Pv, Pcenter}; - QuadDice::SubPatch sub1 = {sub.patch, sub.Pw, Pv, Pu, Pcenter}; - QuadDice::SubPatch sub2 = {sub.patch, sub.Pv, Pu, Pw, Pcenter}; - - limit_edge_factors(sub0, ef0, 1 << params.max_level); - limit_edge_factors(sub1, ef1, 1 << params.max_level); - limit_edge_factors(sub2, ef2, 1 << params.max_level); - - split(sub0, ef0, depth+1); - split(sub1, ef1, depth+1); - split(sub2, ef2, depth+1); - - break; - } - default: { - /* all edges uniform, no splitting needed */ - dispatch(sub, ef); - break; - } - } -} - void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int depth) { if(depth > 32) { @@ -259,6 +140,16 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de bool split_u = (ef.tu0 == DSPLIT_NON_UNIFORM || ef.tu1 == DSPLIT_NON_UNIFORM); bool split_v = (ef.tv0 == DSPLIT_NON_UNIFORM || ef.tv1 == DSPLIT_NON_UNIFORM); + /* Split subpatches such that the ratio of T for opposite edges doesn't + * exceed 1.5, this reduces over tessellation for some patches + */ + bool tmp_split_v = split_v; + if(!split_u && min(ef.tu0, ef.tu1) > 8 && min(ef.tu0, ef.tu1)*1.5f < max(ef.tu0, ef.tu1)) + split_v = true; + if(!tmp_split_v && min(ef.tu0, ef.tu1) > 8 && min(ef.tv0, ef.tv1)*1.5f < max(ef.tv0, ef.tv1)) + split_u = true; + + /* alternate axis */ if(split_u && split_v) { split_u = depth % 2; } @@ -324,69 +215,21 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de } } -void DiagSplit::split_triangle(Patch *patch) -{ - TriangleDice::SubPatch sub_split; - TriangleDice::EdgeFactors ef_split; - - sub_split.patch = patch; - sub_split.Pu = make_float2(1.0f, 0.0f); - sub_split.Pv = make_float2(0.0f, 1.0f); - sub_split.Pw = make_float2(0.0f, 0.0f); - - ef_split.tu = T(patch, sub_split.Pv, sub_split.Pw); - ef_split.tv = T(patch, sub_split.Pw, sub_split.Pu); - ef_split.tw = T(patch, sub_split.Pu, sub_split.Pv); - - limit_edge_factors(sub_split, ef_split, 1 << params.max_level); - - split(sub_split, ef_split); - - TriangleDice dice(params); - - for(size_t i = 0; i < subpatches_triangle.size(); i++) { - TriangleDice::SubPatch& sub = subpatches_triangle[i]; - TriangleDice::EdgeFactors& ef = edgefactors_triangle[i]; - - ef.tu = max(ef.tu, 1); - ef.tv = max(ef.tv, 1); - ef.tw = max(ef.tw, 1); - - dice.dice(sub, ef); - } - - subpatches_triangle.clear(); - edgefactors_triangle.clear(); - - /* triangle might be split into quads so dice quad subpatches as well */ - QuadDice qdice(params); - - for(size_t i = 0; i < subpatches_quad.size(); i++) { - QuadDice::SubPatch& sub = subpatches_quad[i]; - QuadDice::EdgeFactors& ef = edgefactors_quad[i]; - - ef.tu0 = max(ef.tu0, 1); - ef.tu1 = max(ef.tu1, 1); - ef.tv0 = max(ef.tv0, 1); - ef.tv1 = max(ef.tv1, 1); - - qdice.dice(sub, ef); - } - - subpatches_quad.clear(); - edgefactors_quad.clear(); -} - -void DiagSplit::split_quad(Patch *patch) +void DiagSplit::split_quad(Patch *patch, QuadDice::SubPatch *subpatch) { QuadDice::SubPatch sub_split; QuadDice::EdgeFactors ef_split; - sub_split.patch = patch; - sub_split.P00 = make_float2(0.0f, 0.0f); - sub_split.P10 = make_float2(1.0f, 0.0f); - sub_split.P01 = make_float2(0.0f, 1.0f); - sub_split.P11 = make_float2(1.0f, 1.0f); + if(subpatch) { + sub_split = *subpatch; + } + else { + sub_split.patch = patch; + sub_split.P00 = make_float2(0.0f, 0.0f); + sub_split.P10 = make_float2(1.0f, 0.0f); + sub_split.P01 = make_float2(0.0f, 1.0f); + sub_split.P11 = make_float2(1.0f, 1.0f); + } ef_split.tu0 = T(patch, sub_split.P00, sub_split.P10); ef_split.tu1 = T(patch, sub_split.P01, sub_split.P11); diff --git a/intern/cycles/subd/subd_split.h b/intern/cycles/subd/subd_split.h index bbe921f739c..a2f76dd2e03 100644 --- a/intern/cycles/subd/subd_split.h +++ b/intern/cycles/subd/subd_split.h @@ -38,8 +38,6 @@ class DiagSplit { public: vector<QuadDice::SubPatch> subpatches_quad; vector<QuadDice::EdgeFactors> edgefactors_quad; - vector<TriangleDice::SubPatch> subpatches_triangle; - vector<TriangleDice::EdgeFactors> edgefactors_triangle; SubdParams params; @@ -53,11 +51,7 @@ public: void dispatch(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef); void split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int depth=0); - void dispatch(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef); - void split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth=0); - - void split_triangle(Patch *patch); - void split_quad(Patch *patch); + void split_quad(Patch *patch, QuadDice::SubPatch *subpatch=NULL); }; CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index cfe6fa65143..e070b51ae32 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -174,6 +174,11 @@ ccl_device_inline float clamp(float a, float mn, float mx) return min(max(a, mn), mx); } +ccl_device_inline float mix(float a, float b, float t) +{ + return a + t*(b - a); +} + #endif #ifndef __KERNEL_CUDA__ @@ -219,6 +224,11 @@ ccl_device_inline float smoothstepf(float f) return (3.0f*ff - 2.0f*ff*f); } +ccl_device_inline int mod(int x, int m) +{ + return (x % m + m) % m; +} + /* Float2 Vector */ #ifndef __KERNEL_OPENCL__ @@ -652,6 +662,15 @@ ccl_device_inline float3 interp(float3 a, float3 b, float t) return a + t*(b - a); } +#ifndef __KERNEL_OPENCL__ + +ccl_device_inline float3 mix(float3 a, float3 b, float t) +{ + return a + t*(b - a); +} + +#endif + ccl_device_inline bool is_zero(const float3 a) { #ifdef __KERNEL_SSE__ |