Files
test2/intern/cycles/blender/blender_mesh.cpp
Brecht Van Lommel 131de4352b Cycles: fixes to make CUDA 4.2 work, compiling gave errors in shadows and
other places, was mainly due to instancing not working, but also found
issues in procedural textures.

The problem was with --use_fast_math, this seems to now have way lower
precision for some operations. Disabled this flag and selectively use
fast math functions. Did not find performance regression on GTX 460 after
doing this.
2012-05-28 19:21:13 +00:00

338 lines
9.6 KiB
C++

/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mesh.h"
#include "object.h"
#include "scene.h"
#include "blender_sync.h"
#include "blender_util.h"
#include "subd_mesh.h"
#include "subd_patch.h"
#include "subd_split.h"
#include "util_foreach.h"
CCL_NAMESPACE_BEGIN
/* Find/Add */
static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
{
/* create vertices */
BL::Mesh::vertices_iterator v;
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
mesh->verts.push_back(get_float3(v->co()));
/* create vertex normals */
Attribute *attr_N = mesh->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)
*N= get_float3(v->normal());
/* create faces */
BL::Mesh::tessfaces_iterator f;
vector<int> nverts;
for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
int4 vi = get_int4(f->vertices_raw());
int n = (vi[3] == 0)? 3: 4;
int mi = clamp(f->material_index(), 0, used_shaders.size()-1);
int shader = used_shaders[mi];
bool smooth = f->use_smooth();
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
if(n == 4)
mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
nverts.push_back(n);
}
/* create generated coordinates. todo: we should actually get the orco
coordinates from modifiers, for now we use texspace loc/size which
is available in the api. */
if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
float3 loc = get_float3(b_mesh.texspace_location());
float3 size = get_float3(b_mesh.texspace_size());
if(size.x != 0.0f) size.x = 0.5f/size.x;
if(size.y != 0.0f) size.y = 0.5f/size.y;
if(size.z != 0.0f) size.z = 0.5f/size.z;
loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
float3 *fdata = attr->data_float3();
BL::Mesh::vertices_iterator v;
size_t i = 0;
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
fdata[i++] = get_float3(v->co())*size - loc;
}
/* create vertex color attributes */
{
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, Attribute::CORNER);
BL::MeshColorLayer::data_iterator c;
float3 *fdata = attr->data_float3();
size_t i = 0;
for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
fdata[0] = color_srgb_to_scene_linear(get_float3(c->color1()));
fdata[1] = color_srgb_to_scene_linear(get_float3(c->color2()));
fdata[2] = color_srgb_to_scene_linear(get_float3(c->color3()));
if(nverts[i] == 4) {
fdata[3] = fdata[0];
fdata[4] = fdata[2];
fdata[5] = color_srgb_to_scene_linear(get_float3(c->color4()));
fdata += 6;
}
else
fdata += 3;
}
}
}
/* create uv map attributes */
{
BL::Mesh::tessface_uv_textures_iterator l;
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
AttributeStandard std = (l->active_render())? ATTR_STD_UV: ATTR_STD_NONE;
ustring name = ustring(l->name().c_str());
if(!(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)))
continue;
Attribute *attr;
if(l->active_render())
attr = mesh->attributes.add(std, name);
else
attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);
BL::MeshTextureFaceLayer::data_iterator t;
float3 *fdata = attr->data_float3();
size_t i = 0;
for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
fdata[0] = get_float3(t->uv1());
fdata[1] = get_float3(t->uv2());
fdata[2] = get_float3(t->uv3());
fdata += 3;
if(nverts[i] == 4) {
fdata[0] = get_float3(t->uv1());
fdata[1] = get_float3(t->uv3());
fdata[2] = get_float3(t->uv4());
fdata += 3;
}
}
}
}
}
static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
{
/* create subd mesh */
SubdMesh sdmesh;
/* create vertices */
BL::Mesh::vertices_iterator v;
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
sdmesh.add_vert(get_float3(v->co()));
/* create faces */
BL::Mesh::tessfaces_iterator f;
for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
int4 vi = get_int4(f->vertices_raw());
int n= (vi[3] == 0)? 3: 4;
//int shader = used_shaders[f->material_index()];
if(n == 4)
sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
/*else
sdmesh.add_face(vi[0], vi[1], vi[2]);*/
}
/* finalize subd mesh */
sdmesh.link_boundary();
/* subdivide */
DiagSplit dsplit;
dsplit.camera = NULL;
dsplit.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
sdmesh.tessellate(&dsplit, false, mesh, used_shaders[0], true);
}
/* Sync */
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
{
/* test if we can instance or if the object is modified */
BL::ID b_ob_data = b_ob.data();
BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
BL::Material material_override = render_layer.material_override;
/* find shader indices */
vector<uint> used_shaders;
BL::Object::material_slots_iterator slot;
for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
BL::Material material_override = render_layer.material_override;
if(material_override)
find_shader(material_override, used_shaders, scene->default_surface);
else
find_shader(slot->material(), used_shaders, scene->default_surface);
}
if(used_shaders.size() == 0) {
if(material_override)
find_shader(material_override, used_shaders, scene->default_surface);
else
used_shaders.push_back(scene->default_surface);
}
/* test if we need to sync */
Mesh *mesh;
if(!mesh_map.sync(&mesh, key)) {
/* if transform was applied to mesh, need full update */
if(object_updated && mesh->transform_applied);
/* test if shaders changed, these can be object level so mesh
does not get tagged for recalc */
else if(mesh->used_shaders != used_shaders);
else {
/* even if not tagged for recalc, we may need to sync anyway
* because the shader needs different mesh attributes */
bool attribute_recalc = false;
foreach(uint shader, mesh->used_shaders)
if(scene->shaders[shader]->need_update_attributes)
attribute_recalc = true;
if(!attribute_recalc)
return mesh;
}
}
/* ensure we only sync instanced meshes once */
if(mesh_synced.find(mesh) != mesh_synced.end())
return mesh;
mesh_synced.insert(mesh);
/* create derived mesh */
BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
vector<Mesh::Triangle> oldtriangle = mesh->triangles;
mesh->clear();
mesh->used_shaders = used_shaders;
mesh->name = ustring(b_ob_data.name().c_str());
if(b_mesh) {
if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
else
create_mesh(scene, mesh, b_mesh, used_shaders);
/* free derived mesh */
object_remove_mesh(b_data, b_mesh);
}
/* displacement method */
if(cmesh.data) {
int method = RNA_enum_get(&cmesh, "displacement_method");
if(method == 0 || !experimental)
mesh->displacement_method = Mesh::DISPLACE_BUMP;
else if(method == 1)
mesh->displacement_method = Mesh::DISPLACE_TRUE;
else
mesh->displacement_method = Mesh::DISPLACE_BOTH;
}
/* tag update */
bool rebuild = false;
if(oldtriangle.size() != mesh->triangles.size())
rebuild = true;
else if(oldtriangle.size()) {
if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
rebuild = true;
}
mesh->tag_update(scene, rebuild);
return mesh;
}
void BlenderSync::sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion)
{
/* todo: displacement, subdivision */
size_t size = mesh->verts.size();
/* skip objects without deforming modifiers. this is not a totally reliable,
* would need a more extensive check to see which objects are animated */
if(!size || !ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview))
return;
/* get derived mesh */
BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
if(b_mesh) {
BL::Mesh::vertices_iterator v;
AttributeStandard std = (motion == -1)? ATTR_STD_MOTION_PRE: ATTR_STD_MOTION_POST;
Attribute *attr_M = mesh->attributes.add(std);
float3 *M = attr_M->data_float3();
size_t i = 0, size = mesh->verts.size();
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < size; ++v, M++, i++)
*M = get_float3(v->co());
/* if number of vertices changed, or if coordinates stayed the same, drop it */
if(i != size || memcmp(M, &mesh->verts[0], sizeof(float3)*size) == 0)
mesh->attributes.remove(std);
/* free derived mesh */
object_remove_mesh(b_data, b_mesh);
}
}
CCL_NAMESPACE_END