Files
blender/intern/cycles/blender/blender_mesh.cpp
Ton Roosendaal da376e0237 Cycles render engine, initial commit. This is the engine itself, blender modifications and build instructions will follow later.
Cycles uses code from some great open source projects, many thanks them:

* BVH building and traversal code from NVidia's "Understanding the Efficiency of Ray Traversal on GPUs":
http://code.google.com/p/understanding-the-efficiency-of-ray-traversal-on-gpus/
* Open Shading Language for a large part of the shading system:
http://code.google.com/p/openshadinglanguage/
* Blender for procedural textures and a few other nodes.
* Approximate Catmull Clark subdivision from NVidia Mesh tools:
http://code.google.com/p/nvidia-mesh-tools/
* Sobol direction vectors from:
http://web.maths.unsw.edu.au/~fkuo/sobol/
* Film response functions from:
http://www.cs.columbia.edu/CAVE/software/softlib/dorf.php
2011-04-27 11:58:34 +00:00

301 lines
8.1 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 bool mesh_need_attribute(Scene *scene, Mesh *mesh, Attribute::Standard std)
{
if(std == Attribute::STD_NONE)
return false;
foreach(uint shader, mesh->used_shaders)
if(scene->shaders[shader]->attributes.find(std))
return true;
return false;
}
static bool mesh_need_attribute(Scene *scene, Mesh *mesh, ustring name)
{
if(name == ustring())
return false;
foreach(uint shader, mesh->used_shaders)
if(scene->shaders[shader]->attributes.find(name))
return true;
return false;
}
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(v = b_mesh.vertices.begin(); v != b_mesh.vertices.end(); ++v)
mesh->verts.push_back(get_float3(v->co()));
/* create faces */
BL::Mesh::faces_iterator f;
vector<int> nverts;
for(f = b_mesh.faces.begin(); f != b_mesh.faces.end(); ++f) {
int4 vi = get_int4(f->vertices_raw());
int n= (vi[3] == 0)? 3: 4;
int shader = used_shaders[f->material_index()];
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, mesh, Attribute::STD_GENERATED)) {
Attribute *attr = mesh->attributes.add(Attribute::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(v = b_mesh.vertices.begin(); v != b_mesh.vertices.end(); ++v)
fdata[i++] = get_float3(v->co())*size - loc;
}
/* create vertex color attributes */
{
BL::Mesh::vertex_colors_iterator l;
for(l = b_mesh.vertex_colors.begin(); l != b_mesh.vertex_colors.end(); ++l) {
if(!mesh_need_attribute(scene, mesh, ustring(l->name())))
continue;
Attribute *attr = mesh->attributes.add(
ustring(l->name()), TypeDesc::TypeColor, Attribute::CORNER);
BL::MeshColorLayer::data_iterator c;
float3 *fdata = attr->data_float3();
size_t i = 0;
for(c = l->data.begin(); c != l->data.end(); ++c, ++i) {
fdata[0] = get_float3(c->color1());
fdata[1] = get_float3(c->color2());
fdata[2] = get_float3(c->color3());
fdata += 3;
if(nverts[i] == 4) {
fdata[0] = get_float3(c->color1());
fdata[1] = get_float3(c->color3());
fdata[2] = get_float3(c->color4());
fdata += 3;
}
}
}
}
/* create uv layer attributes */
{
BL::Mesh::uv_textures_iterator l;
for(l = b_mesh.uv_textures.begin(); l != b_mesh.uv_textures.end(); ++l) {
Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
ustring name = ustring(l->name());
if(!(mesh_need_attribute(scene, mesh, name) || mesh_need_attribute(scene, mesh, 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(t = l->data.begin(); 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(v = b_mesh.vertices.begin(); v != b_mesh.vertices.end(); ++v)
sdmesh.add_vert(get_float3(v->co()));
/* create faces */
BL::Mesh::faces_iterator f;
for(f = b_mesh.faces.begin(); f != b_mesh.faces.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.tesselate(&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 = (object_is_modified(b_ob))? b_ob: b_ob_data;
/* find shader indices */
vector<uint> used_shaders;
BL::Object::material_slots_iterator slot;
for(slot = b_ob.material_slots.begin(); slot != b_ob.material_slots.end(); ++slot)
find_shader(slot->material(), used_shaders);
if(used_shaders.size() == 0)
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;
}
}
/* create derived mesh */
BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
/* todo: this will crash on non-mesh types! */
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());
if(cmesh.data && 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)
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(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
rebuild = true;
mesh->tag_update(scene, rebuild);
return mesh;
}
CCL_NAMESPACE_END