Cycles microdisplacement: ngons and attributes for subdivision meshes
This adds support for ngons and attributes on subdivision meshes. Ngons are needed for proper attribute interpolation as well as correct Catmull-Clark subdivision. Several changes are made to achieve this: - new primitive `SubdFace` added to `Mesh` - 3 more textures are used to store info on patches from subd meshes - Blender export uses loop interface instead of tessface for subd meshes - `Attribute` class is updated with a simplified way to pass primitive counts around and to support ngons. - extra points for ngons are generated for O(1) attribute interpolation - curves are temporally disabled on subd meshes to avoid various bugs with implementation - old unneeded code is removed from `subd/` - various fixes and improvements Reviewed By: brecht Differential Revision: https://developer.blender.org/D2108
This commit is contained in:
parent
f74645578c
commit
c96ae81160
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
cdata[0] = colors[tri_a[0]];
|
||||
cdata[1] = colors[tri_a[1]];
|
||||
cdata[2] = colors[tri_a[2]];
|
||||
Attribute *attr = mesh->attributes.add(ustring(l->name().c_str()),
|
||||
TypeDesc::TypeColor,
|
||||
ATTR_ELEMENT_CORNER_BYTE);
|
||||
|
||||
if(nverts[i] == 4) {
|
||||
cdata[3] = colors[tri_b[0]];
|
||||
cdata[4] = colors[tri_b[1]];
|
||||
cdata[5] = colors[tri_b[2]];
|
||||
cdata += 6;
|
||||
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]];
|
||||
|
||||
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;
|
||||
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();
|
||||
/* 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]);
|
||||
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]);
|
||||
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;
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
else
|
||||
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth, false);
|
||||
|
||||
nverts[fi] = n;
|
||||
nverts[fi] = n;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
262
intern/cycles/kernel/geom/geom_subd_triangle.h
Normal file
262
intern/cycles/kernel/geom/geom_subd_triangle.h
Normal file
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -30,6 +30,7 @@ set(SRC
|
||||
light.cpp
|
||||
mesh.cpp
|
||||
mesh_displace.cpp
|
||||
mesh_subdivision.cpp
|
||||
nodes.cpp
|
||||
object.cpp
|
||||
osl.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 */
|
||||
|
@ -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);
|
||||
|
@ -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++;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
/* terminator */
|
||||
attr_map[index].x = ATTR_STD_NONE;
|
||||
attr_map[index].y = 0;
|
||||
attr_map[index].z = 0;
|
||||
attr_map[index].w = 0;
|
||||
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++;
|
||||
|
||||
attr_map[index].x = ATTR_STD_NONE;
|
||||
attr_map[index].y = 0;
|
||||
attr_map[index].z = 0;
|
||||
attr_map[index].w = 0;
|
||||
|
||||
index++;
|
||||
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
|
||||
|
||||
|
@ -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,
|
||||
|
224
intern/cycles/render/mesh_subdivision.cpp
Normal file
224
intern/cycles/render/mesh_subdivision.cpp
Normal file
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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 */
|
||||
|
@ -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__ */
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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__
|
||||
|
Loading…
Reference in New Issue
Block a user