Cycles Standalone: Fix support for subdivision meshes

Changes from microdisplacement work broke previous support for subdivision
meshes, sometimes leading to crashes; this makes things work again. Files
that contain "patch" nodes will need to be updated to use meshes instead, as
specifying patches was both inefficient and completely unsupported by the new
subdivision code.
This commit is contained in:
Mai Lavelle
2016-08-23 13:57:45 -04:00
parent 0ca4e39424
commit 74bd809962
4 changed files with 96 additions and 116 deletions

View File

@@ -62,7 +62,7 @@ struct XMLReadState : public XMLReader {
: scene(NULL),
smooth(false),
shader(NULL),
dicing_rate(0.0f)
dicing_rate(1.0f)
{
tfm = transform_identity();
}
@@ -197,6 +197,9 @@ static void xml_read_camera(XMLReadState& state, pugi::xml_node node)
xml_read_int(&cam->width, node, "width");
xml_read_int(&cam->height, node, "height");
cam->full_width = cam->width;
cam->full_height = cam->height;
xml_read_node(state, cam, node);
cam->matrix = state.tfm;
@@ -412,53 +415,14 @@ 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;
/* create subd vertices */
for(size_t i = 0; i < P.size(); i++)
sdmesh.add_vert(P[i]);
/* create subd faces */
int index_offset = 0;
for(size_t i = 0; i < nverts.size(); i++) {
if(nverts[i] == 4) {
int v0 = verts[index_offset + 0];
int v1 = verts[index_offset + 1];
int v2 = verts[index_offset + 2];
int v3 = verts[index_offset + 3];
sdmesh.add_face(v0, v1, v2, v3);
}
else {
for(int j = 0; j < nverts[i]-2; j++) {
int v0 = verts[index_offset];
int v1 = verts[index_offset + j + 1];
int v2 = verts[index_offset + j + 2];
sdmesh.add_face(v0, v1, v2);
}
}
index_offset += nverts[i];
}
/* finalize subd mesh */
sdmesh.finish();
/* parameters */
SubdParams sdparams(mesh, shader, smooth);
xml_read_float(&sdparams.dicing_rate, node, "dicing_rate");
DiagSplit dsplit(sdparams);
sdmesh.tessellate(&dsplit);
mesh->subdivision_type = Mesh::SUBDIVISION_CATMULL_CLARK;
}
else
#endif
{
else if(xml_equal_string(node, "subdivision", "linear")) {
mesh->subdivision_type = Mesh::SUBDIVISION_LINEAR;
}
if(mesh->subdivision_type == Mesh::SUBDIVISION_NONE) {
/* create vertices */
mesh->verts = P;
@@ -513,72 +477,65 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
}
}
}
else {
/* create vertices */
mesh->verts = P;
size_t num_ngons = 0;
size_t num_corners = 0;
for(size_t i = 0; i < nverts.size(); i++) {
num_ngons += (nverts[i] == 4) ? 0 : 1;
num_corners += nverts[i];
}
mesh->reserve_subd_faces(nverts.size(), num_ngons, num_corners);
/* create subd_faces */
int index_offset = 0;
for(size_t i = 0; i < nverts.size(); i++) {
mesh->add_subd_face(&verts[index_offset], nverts[i], shader, smooth);
index_offset += nverts[i];
}
/* uv map */
if(xml_read_float_array(UV, node, "UV")) {
ustring name = ustring("UVMap");
Attribute *attr = mesh->subd_attributes.add(ATTR_STD_UV, name);
float3 *fdata = attr->data_float3();
#if 0
if(subdivide_uvs) {
attr->flags |= ATTR_SUBDIVIDED;
}
#endif
index_offset = 0;
for(size_t i = 0; i < nverts.size(); i++) {
for(int j = 0; j < nverts[i]; j++) {
*(fdata++) = make_float3(UV[index_offset++]);
}
}
}
/* setup subd params */
if(!mesh->subd_params) {
mesh->subd_params = new SubdParams(mesh);
}
SubdParams& sdparams = *mesh->subd_params;
sdparams.dicing_rate = state.dicing_rate;
xml_read_float(&sdparams.dicing_rate, node, "dicing_rate");
sdparams.dicing_rate = std::max(0.1f, sdparams.dicing_rate);
state.scene->camera->update();
sdparams.camera = state.scene->camera;
sdparams.objecttoworld = state.tfm;
}
/* temporary for test compatibility */
mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
}
/* Patch */
static void xml_read_patch(const XMLReadState& state, pugi::xml_node node)
{
/* read patch */
Patch *patch = NULL;
vector<float3> P;
xml_read_float3_array(P, node, "P");
if(xml_equal_string(node, "type", "bilinear")) {
/* bilinear patch */
if(P.size() == 4) {
LinearQuadPatch *bpatch = new LinearQuadPatch();
for(int i = 0; i < 4; i++)
P[i] = transform_point(&state.tfm, P[i]);
memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
patch = bpatch;
}
else
fprintf(stderr, "Invalid number of control points for bilinear patch.\n");
}
else if(xml_equal_string(node, "type", "bicubic")) {
/* bicubic patch */
if(P.size() == 16) {
BicubicPatch *bpatch = new BicubicPatch();
for(int i = 0; i < 16; i++)
P[i] = transform_point(&state.tfm, P[i]);
memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
patch = bpatch;
}
else
fprintf(stderr, "Invalid number of control points for bicubic patch.\n");
}
else
fprintf(stderr, "Unknown patch type.\n");
if(patch) {
/* add mesh */
Mesh *mesh = xml_add_mesh(state.scene, transform_identity());
mesh->used_shaders.push_back(state.shader);
/* split */
SubdParams sdparams(mesh);
xml_read_float(&sdparams.dicing_rate, node, "dicing_rate");
DiagSplit dsplit(sdparams);
dsplit.split_quad(patch);
delete patch;
/* temporary for test compatibility */
mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
}
}
/* Light */
static void xml_read_light(XMLReadState& state, pugi::xml_node node)
@@ -676,9 +633,6 @@ static void xml_read_scene(XMLReadState& state, pugi::xml_node scene_node)
else if(string_iequals(node.name(), "mesh")) {
xml_read_mesh(state, node);
}
else if(string_iequals(node.name(), "patch")) {
xml_read_patch(state, node);
}
else if(string_iequals(node.name(), "light")) {
xml_read_light(state, node);
}
@@ -739,7 +693,7 @@ void xml_read_file(Scene *scene, const char *filepath)
state.tfm = transform_identity();
state.shader = scene->default_surface;
state.smooth = false;
state.dicing_rate = 0.1f;
state.dicing_rate = 1.0f;
state.base = path_dirname(filepath);
xml_read_include(state, path_filename(filepath));

