/* * 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