View File

@@ -30,14 +30,14 @@ ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals *kg, ShaderData
if(ccl_fetch(sd, object) != OBJECT_NONE) {
desc = find_attribute(kg, sd, node.y);
if(desc.offset == ATTR_STD_NOT_FOUND) {
desc.element = ATTR_ELEMENT_NONE;
desc = attribute_not_found();
desc.offset = 0;
desc.type = (NodeAttributeType)node.w;
}
}
else {
/* background */
desc.element = ATTR_ELEMENT_NONE;
desc = attribute_not_found();
desc.offset = 0;
desc.type = (NodeAttributeType)node.w;
}

View File

@@ -500,7 +500,7 @@ void Mesh::add_vertex_normals()
size_t triangles_size = num_triangles();
/* static vertex normals */
if(!attributes.find(ATTR_STD_VERTEX_NORMAL)) {
if(!attributes.find(ATTR_STD_VERTEX_NORMAL) && triangles_size) {
/* get attributes */
Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL);
@@ -529,7 +529,7 @@ void Mesh::add_vertex_normals()
Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
if(has_motion_blur() && attr_mP && !attr_mN) {
if(has_motion_blur() && attr_mP && !attr_mN && triangles_size) {
/* create attribute */
attr_mN = attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
@@ -556,6 +556,32 @@ void Mesh::add_vertex_normals()
}
}
}
/* subd vertex normals */
if(!subd_attributes.find(ATTR_STD_VERTEX_NORMAL) && subd_faces.size()) {
/* get attributes */
Attribute *attr_vN = subd_attributes.add(ATTR_STD_VERTEX_NORMAL);
float3 *vN = attr_vN->data_float3();
/* compute vertex normals */
memset(vN, 0, verts.size()*sizeof(float3));
for(size_t i = 0; i < subd_faces.size(); i++) {
SubdFace& face = subd_faces[i];
for(size_t j = 0; j < face.num_corners; j++) {
size_t corner = subd_face_corners[face.start_corner+j];
vN[corner] += verts[corner];
}
}
for(size_t i = 0; i < verts_size; i++) {
vN[i] = normalize(vN[i]);
if(flip) {
vN[i] = -vN[i];
}
}
}
}
void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)

View File

@@ -49,7 +49,7 @@ struct SubdParams {
test_steps = 3;
split_threshold = 1;
dicing_rate = 0.1f;
dicing_rate = 1.0f;
max_level = 12;
camera = NULL;
}